November 2nd, 2021

The focus rectangle says, “I’m not orange. I’m just drawn that way.”

A customer saw that the Draw­Focus­Rect function was drawing an orange focus rectangle when applied to highlighted text. Whose bright idea was it for the focus rectangle to be orange?

The focus rectangle says, “I’m not orange. I’m just drawn that way.”

The focus rectangle is drawn by performing an XOR operation with a checkerboard brush. The idea behind using an XOR brush was that you could erase the focus rectangle by drawing it again. And the checkerboard brush means that both horizontal and vertical lines are dotted, and the corners match.

Rewind back to 1983. Most computer screens were monochrome. Bitmaps were one bit per pixel. And screens were 96 DPI.

In this world, XOR is a perfectly reasonable thing to do, since it looks good against both white¹ and black backgrounds.

A simple pattern of alternating white and black pixels gets you the dotted-line effect.

Of course, weird things happened if the focus rectangle was drawn against a non-solid background, but given the limitations of the hardware, you didn’t really have too much choice.

Fast-forward to the days of high-density 32-bit-per-pixel displays. That simple algorithm doesn’t produce results that are quite so pretty any more. For one thing, a single pixel dotted line is barely visible on high-density displays. And for another thing, XOR’ing colored pixels can produce strange effects.

In our case, what happened is that we took the blue color #0078D7 and flipped all the bits, producing #FF8728, which is bright orange.

That’s where the orange comes from. The focus rectangle doesn’t draw orange. It just flips the pixels that are already there, and blue flips to orange.

The Draw­Focus­Rect function can’t do anything about the XOR brush, because that would break compatibility with code that used a second Draw­Focus­Rect to erase the focus rectangle. But at least it can do a little bit to help with the dotted rectangle: The thickness of the dotted rectangle is controlled by an accessibility setting. In Control Panel, under Ease of Access, Make the computer easier to see, you can check “Make the focus rectangle thicker”, which makes the focus rectangle two pixels thick instead of just being a dotted line.

Programs which draw their own focus indicators can match the accessibility setting by using the SPI_GET­FOCUS­BORDER­WIDTH and SPI_GET­FOCUS­BORDER­HEIGHT system metrics.

Bonus chatter: The blinking line that indicates where typing will be inserted is called the caret, and it too is drawn by XOR. This works fine when the caret is against a white or black background, but again, if it’s against a colored background, things can get a little weird.

¹ Or, more likely, P1 phosphor green and black, or P3 phosphor amber and black.

Topics
Code

Author

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.

8 comments

Discussion is closed. Login to edit/delete existing comments.

  • ChDF T

    The idea behind using an XOR brush was that you could erase the focus rectangle by drawing it again.
    This explains a lot. Back in the days when everyone used GDI+ and liked it, these highlight rectangles would sporadically only get partially removed¹. It never occurred to me, that the application might be relying on the XOR-nature instead of redrawing the entire window (or part of it).
    This brings me to the hypothesis, that when...

    Read more
      • Antonio Rodríguez

        You should never use mid values (i.e. 50% gray) as background when information is going to be placed on it. Human vision is far more sensitive to luminance than to chrominance, so the best way to make something readable is either dark text (or pictures) on clear background, or clear text (or pictures) on dark background. This is also why, for example, yellow on white, or navy blue on black, are really hard to read....

        Read more
      • Joshua Hudson

        I agree with you, but Microsoft does not. https://aka.ms/AAeqt41

      • ChDF T · Edited

        That is a very good point. The 50ish% gray as an edge-case isn't even all that rare either.
        And since the XORing nature - and not just the 2nd-call-reverts-changes-nature - is actually documented, can't even be changed to use some other mapping where (which would at least enable the graphics designers to choose pairs of colors which look less odd than blue-orange and are more visible than gray-gray).

        Read more
      • Neil Rashbrook

        Ah, but it can – simply XOR with 50% grey, 0x7F7F7F if you want colour inversion, 0x808080 if you don’t. In at least Windows 95-2000 you also used to be able to do this with the mouse cursor, but of course this was undocumented behaviour and sadly stopped working in Windows XP.

      • Neil Rashbrook

        Actually, 0x7F7F7F doesn’t work on light grey 0xC0C0C0 because it just turns it into 0xBFBFBF so forget that. As for 0x808080, it does at least guarantee exactly 50% contrast on all grey backgrounds, but I can’t remember how it looks like on coloured backgrounds, although I do remember it being dim and so I understand it wouldn’t suit everyone.

      • Antonio Rodríguez

        XORing a 50% grey with white, black or any saturated color gives a 50% grey, which may not have enough contrast. And with a non-saturated color (dark, pastel, grayed, etc.) is even worse: it gives the an opposite color, yes, but with a value (luminance) dangerously near to the original (a purple dotted line on a medium green background, for example). It is a bad idea, specially when you take accessibility into account. See my...

        Read more