Implementation for the window states API on Windows.

This commit is contained in:
Maximilian Wagenbach 2018-02-11 16:56:36 +01:00 committed by Lukas Dürrenberger
parent c793b81235
commit 0317f83b70
3 changed files with 161 additions and 33 deletions

View File

@ -123,6 +123,28 @@ namespace
FreeLibrary(user32Dll); 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 namespace sf
@ -141,8 +163,9 @@ m_lastSize (0, 0),
m_resizing (false), m_resizing (false),
m_surrogate (0), m_surrogate (0),
m_mouseInside (false), 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 // Set that this process is DPI aware and can handle DPI scaling
setProcessDpiAware(); setProcessDpiAware();
@ -174,8 +197,9 @@ m_lastSize (mode.width, mode.height),
m_resizing (false), m_resizing (false),
m_surrogate (0), m_surrogate (0),
m_mouseInside (false), m_mouseInside (false),
m_fullscreen ((style & Style::Fullscreen) != 0), m_cursorGrabbed ((style & Style::Fullscreen) != 0),
m_cursorGrabbed (m_fullscreen) m_win32Style (translateStyle(style)),
m_mode (mode)
{ {
// Set that this process is DPI aware and can handle DPI scaling // Set that this process is DPI aware and can handle DPI scaling
setProcessDpiAware(); setProcessDpiAware();
@ -192,30 +216,17 @@ m_cursorGrabbed (m_fullscreen)
int height = mode.height; int height = mode.height;
ReleaseDC(NULL, screenDC); 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 // 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}; RECT rectangle = {0, 0, width, height};
AdjustWindowRect(&rectangle, win32Style, false); AdjustWindowRect(&rectangle, m_win32Style, false);
width = rectangle.right - rectangle.left; width = rectangle.right - rectangle.left;
height = rectangle.bottom - rectangle.top; height = rectangle.bottom - rectangle.top;
} }
// Create the window // 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) // 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}; 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; ++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 // we have to resize it after creation to apply the real size
setSize(Vector2u(mode.width, mode.height)); setSize(Vector2u(mode.width, mode.height));
// Switch to fullscreen if requested // Switch to fullscreen if requested
if (m_fullscreen) if (style & Style::Fullscreen)
switchToFullscreen(mode); switchToFullscreen();
// Increment window count // Increment window count
windowCount++; 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, &currentState);
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() void WindowImplWin32::registerWindowClass()
{ {
@ -486,13 +542,13 @@ void WindowImplWin32::registerWindowClass()
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void WindowImplWin32::switchToFullscreen(const VideoMode& mode) void WindowImplWin32::switchToFullscreen()
{ {
DEVMODE devMode; DEVMODE devMode;
devMode.dmSize = sizeof(devMode); devMode.dmSize = sizeof(devMode);
devMode.dmPelsWidth = mode.width; devMode.dmPelsWidth = m_mode.width;
devMode.dmPelsHeight = mode.height; devMode.dmPelsHeight = m_mode.height;
devMode.dmBitsPerPel = mode.bitsPerPixel; devMode.dmBitsPerPel = m_mode.bitsPerPixel;
devMode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL; devMode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL;
// Apply fullscreen mode // Apply fullscreen mode
@ -507,7 +563,7 @@ void WindowImplWin32::switchToFullscreen(const VideoMode& mode)
SetWindowLongW(m_handle, GWL_EXSTYLE, WS_EX_APPWINDOW); SetWindowLongW(m_handle, GWL_EXSTYLE, WS_EX_APPWINDOW);
// Resize the window so that it fits the entire screen // 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); ShowWindow(m_handle, SW_SHOW);
// Set "this" as the current fullscreen window // 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<int>(m_mode.width)) / 2;
int top = (GetDeviceCaps(screenDC, VERTRES) - static_cast<int>(m_mode.height)) / 2;
ReleaseDC(NULL, screenDC);
RECT rectangle = {0, 0, static_cast<LONG>(m_mode.width), static_cast<LONG>(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() void WindowImplWin32::cleanup()
{ {

View File

@ -184,6 +184,22 @@ public:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
virtual bool hasFocus() const; 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: protected:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -201,12 +217,16 @@ private:
void registerWindowClass(); void registerWindowClass();
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Switch to fullscreen mode /// \brief Switch to fullscreen state
///
/// \param mode Video mode to switch to
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void switchToFullscreen(const VideoMode& mode); void switchToFullscreen();
////////////////////////////////////////////////////////////
/// \brief Switch to windowed state
///
////////////////////////////////////////////////////////////
void switchToWindowed();
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Free all the graphical resources attached to the window /// \brief Free all the graphical resources attached to the window
@ -282,8 +302,10 @@ private:
bool m_resizing; ///< Is the window being resized? 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 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_mouseInside; ///< Mouse is inside the window?
bool m_fullscreen; ///< Is the window fullscreen?
bool m_cursorGrabbed; ///< Is the mouse cursor trapped? 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 } // namespace priv

View File

@ -31,6 +31,8 @@
#include <SFML/System/Sleep.hpp> #include <SFML/System/Sleep.hpp>
#include <SFML/System/Err.hpp> #include <SFML/System/Err.hpp>
#include <iostream>
namespace namespace
{ {
@ -371,7 +373,28 @@ bool Window::hasFocus() const
void Window::setState(State state) void Window::setState(State state)
{ {
if (m_impl) 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); m_impl->setState(state);
}
} }