September, 2003

  • The Old New Thing

    Scrollbars part 10 - Towards a deeper understanding of the WM_NCCALCSIZE message

    • 2 Comments

    When your window is resized, Windows uses the WM_NCCALCSIZE message to determine where your window's client area lives inside your window rectangle.

    There are two forms of the WM_NCCALCSIZE message. The simple form merely takes a window rectangle and returns a client rectangle. This is useful for resizing a window to have a desired client rectangle, taking menu wrapping into account. The AdjustWindowRectEx function cannot take menu wrapping into account because it doesn't know which menu you are using. (Notice that there is no HMENU or HWND parameter to AdjustWindowRectEx.)

    void
    SetWindowClientSize(HWND hwnd, int cx, int cy)
    {
        HMENU hmenu = GetMenu(hwnd);
        RECT rcWindow = { 0, 0, cx, cy };
    
        /*
         *  First convert the client rectangle to a window rectangle the
         *  menu-wrap-agnostic way.
         */
        AdjustWindowRectEx(&rcWindow, GetWindowStyle(hwnd), hmenu != NULL,
                           GetWindowExStyle(hwnd));
    
        /*
         *  If there is a menu, then check how much wrapping occurs
         *  when we set a window to the width specified by AdjustWindowRect
         *  and an infinite amount of height.  An infinite height allows
         *  us to see every single menu wrap.
         */
        if (hmenu) {
            RECT rcTemp = rcWindow;
            rcTemp.bottom = 0x7FFF;     /* "Infinite" height */
            SendMessage(hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&rcTemp);
    
            /*
             *  Adjust our previous calculation to compensate for menu
             *  wrapping.
             */
            rcWindow.bottom += rcTemp.top;
        }
    
        SetWindowPos(hwnd, NULL, 0, 0, rcWindow.right - rcWindow.left,
                     rcWindow.bottom - rcWindow.top, SWP_NOMOVE | SWP_NOZORDER);
    
    }
    

    Exercise: Explain why we used 0x7FFF to represent infinite height.

    Exercise: Explain the line rcWindow.bottom += rcTemp.top.

  • The Old New Thing

    You too can dress like Raymond

    • 8 Comments

    Yes, I'm the Raymond that Kraig Brockschmidt is writing about when he discusses "Dress Like Raymond Day".

  • The Old New Thing

    Computers are still too hard to use.

    • 11 Comments

    UK survey reveals that one in seven computer users needs help turning the computer on and off.

  • The Old New Thing

    Why do some people call the taskbar the "tray"?

    • 73 Comments

    Short answer: Because they're wrong.

    Long answer:

    The official name for the thingie at the bottom of the screen is the "taskbar". The taskbar contains a variety of elements, such as the "Start Button", a collection of "taskbar buttons", the clock, and the "Taskbar Notification Area".

    One of the most common errors is to refer to the Taskbar Notification Area as the "tray" or the "system tray". This has never been correct. If you find any documentation that refers to it as the "tray" then you found a bug.

    In early builds of Windows 95, the taskbar originally wasn't a taskbar; it was a folder window docked at the bottom of the screen that you could drag/drop things into/out of, sort of like the organizer tray in the top drawer of you desk. That's where the name "tray" came from. (Some might argue that this was taking the desktop metaphor a bit too far.)

    Artist's conception (i.e., Raymond sat down with Paint and tried to reconstruct it from memory) of what the tray looked like at this time:

    The tray could be docked to any edge of the screen or it could be undocked and treated like any other window.

    Then we ditched the tray and replaced it with the taskbar. We went through a doc scrub to change all occurrences of "tray" to "taskbar". If you go through the shell documentation, you should not find the word "tray" anywhere.

    A little while later, we added notification icons to the taskbar.

    I think the reason people started calling it the "system tray" is that on Win95 there was a program called "systray.exe" that displayed some icons in the notification area: volume control, PCMCIA (as it was then called) status, battery meter. If you killed systray.exe, you lost those notification icons. So people thought, "Ah, systray must be the component that manages those icons, and I bet its name is 'system tray'." Thus began the misconception that we have been trying to eradicate for over eight years...

    Even worse, other groups (not the shell) picked up on this misnomer and started referring it to the tray in their own documentation and samples, some of which even erroneously claim that "system tray" is the official name of the notification area.

    "But why do you care? That's what everybody calls it now, may as well go with the flow."

    How would you like it if everybody started calling you by the wrong name?

    Summary: It is never correct to refer to the notification area as the tray. It has always been called the "notification area".

  • The Old New Thing

    If you see only one Elvis vs. Mummy movie this year, make it this one

    • 3 Comments

    Bubba Ho-Tep will be playing at the Varsity Theater in Seattle for a limited run. (Check the release schedule to see if it will be airing in your area.)

    Be there. Or the mummy will have already won.

  • The Old New Thing

    Scrollbars part 9 - Maintaining the metaphor

    • 2 Comments

    When a document is displayed with scrollbars, the metaphor is that the window is a viewport onto the entire document, only a portion of which is visible at the moment. The default behavior of a resize, however, is to maintain the origin at the upper left corner of the client area, which breaks the metaphor when the window is resized at the top or left edge.

    Suppose, for example, that the top line in the document is line ten. If the user grabs the top edge of the window and resizes upwards by one line (in an attempt to view line nine), the default behavior is to maintain the origin, which keeps line ten at the top of the window. The visual effect is that the window has scrolled upwards one line, subverting the user's attempt to view line nine.

    This is one of the subtleties of scrollbars which users rarely consciously notice, but when it doesn't work, it gives the impression that computers never quite get things right.

    Let's fix our scrolling behavior to maintain the viewport metaphor. We'll do it in several steps. First, we'll over-preserve the metaphor. Add the following new section to OnWindowPosChanging:

    BOOL OnWindowPosChanging(HWND hwnd, LPWINDOWPOS pwp)
    {
        if (!(pwp->flags & SWP_NOMOVE)) {
            RECT rc;
            GetWindowRect(hwnd, &rc);
            int dy = pwp->y - rc.top;
            ScrollDelta(hwnd, dy / g_cyLine);
        }

        if (!(pwp->flags & SWP_NOSIZE)) {
            RECT rc = { 0, 0, pwp->cx, pwp->cy };
            AdjustSizeRectangle(hwnd, WMSZ_BOTTOM, &rc);
            pwp->cy = rc.bottom;
        }

        return 0;
    }

    Now run the program, move the scrollbar thumb to somewhere in the middle, and resize the top edge of the window upwards and downwards. Notice that the existing lines on the screen don't move; all that resizing the top of the window does is expose or hide lines at the top. You already experience this behavior when resizing the bottom edge; now you get it at the top, too.

    There are several things wrong with this code, however.

    First, observe that it is trying too hard. Grab the window and move it across the screen. Observe that it still tries to preserve the aperture metaphor. (Even worse: It depends on how fast you move your mouse. The effect is more noticeable if you disable "Show window contents while dragging".) This is probably undesirable.

    Second, notice all the horrible flicker.

    We'll address these two problems in turn.

    Fixing the overzealousness is the easier problem. First, we do the work only if the window is simultaneously moving and sizing. This prevents simple moving from triggering the metaphor behavior.

    BOOL OnWindowPosChanging(HWND hwnd, LPWINDOWPOS pwp)
    {
        if (!(pwp->flags & SWP_NOSIZE)) {

            RECT rc = { 0, 0, pwp->cx, pwp->cy };
            AdjustSizeRectangle(hwnd, WMSZ_BOTTOM, &rc);
            pwp->cy = rc.bottom;

            if (!(pwp->flags & SWP_NOMOVE)) {
                RECT rc;
                GetWindowRect(hwnd, &rc);
                int dy = pwp->y - rc.top;
                ScrollDelta(hwnd, dy / g_cyLine);
            }

        }
        return 0;
    }

    Now if you grab the window and move it around, we don't do the metaphor thing because the size didn't change.

    However, if you maximize a window, the metaphor code kicks in. But that's easy to fix: Only do the metaphor if the top edge changes and the bottom edge doesn't.

    BOOL OnWindowPosChanging(HWND hwnd, LPWINDOWPOS pwp)
    {
        if (!(pwp->flags & SWP_NOSIZE)) {
            RECT rc = { 0, 0, pwp->cx, pwp->cy };
            AdjustSizeRectangle(hwnd, WMSZ_BOTTOM, &rc);
            pwp->cy = rc.bottom;

            if (!(pwp->flags & SWP_NOMOVE)) {
                RECT rc;
                GetWindowRect(hwnd, &rc);
                if (rc.bottom == pwp->y + pwp->cy) {
                    int dy = pwp->y - rc.top;
                    ScrollDelta(hwnd, dy / g_cyLine);
                }

            }
        }
        return 0;
    }

    We still have a problem with the flicker, though. Before we can fix that, we will need a deeper understanding of the WM_NCCALCSIZE message.

    
    
  • The Old New Thing

    It's a lot easier to write a column if you don't care about accuracy

    • 9 Comments

    Now that Longhorn Rumor Season seems to have kicked up, I'm reminded of Windows 95 Rumor Season. The great thing about writing a rumors column is that you don't have to be right! Even if you're wrong, you can just say, "Well, Microsoft changed it before they shipped," and nobody can say you were wrong. It's a victimless crime! The only victim is Microsoft!

    Here's a classic example from early 1995:

    Notes from the Field
    Microsoft's latest security scheme could leave users of Windows 95 dongling

    BY ROBERT X. CRINGELY

    One thing that will be pretty darned hard to steal, come Aug. 24, is a renegade copy of Windows 95. Just before heading to the DMV, I heard that the kids in Redmond plan to cut Win95 piracy to zilch by requiring the use of a dongle. Yes, a dongle.

    Just in case you've led a charmed or boring life, a dongle is a thingamajig that plugs into one of your PC I/O ports. One dongle is shipped for each copy of the OS and the software won't work if it can't detect the proper dongle.

    The upshot of this plan is that you can load as many copies of Win95 as you like, but only the machine with the dongle will work.

    Now the requisite qualifiers, pre-paid backpedaling, and so on: I believe this information to be true, but I have it from only one source, so it should be classified as a rumor. Microsoft could change its mind on the dongle security strategy tomorrow.

    Emphasis mine. And the great thing is, if the story turns out untrue, you can even take credit for it! "Thanks to public uproar over my amazing scoop, Microsoft changed their mind and decided not to do this thing" (that they weren't planning on doing anyway).

    It's very frustrating reading rampant bogus rumors about your product and not being able to do anything about it.

    So remember, all you Lonhorn rumor-consumers: Just because you saw it in the newspaper doesn't mean that it's true.

  • The Old New Thing

    An insight into the Windows 95 startup sound

    • 14 Comments

    Doo, dudududingggggg.... ding.... ding... ding...

    In an interview with Joel Selvin at the San Francisco Chronicle, Brian Eno explains.

    Q: How did you come to compose "The Microsoft Sound"?

    A: The idea came up at the time when I was completely bereft of ideas. I'd been working on my own music for a while and was quite lost, actually. And I really appreciated someone coming along and saying, "Here's a specific problem -- solve it."

    The thing from the agency said, "We want a piece of music that is inspiring, universal, blah-blah, da-da-da, optimistic, futuristic, sentimental, emotional," this whole list of adjectives, and then at the bottom it said "and it must be 3 1/4 seconds long."

    I thought this was so funny and an amazing thought to actually try to make a little piece of music. It's like making a tiny little jewel.

    In fact, I made 84 pieces. I got completely into this world of tiny, tiny little pieces of music. I was so sensitive to microseconds at the end of this that it really broke a logjam in my own work. Then when I'd finished that and I went back to working with pieces that were like three minutes long, it seemed like oceans of time.

    The Windows 95 CD contained extra multimedia toss-ins. The ones I remember are a cartoon or two by Bill Plympton, a Weezer music video, and music video of Edie Brickell singing Good Times.

    For some reason, everybody wanted to know the artist from the Good Times video. Nobody was interested in the artists who did any of the other stuff. (Okay, probably nobody asked about Weezer because, well, that's the group right there in the filename.)

    Hint: Right-click and select Properties. That will tell you the artist.

    Oh, and the question nobody asked but I'm going to answer it anyway: The composer of the Windows 95 Easter Egg theme is Brian Orr. Here's his story of how it came to be.

  • The Old New Thing

    Where is my program running from?

    • 1 Comments

    Another common question: "How do I find out where my program is? I want to be able to access support files in that same directory."

    Answer: GetModuleFileName(NULL, ...).

  • The Old New Thing

    Case mapping on Unicode is hard

    • 2 Comments

    Occasionally, I'm asked, "I have to identify strings that are identical, case-insensitively.  How do I do it?"

    The answer is, "Well, it depends. Whose case-mapping rules do you want to use?"

    Sometimes the reply is, "I want this to be language-independent."

    Now you have a real problem.

    Every locale has its own case-mapping rules. Many of them are in conflict with the rules for other locales. For example, which of the the following pairs of words compare case-insensitive equal?

    1. gif GIF
    2. Maße MASSE
    3. Maße Masse
    4. même MEME

    Answers:

    1. no in Turkey, yes in US
    2. no in US, yes in Germany
    3. no in US, no in Germany, yes in Switzerland! (Though you would likely never see it written as "Maße" in Switzerland.)
    4. yes in France, no in Quebec!

    (And I've heard that the capitalization rules for German are context-sensitive. Maybe that changed with the most recent spelling reform.) Unicode Technical Report #21 has more examples.

    Just because you're using Unicode doesn't mean that all your language problems are solved. Indeed, the ability to represent characters in nearly all of the world's languages means that you have more things to worry about, not less.

Page 3 of 4 (38 items) 1234