简体   繁体   中英

Going Fullscreen in win32 without 2 WM_SIZE message

So I am creating a fullscreen function in win32 c++ doing:

uint8_t isFullscreen = 0;

RECT winRect;           //Current Window Rect
RECT nonFullScreenRect; //Rect Not In Full Screen Position (used to restore window to not full screen position when coming out of fullscreen) 

uint32_t screen_width = DEFAULT_SCREEN_WIDTH;
uint32_t screen_height = DEFAULT_SCREEN_HEIGHT;

void Fullscreen( HWND WindowHandle )
{
    isFullscreen = isFullscreen ^ 1;
    if( isFullscreen )
    {
        //saving off current window rect
        nonFullScreenRect.left = winRect.left;
        nonFullScreenRect.right = winRect.right;
        nonFullScreenRect.bottom = winRect.bottom;
        nonFullScreenRect.top = winRect.top;
        SetWindowLongPtr( WindowHandle, GWL_STYLE,  WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE );  //causes a resize msg 
        HMONITOR hmon = MonitorFromWindow(WindowHandle, MONITOR_DEFAULTTONEAREST);
        MONITORINFO mi = { sizeof( mi ) };
        GetMonitorInfo( hmon, &mi );
        screen_width = mi.rcMonitor.right - mi.rcMonitor.left;
        screen_height = mi.rcMonitor.bottom - mi.rcMonitor.top;
        MoveWindow( WindowHandle, mi.rcMonitor.left, mi.rcMonitor.top, (int32_t)screen_width, (int32_t)screen_height, FALSE );      
    }
    else
    {
        SetWindowLongPtr( WindowHandle, GWL_STYLE, WS_OVERLAPPEDWINDOW | WS_VISIBLE );
        screen_width = nonFullScreenRect.right - nonFullScreenRect.left;
        screen_height = nonFullScreenRect.bottom - nonFullScreenRect.top;
        MoveWindow( WindowHandle, nonFullScreenRect.left, nonFullScreenRect.top, (int32_t)screen_width, (int32_t)screen_height, FALSE );
    }
}

If you only want a single WM_SIZE to trigger, when you switch to full screen then you should go for something like this:

    SetWindowLongPtr(hWnd, GWL_EXSTYLE, WS_EX_TOPMOST);
    SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
    ShowWindow(hWnd, SW_SHOWMAXIMIZED);

Any SetWindowLongPtr call to GWL_STYLE will trigger a WM_SIZE, so make sure it's only called with GWL_EXSTYLE . For example, if you both set GWL_EXSTYLE to what you want, and reset GWL_STYLE to 0, you'll trigger WM_SIZE twice.

To make it clearer:

  • Don't use GWL_STYLE in SetWindowLongPtr because it triggers a useless WM_SIZE
  • ShowWindow will trigger WM_SIZE
  • The above code will ultimately only trigger WM_SIZE once.

EDIT: It turns out that YMMV. It's entirely possible that the first time you switch fullscreen, you'll get 2 WM_SIZE. One will be with the original size, and the other with the new size. Subsequent calls will trigger only one WM_SIZE.

Hence, the really bulletproof solution (which I was using anyway before playing around with the SetWindowLongPtr to answer this question, is to validate that the window size has actually changed. Because one thing that I can guarantee in the above call is that you'll never get more than 1 call with the new size. At most you'll get a WM_SIZE call with the old size, which you'll discard by checking that it's the same as the current size.

If you use the DevicesResources template for DX12, you'll see that there's a check in OnWindowSizeChanged() that does nothing if the size hasn't changed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM