From 0317f83b70fc546a7e6ddcc8add5142bba6121a7 Mon Sep 17 00:00:00 2001 From: Maximilian Wagenbach Date: Sun, 11 Feb 2018 16:56:36 +0100 Subject: [PATCH] Implementation for the window states API on Windows. --- src/SFML/Window/Win32/WindowImplWin32.cpp | 139 +++++++++++++++++----- src/SFML/Window/Win32/WindowImplWin32.hpp | 32 ++++- src/SFML/Window/Window.cpp | 23 ++++ 3 files changed, 161 insertions(+), 33 deletions(-) diff --git a/src/SFML/Window/Win32/WindowImplWin32.cpp b/src/SFML/Window/Win32/WindowImplWin32.cpp index e8e17fe5f..bb3ef8480 100755 --- a/src/SFML/Window/Win32/WindowImplWin32.cpp +++ b/src/SFML/Window/Win32/WindowImplWin32.cpp @@ -123,6 +123,28 @@ namespace FreeLibrary(user32Dll); } } + + DWORD translateStyle(sf::Uint32 style) + { + // Choose the window style according to the Style parameter + DWORD win32Style = WS_VISIBLE; + if (style == sf::Style::None) + { + win32Style |= WS_POPUP; + } + else + { + if (style & sf::Style::Titlebar) win32Style |= WS_CAPTION | WS_MINIMIZEBOX; + if (style & sf::Style::Resize) win32Style |= WS_THICKFRAME | WS_MAXIMIZEBOX; + if (style & sf::Style::Close) win32Style |= WS_SYSMENU; + } + if (!(style & sf::Style::Hidden)) + { + win32Style |= WS_VISIBLE; + } + + return win32Style; + } } namespace sf @@ -141,8 +163,9 @@ m_lastSize (0, 0), m_resizing (false), m_surrogate (0), m_mouseInside (false), -m_fullscreen (false), -m_cursorGrabbed (false) +m_cursorGrabbed (false), +m_win32Style (translateStyle(Style::None)), +m_mode (VideoMode::getDesktopMode()) { // Set that this process is DPI aware and can handle DPI scaling setProcessDpiAware(); @@ -174,8 +197,9 @@ m_lastSize (mode.width, mode.height), m_resizing (false), m_surrogate (0), m_mouseInside (false), -m_fullscreen ((style & Style::Fullscreen) != 0), -m_cursorGrabbed (m_fullscreen) +m_cursorGrabbed ((style & Style::Fullscreen) != 0), +m_win32Style (translateStyle(style)), +m_mode (mode) { // Set that this process is DPI aware and can handle DPI scaling setProcessDpiAware(); @@ -192,30 +216,17 @@ m_cursorGrabbed (m_fullscreen) int height = mode.height; ReleaseDC(NULL, screenDC); - // Choose the window style according to the Style parameter - DWORD win32Style = WS_VISIBLE; - if (style == Style::None) - { - win32Style |= WS_POPUP; - } - else - { - if (style & Style::Titlebar) win32Style |= WS_CAPTION | WS_MINIMIZEBOX; - if (style & Style::Resize) win32Style |= WS_THICKFRAME | WS_MAXIMIZEBOX; - if (style & Style::Close) win32Style |= WS_SYSMENU; - } - // In windowed mode, adjust width and height so that window will have the requested client area - if (!m_fullscreen) + if (!(style & Style::Fullscreen)) { RECT rectangle = {0, 0, width, height}; - AdjustWindowRect(&rectangle, win32Style, false); + AdjustWindowRect(&rectangle, m_win32Style, false); width = rectangle.right - rectangle.left; height = rectangle.bottom - rectangle.top; } // Create the window - m_handle = CreateWindowW(className, title.toWideString().c_str(), win32Style, left, top, width, height, NULL, NULL, GetModuleHandle(NULL), this); + m_handle = CreateWindowW(className, title.toWideString().c_str(), m_win32Style, left, top, width, height, NULL, NULL, GetModuleHandle(NULL), this); // Register to receive device interface change notifications (used for joystick connection handling) DEV_BROADCAST_DEVICEINTERFACE deviceInterface = {sizeof(DEV_BROADCAST_DEVICEINTERFACE), DBT_DEVTYP_DEVICEINTERFACE, 0, GUID_DEVINTERFACE_HID, 0}; @@ -230,13 +241,13 @@ m_cursorGrabbed (m_fullscreen) ++handleCount; } - // By default, the OS limits the size of the window the the desktop size, + // By default, the OS limits the size of the window to the desktop size, // we have to resize it after creation to apply the real size setSize(Vector2u(mode.width, mode.height)); // Switch to fullscreen if requested - if (m_fullscreen) - switchToFullscreen(mode); + if (style & Style::Fullscreen) + switchToFullscreen(); // Increment window count windowCount++; @@ -467,6 +478,51 @@ bool WindowImplWin32::hasFocus() const } +//////////////////////////////////////////////////////////// +void WindowImplWin32::setState(State state) +{ + State currentState = getState(); + + switch (state) + { + case State::Windowed: + if (currentState == State::Fullscreen) + switchToWindowed(); + else + ShowWindow(m_handle, SW_RESTORE); + break; + case State::Minimized: + ShowWindow(m_handle, SW_MINIMIZE); + break; + case State::Maximized: + ShowWindow(m_handle, SW_MAXIMIZE); + break; + case State::Fullscreen: + if (currentState != State::Fullscreen) + switchToFullscreen(); + break; + + } +} + + +//////////////////////////////////////////////////////////// +State WindowImplWin32::getState() const +{ + WINDOWPLACEMENT currentState; + currentState.length = sizeof(WINDOWPLACEMENT); + GetWindowPlacement(m_handle, ¤tState); + + if ((currentState.showCmd == SW_MINIMIZE) || (currentState.showCmd == SW_SHOWMINIMIZED)) + return State::Minimized; + if ((currentState.showCmd == SW_MAXIMIZE) || (currentState.showCmd == SW_SHOWMAXIMIZED)) + return State::Maximized; + if (fullscreenWindow == this) + return State::Fullscreen; + + return State::Windowed; +} + //////////////////////////////////////////////////////////// void WindowImplWin32::registerWindowClass() { @@ -486,13 +542,13 @@ void WindowImplWin32::registerWindowClass() //////////////////////////////////////////////////////////// -void WindowImplWin32::switchToFullscreen(const VideoMode& mode) +void WindowImplWin32::switchToFullscreen() { DEVMODE devMode; devMode.dmSize = sizeof(devMode); - devMode.dmPelsWidth = mode.width; - devMode.dmPelsHeight = mode.height; - devMode.dmBitsPerPel = mode.bitsPerPixel; + devMode.dmPelsWidth = m_mode.width; + devMode.dmPelsHeight = m_mode.height; + devMode.dmBitsPerPel = m_mode.bitsPerPixel; devMode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL; // Apply fullscreen mode @@ -507,7 +563,7 @@ void WindowImplWin32::switchToFullscreen(const VideoMode& mode) SetWindowLongW(m_handle, GWL_EXSTYLE, WS_EX_APPWINDOW); // Resize the window so that it fits the entire screen - SetWindowPos(m_handle, HWND_TOP, 0, 0, mode.width, mode.height, SWP_FRAMECHANGED); + SetWindowPos(m_handle, HWND_TOP, 0, 0, m_mode.width, m_mode.height, SWP_FRAMECHANGED); ShowWindow(m_handle, SW_SHOW); // Set "this" as the current fullscreen window @@ -515,6 +571,33 @@ void WindowImplWin32::switchToFullscreen(const VideoMode& mode) } +//////////////////////////////////////////////////////////// +void WindowImplWin32::switchToWindowed() +{ + // Restore the graphics mode of the display device back to the values from the registry + ChangeDisplaySettings(NULL, 0); + + // Set the window flags to what the user requested before switching to fullscreen + SetWindowLongW(m_handle, GWL_STYLE, m_win32Style); + + // Compute position and size + HDC screenDC = GetDC(NULL); + int left = (GetDeviceCaps(screenDC, HORZRES) - static_cast(m_mode.width)) / 2; + int top = (GetDeviceCaps(screenDC, VERTRES) - static_cast(m_mode.height)) / 2; + ReleaseDC(NULL, screenDC); + + RECT rectangle = {0, 0, static_cast(m_mode.width), static_cast(m_mode.height)}; + AdjustWindowRect(&rectangle, m_win32Style, false); + int width = rectangle.right - rectangle.left; + int height = rectangle.bottom - rectangle.top; + + SetWindowPos(m_handle, HWND_TOP, left, top, width, height, SWP_FRAMECHANGED); + + + fullscreenWindow = NULL; +} + + //////////////////////////////////////////////////////////// void WindowImplWin32::cleanup() { diff --git a/src/SFML/Window/Win32/WindowImplWin32.hpp b/src/SFML/Window/Win32/WindowImplWin32.hpp index 4114c51b7..afef5f656 100755 --- a/src/SFML/Window/Win32/WindowImplWin32.hpp +++ b/src/SFML/Window/Win32/WindowImplWin32.hpp @@ -184,6 +184,22 @@ public: //////////////////////////////////////////////////////////// virtual bool hasFocus() const; + //////////////////////////////////////////////////////////// + /// \brief Set the window state + /// + /// \param state The new state + /// + //////////////////////////////////////////////////////////// + virtual void setState(State state); + + //////////////////////////////////////////////////////////// + /// \brief Get the window state + /// + /// \return The window state + /// + //////////////////////////////////////////////////////////// + virtual State getState() const; + protected: //////////////////////////////////////////////////////////// @@ -201,12 +217,16 @@ private: void registerWindowClass(); //////////////////////////////////////////////////////////// - /// \brief Switch to fullscreen mode - /// - /// \param mode Video mode to switch to + /// \brief Switch to fullscreen state /// //////////////////////////////////////////////////////////// - void switchToFullscreen(const VideoMode& mode); + void switchToFullscreen(); + + //////////////////////////////////////////////////////////// + /// \brief Switch to windowed state + /// + //////////////////////////////////////////////////////////// + void switchToWindowed(); //////////////////////////////////////////////////////////// /// \brief Free all the graphical resources attached to the window @@ -282,8 +302,10 @@ private: bool m_resizing; ///< Is the window being resized? Uint16 m_surrogate; ///< First half of the surrogate pair, in case we're receiving a Unicode character in two events bool m_mouseInside; ///< Mouse is inside the window? - bool m_fullscreen; ///< Is the window fullscreen? bool m_cursorGrabbed; ///< Is the mouse cursor trapped? + + const DWORD m_win32Style; ///< Window style in the windows format + const VideoMode m_mode; ///< Video mode of the window }; } // namespace priv diff --git a/src/SFML/Window/Window.cpp b/src/SFML/Window/Window.cpp index ef70f57b9..8cf5fa829 100644 --- a/src/SFML/Window/Window.cpp +++ b/src/SFML/Window/Window.cpp @@ -31,6 +31,8 @@ #include #include +#include + namespace { @@ -371,7 +373,28 @@ bool Window::hasFocus() const void Window::setState(State state) { if (m_impl) + { + // TODO: this if never evaluates to true, even if state IS State::Windowed + // I can't figure out why. This is ehy you can only switch to fullscreen once + if (state == State::Windowed) + { + if (this == fullscreenWindow) + fullscreenWindow == NULL; + } + + if (state == State::Fullscreen) + if (fullscreenWindow != NULL) + { + err() << "Creating more than one fullscreen window is not allowed" << std::endl; + return; + } + else + { + fullscreenWindow = this; + } + m_impl->setState(state); + } }