diff --git a/examples/display/DisplayExample.cpp b/examples/display/DisplayExample.cpp index 2cbe330..8a430ae 100644 --- a/examples/display/DisplayExample.cpp +++ b/examples/display/DisplayExample.cpp @@ -24,7 +24,19 @@ void DisplayExample::onEvent(const sp::Event& event) { if (event.type == sp::Event::Key && event.key.pressed == false) { - if (event.key.code == sp::Keyboard::Space) { + if (event.key.code == sp::Keyboard::W) { + + if (m_mode == sp::Display::WINDOWED) { + m_mode = sp::Display::WINDOWEDFULLSCREEN; + sp::Log::info("Windowed Fullscreen"); + } else { + m_mode = sp::Display::WINDOWED; + sp::Log::info("Windowed"); + } + + getGraphics()->setDisplayMode(m_mode); + + } else if (event.key.code == sp::Keyboard::Space) { if (m_mode == sp::Display::WINDOWED) { m_mode = sp::Display::FULLSCREEN; diff --git a/include/Spectre/Display/Display.h b/include/Spectre/Display/Display.h index 0985945..073fd0d 100644 --- a/include/Spectre/Display/Display.h +++ b/include/Spectre/Display/Display.h @@ -4,6 +4,7 @@ #include "DisplayMode.h" #include "DisplayDescription.h" +#include #include #include #include @@ -71,6 +72,10 @@ protected : protected : enum Mode m_fmode; + // Cache window position when entering fullscreen + // So it can be restored when returning to window mode. + Vector2u m_cachePos; + DisplayDescription m_description; DisplayDescription m_cacheDesc; diff --git a/source/Display/Display.cpp b/source/Display/Display.cpp index 24ced50..b7a3135 100644 --- a/source/Display/Display.cpp +++ b/source/Display/Display.cpp @@ -98,28 +98,39 @@ void Display::setSize(unsigned int width, unsigned int height) void Display::setVideoMode(Mode mode) { - DisplayDescription desc; - if (m_fmode == mode) { return; } - if (mode == FULLSCREEN || mode == WINDOWEDFULLSCREEN) { - - // True fullscreen - if (mode == FULLSCREEN) { - desc.mode = m_description.mode; - } else { - desc.mode = DisplayMode::getDesktopMode(); - m_cacheDesc = m_description; - } - - desc.decoration = DisplayDecorate::None; - } else { - desc = m_cacheDesc; + if (mode != FULLSCREEN) { + m_impl->exitFullscreen(); } - create(desc); + // Cache window position when entering fullscreen. + if (mode == FULLSCREEN || mode == WINDOWEDFULLSCREEN) { + m_cachePos = m_impl->getPosition(); + } + + // True fullscreen + if (mode == FULLSCREEN) { + m_impl->enterFullscreen(m_description.mode); + } + // Windowed fullscreen. + else if (mode == WINDOWEDFULLSCREEN) { + DisplayMode desktop = DisplayMode::getDesktopMode(); + m_impl->setDecoration(DisplayDecorate::None); + m_impl->setSize(desktop.width, desktop.height); + m_impl->setPosition(0, 0); + } + // Window mode. + else { + // Set stored decoration. + m_impl->setDecoration(m_description.decoration); + + // Restore size and position. + m_impl->setSize(m_description.mode.width, m_description.mode.height); + m_impl->setPosition(m_cachePos.x, m_cachePos.y); + } m_fmode = mode; } diff --git a/source/Graphics/OpenGL.cpp b/source/Graphics/OpenGL.cpp index ef7383d..da752dd 100644 --- a/source/Graphics/OpenGL.cpp +++ b/source/Graphics/OpenGL.cpp @@ -24,8 +24,6 @@ bool Graphics::init() DisplayMode mode(m_width, m_height); DisplayDescription desc(mode); - desc.decoration = DisplayDecorate::Menu | DisplayDecorate::Close | DisplayDecorate::Resize; - if (!m_display->create(desc)) { return false; } diff --git a/source/Platform/PlatformDisplay.h b/source/Platform/PlatformDisplay.h index 2147230..3fff71f 100644 --- a/source/Platform/PlatformDisplay.h +++ b/source/Platform/PlatformDisplay.h @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -39,10 +40,16 @@ public : virtual void setVisible(bool visible) = 0; + virtual void setDecoration(unsigned decoration) = 0; + virtual void minimize() = 0; virtual void maximize() = 0; + virtual void enterFullscreen(DisplayMode mode) = 0; + + virtual void exitFullscreen() = 0; + virtual void setCaption(const std::string& caption) = 0; virtual void setIcon(unsigned int width, unsigned int height, const uint8_t *pixels) = 0; diff --git a/source/Platform/Win32/Win32Display.cpp b/source/Platform/Win32/Win32Display.cpp index 25544e2..294b9a0 100644 --- a/source/Platform/Win32/Win32Display.cpp +++ b/source/Platform/Win32/Win32Display.cpp @@ -41,7 +41,7 @@ Win32Display::~Win32Display() bool Win32Display::create(DisplayDescription description) { - DWORD flags = getWin32Flags(description.decoration); + DWORD flags; Vector2i pos; if (firstTime) { @@ -49,7 +49,9 @@ bool Win32Display::create(DisplayDescription description) firstTime = false; } + // Set window to center and set decoration flags. pos = centerWindow(description.mode.width, description.mode.height); + flags = getWin32Flags(description.decoration); // Create window. m_handle = CreateWindowExA(0, WND_CLASSNAME, "", flags, @@ -128,6 +130,11 @@ void Win32Display::setVisible(bool visible) ::ShowWindow(m_handle, visible ? SW_SHOW : SW_HIDE); } +void Win32Display::setDecoration(unsigned decoration) +{ + ::SetWindowLong(m_handle, GWL_STYLE, getWin32Flags(decoration)); +} + void Win32Display::minimize() { ::ShowWindow(m_handle, SW_MINIMIZE); @@ -277,6 +284,60 @@ Vector2i Win32Display::centerWindow(int width, int height) return v; } +void Win32Display::enterFullscreen(DisplayMode mode) +{ + LONG rc; + ::DEVMODEW dev; + dev.dmSize = sizeof(dev); + dev.dmPelsWidth = mode.width; + dev.dmPelsHeight = mode.height; + dev.dmBitsPerPel = mode.bpp; + dev.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL; + + rc = ::ChangeDisplaySettingsW(&dev, CDS_FULLSCREEN); + if (rc != DISP_CHANGE_SUCCESSFUL) { + const char *msg; + + switch(rc) { + case DISP_CHANGE_BADDUALVIEW : + msg = "The system is DualView capable"; break; + case DISP_CHANGE_BADFLAGS : + msg = "Invalid flags given"; break; + case DISP_CHANGE_BADPARAM : + msg = "Invalid parameter"; break; + case DISP_CHANGE_BADMODE : + msg = "Resolution not supported"; break; + case DISP_CHANGE_FAILED : + msg = "Display driver failed to set mode"; break; + case DISP_CHANGE_NOTUPDATED : + msg = "Unable to write settings to the registry"; break; + case DISP_CHANGE_RESTART : + msg = "System restart required"; break; + default : + msg = "Unkown error"; + } + + sp::Log::error("Win32: Failed to switch to fullscreen mode: %s.", msg); + return; + } + + ::SetWindowLong(m_handle, GWL_STYLE, WS_VISIBLE | WS_POPUP); + ::SetWindowPos(m_handle, HWND_TOP, 0, 0, mode.width, mode.height, SWP_FRAMECHANGED | SWP_SHOWWINDOW); + + grabCursor(true); + + m_fs_mode = mode; +} + +void Win32Display::exitFullscreen() +{ + if (!m_fs_mode.empty()) { + // Restore to previous mode. + ::ChangeDisplaySettingsW(NULL, 0); + m_fs_mode = DisplayMode(); + } +} + void Win32Display::processResizeMessage(const Vector2u& new_size) { // Check if the size has actually changed. @@ -301,9 +362,22 @@ void Win32Display::processMessage(UINT message, WPARAM wParam, LPARAM lParam) break; case WM_SETFOCUS : Log::debug("WM_SETFOCUS"); + if (m_fs_mode.empty() == false) { + enterFullscreen(m_fs_mode); + } break; case WM_KILLFOCUS : Log::debug("WM_KILLFOCUS"); + // If in fullscreen mode. + if (m_fs_mode.empty() == false) { + // Switch to window mode. + ::ChangeDisplaySettingsW(NULL, 0); + + // also minimize the window to get it out of the way. + minimize(); + } + + grabCursor(false); break; case WM_SIZE : diff --git a/source/Platform/Win32/Win32Display.h b/source/Platform/Win32/Win32Display.h index 80c7cc3..510c275 100644 --- a/source/Platform/Win32/Win32Display.h +++ b/source/Platform/Win32/Win32Display.h @@ -33,6 +33,12 @@ public : virtual void setVisible(bool visible); + virtual void setDecoration(unsigned decoration); + + virtual void enterFullscreen(DisplayMode mode); + + virtual void exitFullscreen(); + virtual void minimize(); virtual void maximize(); @@ -74,6 +80,9 @@ protected : Vector2u m_size; Vector2u m_minSize; + + // Fullscreen mode. + DisplayMode m_fs_mode; }; } // namespace sp