How do I switch a window between normal and fullscreen?


Frederic Delhoume wants to know if there is a simple example of code that switches an application from windowed to fullscreen. He then included a code fragment that did some crazy things with parent windows and hiding and showing.

You're making it way, way harder than it needs to be. Let's start with our scratch program and make these changes:

WINDOWPLACEMENT g_wpPrev = { sizeof(g_wpPrev) };

void OnLButtonUp(HWND hwnd, int x, int y, UINT keyFlags)
{
  DWORD dwStyle = GetWindowLong(hwnd, GWL_STYLE);
  if (dwStyle & WS_OVERLAPPEDWINDOW) {
    MONITORINFO mi = { sizeof(mi) };
    if (GetWindowPlacement(hwnd, &g_wpPrev) &&
        GetMonitorInfo(MonitorFromWindow(hwnd,
                       MONITOR_DEFAULTTOPRIMARY), &mi)) {
      SetWindowLong(hwnd, GWL_STYLE,
                    dwStyle & ~WS_OVERLAPPEDWINDOW);
      SetWindowPos(hwnd, HWND_TOP,
                   mi.rcMonitor.left, mi.rcMonitor.top,
                   mi.rcMonitor.right - mi.rcMonitor.left,
                   mi.rcMonitor.bottom - mi.rcMonitor.top,
                   SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
    }
  } else {
    SetWindowLong(hwnd, GWL_STYLE,
                  dwStyle | WS_OVERLAPPEDWINDOW);
    SetWindowPlacement(hwnd, &g_wpPrev);
    SetWindowPos(hwnd, NULL, 0, 0, 0, 0,
                 SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
                 SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
  }
}

// add to WndProc
    HANDLE_MSG(hwnd, WM_LBUTTONUP, OnLButtonUp);

To avoid getting into the intricacies of hotkeys and accelerators, I opted to toggle to fullscreen on a click. When the button goes up, we check whether we are currently in normal mode or fullscreen mode by sniffing at our window styles. If we are in normal mode, we save the current window placement and get the dimensions of the current monitor. And then the magic happens: We remove the caption and other decorations from our window style and reposition the window so it covers the entire monitor. An important flag to pass here is SWP_FRAME­CHANGED, which tells the window manager to recalculate the window decorations (which we need it to do because we just changed them).

When returning from fullscreen, we just undo what we had done when we went fullscreen: We restore the caption and other decorations to our window and restore the original window state.

And that's all there is to it. You don't have to do anything special to get the taskbar to "get out of the way"; the taskbar recognizes when applications have gone fullscreen and automatically gets out of the way.

Comments (34)
  1. ruf says:

    How about the menu?

    Normally, it is hidden in full screen.

  2. @ruf: When the WS_CAPTION style (included within WS_OVERLAPPEDWINDOW) is removed, the window no longer has a title bar and thus no menu.

  3. W says:

    Doesn’t this code fail when the monitor resolution changes while the window is in fullscreen mode?

    Shouldn’t you set it to maximized instead?

    In Delphi I set it to maximized, always-on-top and borderless. But I don’t know which windows api calls this maps to.

    And aren’t there performance differences depending on how you switch to fullscreen? I believe DirectX might behave differently if it recognizes that you are in fullscreen mode, and aero desktop composition might be disabled in "true" fullscreen mode. But I’m not sure about either of these.

  4. Alexandre Grigoriev says:

    @W:

    You need to monitor WM_DISPLAYCHANGE. For OVERLAPPEDWINDOW, DefWndProc does that for you.

  5. ruf says:

    @Adam Rosenfield

    I have just tried and the menu is not removed. Tested on the default windows application generated from VS2008.

  6. MP says:

    This is the cause of a long-standing bug in Google Chrome. When Google Chrome is maximized, and the taskbar is set to auto-hide, it "recognizes" that you’re trying to do something in fullscreen, and the hidden taskbar will not be shown even if you position the mouse at the bottom of the screen.

    http://code.google.com/p/chromium/issues/detail?id=20

    Is there a way to make a captionless window occupy the entire screen (or the entire screen minus the taskbar) but tell the window manager that "hey, I’m not a fullscreen window"?

  7. Alexandre Grigoriev says:

    @MP

    Use SystemParametersInfo/SPI_GETWORKAREA. This is the moditor minus taskbar.

  8. J says:

    @AG: If the taskbar is set to auto-hide, this doesn’t work correctly. Not sure who SysParInfo determines the work area in that case, but either you’ll get the taskbar-thinks-you’re-fullscreen thing, or you’ll have an empty space at the bottom where the taskbar normally is.

    I suppose one could set the size to one pixel shorter than the height of the work area if you detect that the taskbar is auto-hidden.

  9. Johannes says:

    J: That would assume the taskbar is at the bottom. You should carve the pixel off at the correct side of the window, if you do that.

  10. bla says:

    Even if you set the taskbar to autohide it reserves some pixels of screen area. You have to look closly. It must be a bug in Chrome.

  11. jon says:

    "Is there a way to make a captionless window occupy the entire screen (or the entire screen minus the taskbar) but tell the window manager that "hey, I’m not a fullscreen window"?"

    WS_MAXIMIZE?

  12. Mike says:

    Wasn’t this already covered in http://blogs.msdn.com/oldnewthing/archive/2005/05/05/414910.aspx ?

    [Related but different. This is about convering a window to fullscreen, as opposed to making a fullscreen window. -Raymond]
  13. Leo Davidson says:

    Mike, That was how to open a full-screen window. This is how to switch your window between normal and full-screen.

  14. Koro says:

    "This is the cause of a long-standing bug in Google Chrome."

    If Chrome used regular window captions like EVERY OTHER APPLICATION out there, this would not be an issue.

    It’s their fault for trying to do the window manager’s job (badly).

  15. There’s another way to switch an existing window to fullscreen – you just need to make the window’s client area overlap the monitor’s rect. In this case, window styles can be left intact.

    This is how IE and a couple of picture viewers switch to fullscreen.

  16. Roland says:

    How about ITaskbarList2::MarkFullscreenWindow?

    Is it required to call this in certain scenarios, or is the Shell smart enough to always detect full-screen windows automatically?

  17. Addition to my previous post.

    In fact, to make client rect as large as monitor’s area, WS_CAPTION style should be removed anyway.

    So, the statement "In this case, window styles can be left intact" is sure wrong. Sorry for this mistake.

  18. Yes, we hit that automated taskbar behavior with Songbird pretty hard as well – the issue is pretty identical to what Chrome experienced. When a window without non-client area is maximized the taskbar thinks that it is a fullscreen window and it is rather hard to convince it otherwise. What’s worse, some other Windows functions behave in a very strange way as well (like Windows+Left on Windows 7 to move the window to a different monitor which is pretty broken then if the other monitor has a different size). Me and a colleague spent several days trying out different things and ended up with something similar to Chrome’s solution, and just as ugly. At times I seriously wish the OS wouldn’t try to be clever. Unfortunately, as you make obvious, the OS has to be clever because the applications are very stupid far too often.

  19. ruf says:

    I think client rect can be make as large as monitor’s area. You only need to handle WM_GETMINMAXINFO properly. This way you can hide the menu also.

  20. Ian says:

    To Alexander Belyakov:

    If I understand you correctly, you are suggesting making the window bigger than the monitor so that only the client area is shown and the decorations are off-screen.

    This seems like a terrible idea to me. The decorations won’t be off-screen if the user has more than one monitor. Furthermore, if those monitors are set to different colour depths then there could be a big performance hit on drawing.

  21. px@i.kiev.ua says:

    And what about fullscreen and windowed 3d applications? Especially on non-primary display

  22. dash says:

    Why did you embed a dash in the programming syntax constant?

    –>  An important flag to pass here is <CODE>SWP_<WBR>FRAME&shy;CHANGED</CODE>,

    which tells the window manager to recalculate the window decorations

    (which we need it to do because we just changed them).

    [Um, so it would line-break better? -Raymond]
  23. 640k says:

    It’s also useful to remove the client border in fullscreen, VS add this by default in the dialog editor when creating a overlapped window.

    Else, the client area dimensions usually becomes 4 pixels smaller than the desktop area.

  24. Random832 says:

    "If Chrome used regular window captions like EVERY OTHER APPLICATION out there, this would not be an issue."

    More to the point, they don’t even have the excuse of needing to show a custom appearance (MS Office does it fine) or to show with no title in the titlebar (Explorer does it fine) – both of the named apps have WS_CAPTION on their windows.

    WM_NCPAINT/NCCALCSIZE/NCHITTEST exist for a reason.

  25. Justin says:

    Raymond,

    I just want to say thank you for posting very useful stuff like this.  People might have a tendancy to nitpick and complain, but useful tidbits like this are why I read your blog and appreciate your work.

    Thanks,

    Justin

  26. James Schend says:

    Koro: Sadly, Adobe is quickly making "re-implement the window manager, badly" the standard practice in software development with their creative suite products.

  27. Anonymous Coward says:

    If you are writing a game, please take care that you switch resolution while your window is already fullscreen. If you don’t, the desktop will pop back which looks really unprofessional. You wouldn’t believe how many games get this wrong. And then we’re not even talking about games that don’t really use a fullscreen window, but paint to the screen device context and lock the mouse and keyboard for their input. Yeah, it works – until something happens that the programmers didn’t anticipate…

  28. To Ian:

    "… The decorations won’t be off-screen if the user has more than one monitor. Furthermore, if those monitors are set to different colour depths then there could be a big performance hit on drawing."

    Please don’t forget about window regions. Setting them properly is a rather good way to avoid those drawbacks.

  29. dash says:

    @Raymond: [Um, so it would line-break better? -Raymond]

    IE copies (pastes) the text with a verbatim dash, not a line break.

    [I didn’t do it to the code, just the running text. -Raymond]
  30. Ef ess dee gee says:

    @Koro:

    It’s their fault for trying to do the window manager’s job (badly).

    Actually they do a better job feature-wise (not much of an accomplishment considering the window manager was barely serviceable in 1995 and has stayed the same until recently). In particular, it gets you "aero-snap" on all OSes, at least for individual tabs.

    Meanwhile always-on-top, transparency, position remembering, intelligent positioning (least overlap), multiple desktops and so on remain alien to Windows and have to be implemented by applications in ways which barely work, and you hit problems like this. Oh well. Fortunately since all other OSes have them I guess it’s just a matter of a few years until MS copies them.

  31. Gabe says:

    fsdg: You have a problem with the way Windows handles always-on-top windows?

  32. Demid says:

    To Wladimir Palant

    "When a window without non-client area is maximized the taskbar thinks that it is a fullscreen window and it is rather hard to convince it otherwise."

    In multi-monitor environment it’s even worse: the window manager automatically translates secondary monitor coordinates into primary monitor (see remarks section here: http://msdn.microsoft.com/en-us/library/ms632605(v=VS.85).aspx ) and for example the solution here ( http://blogs.msdn.com/llobo/archive/2006/08/01/Maximizing-window-2800_with-WindowStyle_3D00_None_2900-considering-Taskbar.aspx ) doesn’t work and on the secondary monitor a window is maximized beyond the screen limits.

    Sometimes the window manager is too clever and unfortunately there is no way to switch off that cleverness.

  33. Unfortunately, Raymond Chen’s code doesn’t work in all cases. It is fine on XP but it can cause problems Vista and higher when using OpenGL/D3D with Aero enabled: the Aero borders disappear and are replaced by black rectangles.

    This doesn’t happen on all video cards but it is widespread enough for it to be a problem (it affects more than own GPU vendor).

    The only reliable solution is to use two windows instead of one: a vanilla parent window and a child window that host the OpenGL/D3D context. This allows Raymond’s code to work correctly on the parent window.

    It would be great if someone could share some insight on why this happens.

Comments are closed.