From a18aa24fe3aa0b7965ee15dfd50b526e03024ee1 Mon Sep 17 00:00:00 2001 From: Ykkrosh Date: Thu, 3 Jun 2010 21:15:45 +0000 Subject: [PATCH] Windows support for window resizing and fullscreen toggling. Windows build fixes. This was SVN commit r7607. --- build/premake/premake.lua | 5 +- source/lib/sysdep/os/win/wsdl.cpp | 120 ++++++++++++++++----- source/lib/sysdep/os/win/wsdl.h | 11 ++ source/main.cpp | 17 ++- source/ps/VideoMode.cpp | 4 + source/tools/atlas/AtlasUI/Misc/KeyMap.cpp | 2 + 6 files changed, 130 insertions(+), 29 deletions(-) diff --git a/build/premake/premake.lua b/build/premake/premake.lua index f51c15ba44..1ee7fb7279 100644 --- a/build/premake/premake.lua +++ b/build/premake/premake.lua @@ -830,14 +830,15 @@ function setup_atlas_packages() "Misc" },{ -- extern_libs "boost", + "comsuppw", "devil", --"ffmpeg", -- disabled for now because it causes too many build difficulties "libxml2", + "sdl", -- key definitions "spidermonkey", "wxwidgets", - "comsuppw", - "zlib", "x11", + "zlib", },{ -- extra_params pch = (not has_broken_pch), extra_links = atlas_extra_links, diff --git a/source/lib/sysdep/os/win/wsdl.cpp b/source/lib/sysdep/os/win/wsdl.cpp index b4e55d1104..dab0d952c8 100644 --- a/source/lib/sysdep/os/win/wsdl.cpp +++ b/source/lib/sysdep/os/win/wsdl.cpp @@ -203,10 +203,11 @@ static inline void video_enter_game_mode() ChangeDisplaySettings(&dm, CDS_FULLSCREEN); } -static inline void video_leave_game_mode() +static inline void video_leave_game_mode(bool hide = true) { ChangeDisplaySettings(0, 0); - ShowWindow(g_hWnd, SW_MINIMIZE); + if(hide) + ShowWindow(g_hWnd, SW_MINIMIZE); } @@ -218,6 +219,27 @@ int SDL_GL_SetAttribute(SDL_GLattr attr, int value) return 0; } +static void compute_window_style_and_size(bool fullscreen, DWORD* windowStyle, int* w, int* h) +{ + *windowStyle = fullscreen? WS_POPUP : WS_POPUPWINDOW|WS_CAPTION|WS_MINIMIZEBOX; + *windowStyle |= WS_VISIBLE; + *windowStyle |= WS_CLIPCHILDREN|WS_CLIPSIBLINGS; // MSDN SetPixelFormat says this is required + + // support resizing of windows + if(!fullscreen) + *windowStyle |= WS_SIZEBOX|WS_MAXIMIZEBOX; + + // Calculate the size of the outer window, so that the client area has + // the desired dimensions. + RECT r; + r.left = r.top = 0; + r.right = *w; r.bottom = *h; + if (AdjustWindowRectEx(&r, *windowStyle, FALSE, 0)) + { + *w = r.right - r.left; + *h = r.bottom - r.top; + } +} static LRESULT CALLBACK wndproc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); @@ -244,20 +266,8 @@ static HWND wsdl_CreateWindow(int w, int h) return 0; } - DWORD windowStyle = fullscreen? WS_POPUP : WS_POPUPWINDOW|WS_CAPTION|WS_MINIMIZEBOX; - windowStyle |= WS_VISIBLE; - windowStyle |= WS_CLIPCHILDREN|WS_CLIPSIBLINGS; // MSDN SetPixelFormat says this is required - - // Calculate the size of the outer window, so that the client area has - // the desired dimensions. - RECT r; - r.left = r.top = 0; - r.right = w; r.bottom = h; - if (AdjustWindowRectEx(&r, windowStyle, FALSE, 0)) - { - w = r.right - r.left; - h = r.bottom - r.top; - } + DWORD windowStyle; + compute_window_style_and_size(fullscreen, &windowStyle, &w, &h); // note: you can override the hardcoded window name via SDL_WM_SetCaption. return CreateWindowExW(WS_EX_APPWINDOW, (LPCWSTR)(uintptr_t)class_atom, L"wsdl", windowStyle, 0, 0, w, h, 0, 0, hInst, 0); @@ -330,20 +340,51 @@ int SDL_SetVideoMode(int w, int h, int bpp, unsigned long flags) } // the (possibly changed) mode will be (re)set at next WM_ACTIVATE - g_hWnd = wsdl_CreateWindow(w, h); - if(!wutil_IsValidHandle(g_hWnd)) - return 0; + if(g_hWnd == (HWND)INVALID_HANDLE_VALUE) + { + g_hWnd = wsdl_CreateWindow(w, h); + if(!wutil_IsValidHandle(g_hWnd)) + return 0; - g_hDC = GetDC(g_hWnd); + g_hDC = GetDC(g_hWnd); - SetPixelFormat(g_hDC, bpp); + SetPixelFormat(g_hDC, bpp); - hGLRC = wglCreateContext(g_hDC); - if(!hGLRC) - return 0; + hGLRC = wglCreateContext(g_hDC); + if(!hGLRC) + return 0; - if(!wglMakeCurrent(g_hDC, hGLRC)) - return 0; + if(!wglMakeCurrent(g_hDC, hGLRC)) + return 0; + } + else + { + // update the existing window + + DWORD oldWindowStyle = GetWindowLongW(g_hWnd, GWL_STYLE); + + DWORD windowStyle; + compute_window_style_and_size(fullscreen, &windowStyle, &w, &h); + + UINT flags = SWP_FRAMECHANGED|SWP_NOZORDER|SWP_NOACTIVATE; + + if(!fullscreen) + { + // preserve the top-left corner if windowed + flags |= SWP_NOMOVE; + + // preserve maximisedness, else we'll mess up when the user attempts to maximise the window + windowStyle |= (oldWindowStyle & WS_MAXIMIZE); + } + + WARN_IF_FALSE(SetWindowLongW(g_hWnd, GWL_STYLE, windowStyle)); + WARN_IF_FALSE(SetWindowPos(g_hWnd, 0, 0, 0, w, h, flags)); + + if(fullscreen) + video_enter_game_mode(); + else + video_leave_game_mode(false); + } return 1; } @@ -956,6 +997,30 @@ int SDL_ShowCursor(int toggle) +//---------------------------------------------------------------------------- +// resizing + +static void queue_resize_event(int w, int h) +{ + SDL_Event ev; + ev.type = SDL_VIDEORESIZE; + ev.resize.w = w; + ev.resize.h = h; + queue_event(ev); +} + +static LRESULT OnPosChanged(HWND hWnd, PWINDOWPOS pos) +{ + RECT client_rect; + WARN_IF_FALSE(GetClientRect(hWnd, &client_rect)); + + queue_resize_event(client_rect.right, client_rect.bottom); + // top, left are documented to always be 0 + + return 0; +} + + //---------------------------------------------------------------------------- static LRESULT OnDestroy(HWND hWnd) @@ -1041,6 +1106,9 @@ static LRESULT CALLBACK wndproc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar case WM_MBUTTONUP: return OnMouseButton(hWnd, uMsg, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), (UINT)wParam); + case WM_WINDOWPOSCHANGED: + return OnPosChanged(hWnd, (PWINDOWPOS)lParam); + default: // can't call DefWindowProc here: some messages // are only conditionally 'grabbed' (e.g. NCHITTEST) diff --git a/source/lib/sysdep/os/win/wsdl.h b/source/lib/sysdep/os/win/wsdl.h index b22d989a90..fa007a4852 100644 --- a/source/lib/sysdep/os/win/wsdl.h +++ b/source/lib/sysdep/os/win/wsdl.h @@ -62,6 +62,7 @@ extern int SDL_GL_SetAttribute(SDL_GLattr attr, int value); // SDL_SetVideoMode() flags #define SDL_OPENGL 0 #define SDL_FULLSCREEN 1 +#define SDL_RESIZABLE 2 extern int SDL_SetVideoMode(int w, int h, int bpp, unsigned long flags); @@ -211,6 +212,14 @@ typedef struct } SDL_ActiveEvent; +typedef struct +{ + Uint8 type; + int w; + int h; +} +SDL_ResizeEvent; + typedef struct { Uint8 type; @@ -228,6 +237,7 @@ enum SDL_Event_type SDL_MOUSEBUTTONUP, SDL_ACTIVEEVENT, SDL_QUIT, + SDL_VIDEORESIZE, SDL_USEREVENT }; @@ -238,6 +248,7 @@ typedef union SDL_MouseMotionEvent motion; SDL_MouseButtonEvent button; SDL_ActiveEvent active; + SDL_ResizeEvent resize; SDL_UserEvent user; } SDL_Event; diff --git a/source/main.cpp b/source/main.cpp index 8a4e49e4e6..20686a47f1 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -72,6 +72,13 @@ extern bool g_GameRestarted; void kill_mainloop(); +// to avoid redundant and/or recursive resizing, we save the new +// size after VIDEORESIZE messages and only update the video mode +// once per frame. +// these values are the latest resize message, and reset to 0 once we've +// updated the video mode +static int g_ResizedW; +static int g_ResizedH; // main app message handler static InReaction MainInputHandler(const SDL_Event_* ev) @@ -83,7 +90,8 @@ static InReaction MainInputHandler(const SDL_Event_* ev) break; case SDL_VIDEORESIZE: - g_VideoMode.ResizeWindow(ev->ev.resize.w, ev->ev.resize.h); + g_ResizedW = ev->ev.resize.w; + g_ResizedH = ev->ev.resize.h; break; case SDL_HOTKEYDOWN: @@ -266,6 +274,13 @@ static void Frame() PumpEvents(); PROFILE_END("input"); + // respond to pumped resize events + if (g_ResizedW || g_ResizedH) + { + g_VideoMode.ResizeWindow(g_ResizedW, g_ResizedH); + g_ResizedW = g_ResizedH = 0; + } + PROFILE_START("network poll"); if (g_NetServer) g_NetServer->Poll(); diff --git a/source/ps/VideoMode.cpp b/source/ps/VideoMode.cpp index 2aa6681081..26316fd8a2 100644 --- a/source/ps/VideoMode.cpp +++ b/source/ps/VideoMode.cpp @@ -159,6 +159,10 @@ bool CVideoMode::ResizeWindow(int w, int h) if (m_IsFullscreen) return true; + // Ignore if the size hasn't changed + if (w == m_WindowedW && h == m_WindowedH) + return true; + int bpp = GetBestBPP(); if (!SetVideoMode(w, h, bpp, false)) diff --git a/source/tools/atlas/AtlasUI/Misc/KeyMap.cpp b/source/tools/atlas/AtlasUI/Misc/KeyMap.cpp index cf52fa2ed8..3e23320c35 100644 --- a/source/tools/atlas/AtlasUI/Misc/KeyMap.cpp +++ b/source/tools/atlas/AtlasUI/Misc/KeyMap.cpp @@ -15,6 +15,8 @@ * along with 0 A.D. If not, see . */ +#include "precompiled.h" + #include "KeyMap.h" #include "SDL/SDL_keysym.h"