CW_USEDEFAULT: An underappreciated UX feature

Say you're writing code for a desktop PC application. It's very common for people to have multiple displays/screens for their desktop setups nowadays. When the user launches your program, how do you know which screen it should appear on to provide the least-jarring user experience? Many applications seem to get this wrong, opting for whatever display happens to be set as primary, or for whatever display the program was last closed on, or whatever screen there happens to be a mouse pointer on, either at some arbitrary time after the app started executing its code or each time it gets around to creating a window. While those approaches would make for good choices that the user can pick between in your app's settings, they're all poor defaults and even worse for the first-launch experience.

It's actually a trick question. The correct answer is to let the window manager decide. That can vary based on operating system and desktop environment, but the general principle is the same: your application does not have the full picture about how it was launched, so it can't possibly know where it should appear to match user expectations. Additionally, if each app tries to be the one to try and figure this out itself, they are likely to come to different answers, leading to an inconsistent user experience from one app to another. Letting the window manager decide provides a uniform and predictable experience for users. Even if the window manager's behavior is not what the user would prefer, the predictability is the main benefit, and your app's settings screen can come in to the rescue for any users unsatisfied with the default behavior.

Let's take a look at how this principle can be applied to Microsoft's Windows operating system. If you're building apps with the Universal Windows Platform, you don't need to do anything special - the UWP API is already designed to not give you control over window positions by default, so the window manager already handles window positioning in all scenarios by default. If you're building apps using the Win32 API, or anything that eventually leads to calling CreateWindowA or CreateWindowW or CreateWindowExA or CreateWindowExW, then things get a bit interesting. Those are the only functions you should be considering when creating your app's first window, but in taking a quick glance at the documentation, you might think you have to pass coordinates for the window position.

Enter CW_USEDEFAULT. This special sentinel value can be passed to the x coordinate parameter to let the window manager know you want it to select a window position for you. Maybe you've tried this before but noticed the window ended up uncentered and was only ever created on your primary display. It goes a bit deeper than that though - if you actually build your program out to an executable and run it as a normal user would, then you can notice that the window is always created on the display where your mouse pointer was at the time of launching the program, even if you moved your mouse to a different display by the time the CreateWindow call was made. Huzzah! It was the act of your IDE launching it that was suppressing the intended behavior.

That's already most of the way there to getting better behavior than what you could have made yourself: the window manager knows where the mouse pointer was before your program even had a chance to note that for itself. As for being uncentered, that's generally not so bad, since it selects a different position each time to make the appearance of multiple windows more obvious than if they all occupied the same space. If you really want your window to be centered though, take a look at the documentation for the y coordinate parameter: If the x coordinate parameter is CW_USEDEFAULT, then the y coordinate parameter can be one of the values you'd normally use with ShowWindow, such as SW_HIDE, meaning you can create the window hidden, on the screen selected by the window manager, and then you can center it yourself since you now know what screen it should be on, and finally reveal the window after doing any other setup, such as rendering the first visible frame of what should be seen in the window.

I've used many different Windows apps and games over many years and very few take advantage of this obscure behavior of CW_USEDEFAULT with the CreateWindow functions. They all seem hyper-focused on trying to solve the problem themselves in their own unique and separate ways. I've even seen some apps that get it wrong multiple times in a row, e.g. I launch the app from screen 1, move my mouse to screen 2 where the splash screen finally appears, and then move my mouse to screen 3 where the program's main window finally appears. Maybe some people find that behavior desirable, but I prefer when an app appears on the screen I launched it from, which is what CW_USEDEFAULT does.

Maybe some popular open source library can come to the rescue? Well, SDL is a particularly popular multi-platform abstraction library, and the only place it uses CW_USEDEFAULT is for the creation of an invisible helper window, which it doesn't bother to use to glean this secret information from. All of SDL's flags related to window positioning either make you specify a display explicitly, or they make the window be created on the "primary" display. There is no obvious way to take advantage of the CW_USEDEFAULT behavior with SDL. And yes, I checked the latest and greatest of SDL3, version 3.2.4, though they did at least make the API more future-proof and could theoretically add support for this in the future.

GLFW is another popular multi-platform abstraction library, and it actually does let you use CW_USEDEFAULT if you specify GLFW_ANY_POSITION for both the x and y coordinates. However, it then specifies CW_USEDEFAULT for the y coordinate parameter too, which is equivalent to SW_SHOW. So much for creating the window hidden first so you can set it up as you like before showing it. I'll give them the benefit of the doubt and assume there's some secret sauce for that elsewhere that I didn't notice.

They say first impressions are important, and having your app appear on an unexpected screen the first time the user launches it can certainly be jarring. It's especially annoying with games that default to launching in fullscreen without warning, typically on a display you don't want them to be on. Many apps save window positions and remember them after the first launch, and you can of course have settings for the user to control how they want the window position to be selected, but this leads to a land of complications. If you're manually managing window positions, you have to also manually be careful about the user's display setup changing unexpectedly - not just number of displays and arrangements, but also display scale factors. It's very common to hear about software saving window positions that end up being completely off-screen after the user changed their display setup. It's also common to have the more subtle mistake of just saving the top left corner and size, forgetting that the size may have to scale depending on the display scaling factor of whatever screen the window is on while the position either uses a coordinate system that is never affected by display scaling, or something more exotic depending on the platform.

How about you save yourself the trouble and just use CW_USEDEFAULT on every launch?

Comments