Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve window creation #767

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 30 additions & 23 deletions include/nbl/ui/IWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,32 @@ class IWindow : public core::IReferenceCounted
public:
enum E_CREATE_FLAGS : uint32_t
{
//! Implicitly adds ECF_BORDERLESS | ECF_ALWAYS_ON_TOP
ECF_FULLSCREEN = 1u << 0,
ECF_HIDDEN = 1u << 1,
ECF_BORDERLESS = 1u << 2,
ECF_RESIZABLE = 1u << 3,
ECF_MINIMIZED = 1u << 4,
ECF_MAXIMIZED = 1u << 5,
//! Indicates whether window can be resized via UI
ECF_UI_RESIZABLE = 1u << 3,
//! Indicates whether window can be resized programmatically
ECF_PROGRAM_RESIZABLE = 1u << 4,
//! Opens the window in manimized mode
//! Implicitly adds ECF_UI_RESIZABLE
ECF_MINIMIZED = 1u << 5,
//! Opens the window in maximized mode
//! Implicitly adds ECF_UI_RESIZABLE
//! NOTE: Not working properly
ECF_MAXIMIZED = 1u << 6,
//! Forces mouse to stay inside the window
ECF_MOUSE_CAPTURE = 1u << 6,
ECF_MOUSE_CAPTURE = 1u << 7,
//! Indicates whether the window is active or not
ECF_INPUT_FOCUS = 1u << 7,
ECF_INPUT_FOCUS = 1u << 8,
//! Indicates whether mouse is hovering over the window even if the window is not active
ECF_MOUSE_FOCUS = 1u << 8,
ECF_ALWAYS_ON_TOP = 1u << 9,
ECF_MOUSE_FOCUS = 1u << 9,
ECF_ALWAYS_ON_TOP = 1u << 10,
//! If disabled, the maximize button is grayed out
ECF_CAN_MAXIMIZE = 1u << 10,
ECF_CAN_MAXIMIZE = 1u << 11,
//! If disabled, the minimize button is grayed out
ECF_CAN_MINIMIZE = 1u << 11,
//! If disabled, the window can't be resized via the UI, only programmatically
ECF_CAN_RESIZE = 1u << 12,
ECF_CAN_MINIMIZE = 1u << 12,

ECF_NONE = 0
};
Expand Down Expand Up @@ -173,18 +180,18 @@ class IWindow : public core::IReferenceCounted
friend class IEventCallback;
inline void setEventCallback(core::smart_refctd_ptr<IEventCallback>&& evCb) { m_cb = std::move(evCb); }

inline bool isFullscreen() { return (m_flags.value & ECF_FULLSCREEN); }
inline bool isHidden() { return (m_flags.value & ECF_HIDDEN); }
inline bool isBorderless() { return (m_flags.value & ECF_BORDERLESS); }
inline bool canProgrammaticallyResize() { return (m_flags.value & ECF_RESIZABLE); }
inline bool isMinimized() { return (m_flags.value & ECF_MINIMIZED); }
inline bool isMaximized() { return (m_flags.value & ECF_MAXIMIZED); }
inline bool hasMouseCaptured() { return (m_flags.value & ECF_MOUSE_CAPTURE); }
inline bool hasInputFocus() { return (m_flags.value & ECF_INPUT_FOCUS); }
inline bool hasMouseFocus() { return (m_flags.value & ECF_MOUSE_FOCUS); }
inline bool isAlwaysOnTop() { return (m_flags.value & ECF_ALWAYS_ON_TOP); }
inline bool isMaximizable() { return (m_flags.value & ECF_CAN_MAXIMIZE); }
inline bool isResizable() { return (m_flags.value & ECF_CAN_RESIZE); }
inline bool isFullscreen() { return (m_flags.value & ECF_FULLSCREEN); }
inline bool isHidden() { return (m_flags.value & ECF_HIDDEN); }
inline bool isBorderless() { return (m_flags.value & ECF_BORDERLESS); }
inline bool isUIResizable() { return (m_flags.value & ECF_UI_RESIZABLE); }
inline bool isProgrammaticallyResizable() { return (m_flags.value & ECF_PROGRAM_RESIZABLE); }
inline bool isMinimized() { return (m_flags.value & ECF_MINIMIZED); }
inline bool isMaximized() { return (m_flags.value & ECF_MAXIMIZED); }
inline bool hasMouseCaptured() { return (m_flags.value & ECF_MOUSE_CAPTURE); }
inline bool hasInputFocus() { return (m_flags.value & ECF_INPUT_FOCUS); }
inline bool hasMouseFocus() { return (m_flags.value & ECF_MOUSE_FOCUS); }
inline bool isAlwaysOnTop() { return (m_flags.value & ECF_ALWAYS_ON_TOP); }
inline bool isMaximizable() { return (m_flags.value & ECF_CAN_MAXIMIZE); }

inline core::bitflag<E_CREATE_FLAGS> getFlags() { return m_flags; }

Expand Down
10 changes: 2 additions & 8 deletions include/nbl/ui/IWindowManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,15 @@ class NBL_API2 IWindowManager : public virtual core::IReferenceCounted

inline bool setWindowSize(IWindow* window, const uint32_t width, const uint32_t height)
{
auto cb = window->getEventCallback();
if (window->getManager()!=this || !window->canProgrammaticallyResize())
if (window->getManager()!=this || !window->isProgrammaticallyResizable())
return false;

return setWindowSize_impl(window, width, height);
}

inline bool setWindowPosition(IWindow* window, const int32_t x, const int32_t y)
{
auto cb = window->getEventCallback();
if (window->getManager()!=this)
if (window->getManager() != this)
return false;

return setWindowPosition_impl(window, x, y);
Expand All @@ -55,7 +53,6 @@ class NBL_API2 IWindowManager : public virtual core::IReferenceCounted

inline bool show(IWindow* window)
{
auto cb = window->getEventCallback();
if (window->getManager() != this || !window->isHidden())
return false;

Expand All @@ -64,7 +61,6 @@ class NBL_API2 IWindowManager : public virtual core::IReferenceCounted

inline bool hide(IWindow* window)
{
auto cb = window->getEventCallback();
if (window->getManager() != this || window->isHidden())
return false;

Expand All @@ -73,7 +69,6 @@ class NBL_API2 IWindowManager : public virtual core::IReferenceCounted

inline bool maximize(IWindow* window)
{
auto cb = window->getEventCallback();
if (window->getManager() != this || window->isMaximized())
return false;

Expand All @@ -82,7 +77,6 @@ class NBL_API2 IWindowManager : public virtual core::IReferenceCounted

inline bool minimize(IWindow* window)
{
auto cb = window->getEventCallback();
if (window->getManager() != this || window->isMinimized())
return false;

Expand Down
82 changes: 50 additions & 32 deletions src/nbl/ui/CWindowManagerWin32.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,59 +29,48 @@ IWindowManager::SDisplayInfo CWindowManagerWin32::getPrimaryDisplayInfo() const
static inline DWORD getWindowStyle(const core::bitflag<IWindow::E_CREATE_FLAGS> flags)
{
DWORD style = WS_POPUP;
// These are always set by GLFW
style |= (WS_CLIPCHILDREN | WS_CLIPSIBLINGS);

if (!flags.hasFlags(IWindow::ECF_FULLSCREEN))
if (!flags.hasFlags(IWindow::ECF_BORDERLESS))
{
if (!flags.hasFlags(IWindow::ECF_BORDERLESS))
{
style |= WS_BORDER;
style |= (WS_SYSMENU | WS_CAPTION);
}
// ? not sure about those below
style |= WS_CLIPCHILDREN;
style |= WS_CLIPSIBLINGS;
style |= WS_BORDER | WS_CAPTION | WS_SYSMENU;
}
if (flags.hasFlags(IWindow::ECF_MINIMIZED))
if (flags.hasFlags(IWindow::ECF_UI_RESIZABLE))
{
style |= WS_MINIMIZE;
style |= WS_SIZEBOX;
}
if (flags.hasFlags(IWindow::ECF_MAXIMIZED))
{
style |= WS_MAXIMIZE;
}
if (flags.hasFlags(IWindow::ECF_ALWAYS_ON_TOP))
{
style |= WS_EX_TOPMOST;
}
if (!flags.hasFlags(IWindow::ECF_HIDDEN))
if (flags.hasFlags(IWindow::ECF_MINIMIZED))
{
style |= WS_VISIBLE;
style |= WS_MINIMIZE;
}
style |= WS_OVERLAPPEDWINDOW;
if (!flags.hasFlags(IWindow::ECF_CAN_RESIZE))
if (flags.hasFlags(IWindow::ECF_CAN_MAXIMIZE))
{
style &= ~WS_SIZEBOX;
style |= WS_MAXIMIZEBOX;
}
if (!flags.hasFlags(IWindow::ECF_CAN_MAXIMIZE))
if (flags.hasFlags(IWindow::ECF_CAN_MINIMIZE))
{
style &= ~WS_MAXIMIZEBOX;
style |= WS_MINIMIZEBOX;
}
if (!flags.hasFlags(IWindow::ECF_CAN_MINIMIZE))
if (!flags.hasFlags(IWindow::ECF_HIDDEN))
{
style &= ~WS_MINIMIZEBOX;
style |= WS_VISIBLE;
}

return style;
}

core::smart_refctd_ptr<IWindow> CWindowManagerWin32::createWindow(IWindow::SCreationParams&& creationParams)
{
// this could be common to all `createWindow` impl
if (creationParams.flags.hasFlags(IWindow::ECF_CAN_RESIZE) || creationParams.flags.hasFlags(IWindow::ECF_CAN_MAXIMIZE))
creationParams.flags |= IWindow::ECF_RESIZABLE;
// win32 minimize is weird, its a resize to 0,0
if (creationParams.flags.hasFlags(IWindow::ECF_CAN_MINIMIZE))
creationParams.flags |= IWindow::ECF_CAN_RESIZE;
if (creationParams.flags.hasFlags(IWindow::ECF_CAN_MAXIMIZE) || creationParams.flags.hasFlags(IWindow::ECF_CAN_MINIMIZE))
creationParams.flags |= IWindow::ECF_UI_RESIZABLE;
if (creationParams.flags.hasFlags(IWindow::ECF_FULLSCREEN))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm I wonder why games have full screen vs windowed borderless fullscreen, do we need to consider this as well? Why are you adding borderless flag when you detect fullscreen?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i did some researching and apparently in windows, the only difference between fullscreen and windowed borderless fullscreen is that the former has the HWND_TOPMOST flag. so:

  • fullscreen: borderless + always-on-top + monitor sized
  • windowed borderless fullscreen: borderless + monitor sized

creationParams.flags |= IWindow::ECF_BORDERLESS | IWindow::ECF_ALWAYS_ON_TOP;

CAsyncQueue::future_t<IWindowWin32::native_handle_t> future;
m_windowThreadManager.request(&future, SRequestParams_CreateWindow{
Expand Down Expand Up @@ -115,7 +104,7 @@ bool CWindowManagerWin32::setWindowSize_impl(IWindow* window, const uint32_t wid
.nativeWindow = static_cast<IWindowWin32*>(window)->getNativeHandle(),
.width = clientSize.right-clientSize.left,
.height = clientSize.bottom-clientSize.top
});
});
return true;
}

Expand Down Expand Up @@ -173,6 +162,15 @@ void CWindowManagerWin32::SRequestParams_CreateWindow::operator()(core::StorageT
clientSize.right = clientSize.left + width;
clientSize.bottom = clientSize.top + height;

if (flags.hasFlags(IWindow::ECF_FULLSCREEN)) {
HMONITOR monitor = MonitorFromPoint({ 0,0 }, MONITOR_DEFAULTTONEAREST);
MONITORINFO monitor_info;
monitor_info.cbSize = sizeof(monitor_info);
GetMonitorInfo(monitor, &monitor_info);
// We ignore the requested size cause they want full screen
clientSize = monitor_info.rcMonitor;
}

const DWORD style = getWindowStyle(flags);

// TODO:
Expand All @@ -192,9 +190,29 @@ void CWindowManagerWin32::SRequestParams_CreateWindow::operator()(core::StorageT
NULL, NULL, hinstance, NULL
);

//
if (flags.hasFlags(IWindow::ECF_ALWAYS_ON_TOP)) {
SetWindowPos(nativeWindow, HWND_TOPMOST, clientSize.left, clientSize.top, realWidth, realHeight, 0);
}

if (flags.hasFlags(IWindow::ECF_MOUSE_CAPTURE)) {
RECT clipRect;
GetClientRect(nativeWindow, &clipRect);
ClientToScreen(nativeWindow, (POINT*)&clipRect.left);
ClientToScreen(nativeWindow, (POINT*)&clipRect.right);
ClipCursor(&clipRect);
}

int show_cmd = SW_SHOWNORMAL;
assert(!flags.hasFlags(IWindow::ECF_MINIMIZED | IWindow::ECF_MAXIMIZED));
if (flags.hasFlags(IWindow::ECF_MINIMIZED)) {
show_cmd = SW_SHOWMINIMIZED;
}
if (flags.hasFlags(IWindow::ECF_MAXIMIZED)) {
show_cmd = SW_SHOWMAXIMIZED;
}

if (!flags.hasFlags(CWindowWin32::ECF_HIDDEN))
ShowWindow(nativeWindow, SW_SHOWNORMAL);
ShowWindow(nativeWindow, show_cmd);
UpdateWindow(nativeWindow);

// fix ugly ATI driver bugs. Thanks to ariaci
Expand Down
1 change: 1 addition & 0 deletions src/nbl/ui/CWindowWin32.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include "nbl/ui/CWindowManagerWin32.h"
#include "nbl/ui/CClipboardManagerWin32.h"
#include "nbl/ui/ICursorControl.h"

#include <cstdint>
#include <queue>
Expand Down