Add glfwSetWindowAttrib

This function allows updating the GLFW_DECORATED, GLFW_RESIZABLE,
GLFW_FLOATING and GLFW_AUTO_ICONIFY attributes for existing windows.

Fixes #537.
This commit is contained in:
Camilla Löwy 2016-09-30 01:52:22 +02:00
parent d92bb41e25
commit 9e56099edd
12 changed files with 354 additions and 54 deletions

View File

@ -107,6 +107,7 @@ information on what to include when reporting a bug.
scancodes for keys (#830)
- Added `glfwSetWindowMaximizeCallback` and `GLFWwindowmaximizefun` for
receiving window maximization events (#778)
- Added `glfwSetWindowAttrib` function for changing window attributes (#537)
- Added headless [OSMesa](http://mesa3d.org/osmesa.html) backend (#281,#850)
- Added definition of `GLAPIENTRY` to public header
- Bugfix: Calling `glfwMaximizeWindow` on a full screen window was not ignored

View File

@ -16,6 +16,15 @@ GLFW now supports querying the platform dependent scancode of any key with
@ref glfwGetKeyScancode.
@subsection news_33_setwindowattrib Support for updating window attributes
GLFW now supports changing the [GLFW_DECORATED](@ref GLFW_DECORATED_attrib),
[GLFW_RESIZABLE](@ref GLFW_RESIZABLE_attrib),
[GLFW_FLOATING](@ref GLFW_FLOATING_attrib) and
[GLFW_AUTO_ICONIFY](@ref GLFW_AUTO_ICONIFY_attrib) attributes for existing
windows with @ref glfwSetWindowAttrib.
@subsection news_33_moltenvk Support for Vulkan on macOS via MoltenVK
GLFW now supports the `VK_MVK_macos_surface` window surface creation extension

View File

@ -980,10 +980,10 @@ the window or framebuffer is resized.
@subsection window_attribs Window attributes
Windows have a number of attributes that can be returned using @ref
glfwGetWindowAttrib. Some reflect state that may change during the lifetime of
the window, while others reflect the corresponding hints and are fixed at the
time of creation. Some are related to the actual window and others to its
context.
glfwGetWindowAttrib. Some reflect state that may change as a result of user
interaction, (e.g. whether it has input focus), while others reflect inherent
properties of the window (e.g. what kind of border it has). Some are related to
the window and others to its OpenGL or OpenGL ES context.
@code
if (glfwGetWindowAttrib(window, GLFW_FOCUSED))
@ -992,6 +992,17 @@ if (glfwGetWindowAttrib(window, GLFW_FOCUSED))
}
@endcode
The [GLFW_DECORATED](@ref GLFW_DECORATED_attrib),
[GLFW_RESIZABLE](@ref GLFW_RESIZABLE_attrib),
[GLFW_FLOATING](@ref GLFW_FLOATING_attrib) and
[GLFW_AUTO_ICONIFY](@ref GLFW_AUTO_ICONIFY_attrib) window attributes can be
changed with @ref glfwSetWindowAttrib.
@code
glfwSetWindowAttrib(window, GLFW_RESIZABLE, GLFW_FALSE);
@endcode
@subsubsection window_attribs_wnd Window related attributes
@ -1013,18 +1024,27 @@ window_hide for details.
@anchor GLFW_RESIZABLE_attrib
__GLFW_RESIZABLE__ indicates whether the specified window is resizable _by the
user_. This is set before creation with the
[GLFW_RESIZABLE](@ref GLFW_RESIZABLE_hint) window hint.
user_. This can be set before creation with the
[GLFW_RESIZABLE](@ref GLFW_RESIZABLE_hint) window hint or after with @ref
glfwSetWindowAttrib.
@anchor GLFW_DECORATED_attrib
__GLFW_DECORATED__ indicates whether the specified window has decorations such as
a border, a close widget, etc. This is set before creation with the
[GLFW_DECORATED](@ref GLFW_DECORATED_hint) window hint.
__GLFW_DECORATED__ indicates whether the specified window has decorations such
as a border, a close widget, etc. This can be set before creation with the
[GLFW_DECORATED](@ref GLFW_DECORATED_hint) window hint or after with @ref
glfwSetWindowAttrib.
@anchor GLFW_AUTO_ICONIFY_attrib
__GLFW_AUTO_ICONIFY__ indicates whether the specified full screen window is
iconified on focus loss, a close widget, etc. This can be set before creation
with the [GLFW_AUTO_ICONIFY](@ref GLFW_AUTO_ICONIFY_hint) window hint or after
with @ref glfwSetWindowAttrib.
@anchor GLFW_FLOATING_attrib
__GLFW_FLOATING__ indicates whether the specified window is floating, also
called topmost or always-on-top. This is controlled by the
[GLFW_FLOATING](@ref GLFW_FLOATING_hint) window hint.
called topmost or always-on-top. This can be set before creation with the
[GLFW_FLOATING](@ref GLFW_FLOATING_hint) window hint or after with @ref
glfwSetWindowAttrib.
@subsubsection window_attribs_ctx Context related attributes

View File

@ -663,9 +663,10 @@ extern "C" {
* [window attribute](@ref GLFW_DECORATED_attrib).
*/
#define GLFW_DECORATED 0x00020005
/*! @brief Window auto-iconification window hint
/*! @brief Window auto-iconification window hint and attribute
*
* Window auto-iconification [window hint](@ref GLFW_AUTO_ICONIFY_hint).
* Window auto-iconification [window hint](@ref GLFW_AUTO_ICONIFY_hint) or
* [window attribute](@ref GLFW_AUTO_ICONIFY_attrib).
*/
#define GLFW_AUTO_ICONIFY 0x00020006
/*! @brief Window decoration window hint and attribute
@ -2710,6 +2711,7 @@ GLFWAPI void glfwSetWindowMonitor(GLFWwindow* window, GLFWmonitor* monitor, int
* @thread_safety This function must only be called from the main thread.
*
* @sa @ref window_attribs
* @sa @ref glfwSetWindowAttrib
*
* @since Added in version 3.0. Replaces `glfwGetWindowParam` and
* `glfwGetGLVersion`.
@ -2718,6 +2720,42 @@ GLFWAPI void glfwSetWindowMonitor(GLFWwindow* window, GLFWmonitor* monitor, int
*/
GLFWAPI int glfwGetWindowAttrib(GLFWwindow* window, int attrib);
/*! @brief Sets an attribute of the specified window.
*
* This function sets the value of an attribute of the specified window.
*
* The supported attributes are [GLFW_DECORATED](@ref GLFW_DECORATED_attrib),
* [GLFW_RESIZABLE](@ref GLFW_RESIZABLE_attrib),
* [GLFW_FLOATING](@ref GLFW_FLOATING_attrib) and
* [GLFW_AUTO_ICONIFY](@ref GLFW_AUTO_ICONIFY_attrib).
*
* Some of these attributes are ignored for full screen windows. The new
* value will take effect if the window is later made windowed.
*
* Some of these attributes are ignored for windowed mode windows. The new
* value will take effect if the window is later made full screen.
*
* @param[in] window The window to set the attribute for.
* @param[in] attrib A supported window attribute.
* @param[in] value `GLFW_TRUE` or `GLFW_FALSE`.
*
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
* GLFW_INVALID_ENUM, @ref GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR.
*
* @remark Calling @ref glfwGetWindowAttrib will always return the latest
* value, even if that value is ignored by the current mode of the window.
*
* @thread_safety This function must only be called from the main thread.
*
* @sa @ref window_attribs
* @sa @ref glfwGetWindowAttrib
*
* @since Added in version 3.3.
*
* @ingroup window
*/
GLFWAPI void glfwSetWindowAttrib(GLFWwindow* window, int attrib, int value);
/*! @brief Sets the user pointer of the specified window.
*
* This function sets the user-defined pointer of the specified window. The

View File

@ -1385,6 +1385,25 @@ int _glfwPlatformWindowMaximized(_GLFWwindow* window)
return [window->ns.object isZoomed];
}
void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled)
{
[window->ns.object setStyleMask:getStyleMask(window)];
}
void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled)
{
[window->ns.object setStyleMask:getStyleMask(window)];
[window->ns.object makeFirstResponder:window->ns.view];
}
void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled)
{
if (enabled)
[window->ns.object setLevel:NSFloatingWindowLevel];
else
[window->ns.object setLevel:NSNormalWindowLevel];
}
void _glfwPlatformPollEvents(void)
{
for (;;)

View File

@ -757,6 +757,21 @@ int _glfwPlatformWindowVisible(_GLFWwindow* window);
*/
int _glfwPlatformWindowMaximized(_GLFWwindow* window);
/*! @brief Sets whether the window is resizable by the user.
* @ingroup platform
*/
void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled);
/*! @brief Sets whether the window is decorated.
* @ingroup platform
*/
void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled);
/*! @brief Sets whether the window is floating.
* @ingroup platform
*/
void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled);
/*! @copydoc glfwPollEvents
* @ingroup platform
*/

View File

@ -595,6 +595,24 @@ int _glfwPlatformWindowMaximized(_GLFWwindow* window)
return mir_surface_get_state(window->mir.surface) == mir_surface_state_maximized;
}
void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
}
void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
}
void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
}
void _glfwPlatformPollEvents(void)
{
EventNode* node = NULL;

View File

@ -280,6 +280,26 @@ static void updateClipRect(_GLFWwindow* window)
ClipCursor(NULL);
}
// Update native window styles to match attributes
//
static void updateWindowStyles(const _GLFWwindow* window)
{
RECT rect;
DWORD style = GetWindowLongW(window->win32.handle, GWL_STYLE);
style &= ~(WS_OVERLAPPEDWINDOW | WS_POPUP);
style |= getWindowStyle(window);
GetClientRect(window->win32.handle, &rect);
AdjustWindowRectEx(&rect, style, FALSE, getWindowExStyle(window));
ClientToScreen(window->win32.handle, (POINT*) &rect.left);
ClientToScreen(window->win32.handle, (POINT*) &rect.right);
SetWindowLongW(window->win32.handle, GWL_STYLE, style);
SetWindowPos(window->win32.handle, HWND_TOP,
rect.left, rect.top,
rect.right - rect.left, rect.bottom - rect.top,
SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOZORDER);
}
// Translates a GLFW standard cursor to a resource ID
//
static LPWSTR translateCursorShape(int shape)
@ -1346,6 +1366,23 @@ int _glfwPlatformWindowMaximized(_GLFWwindow* window)
return IsZoomed(window->win32.handle);
}
void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled)
{
updateWindowStyles(window);
}
void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled)
{
updateWindowStyles(window);
}
void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled)
{
const HWND after = enabled ? HWND_TOPMOST : HWND_NOTOPMOST;
SetWindowPos(window->win32.handle, after, 0, 0, 0, 0,
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
}
void _glfwPlatformPollEvents(void)
{
MSG msg;

View File

@ -704,6 +704,8 @@ GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib)
return window->decorated;
case GLFW_FLOATING:
return window->floating;
case GLFW_AUTO_ICONIFY:
return window->autoIconify;
case GLFW_CLIENT_API:
return window->context.client;
case GLFW_CONTEXT_CREATION_API:
@ -732,6 +734,52 @@ GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib)
return 0;
}
GLFWAPI void glfwSetWindowAttrib(GLFWwindow* handle, int attrib, int value)
{
_GLFWwindow* window = (_GLFWwindow*) handle;
assert(window != NULL);
_GLFW_REQUIRE_INIT();
value = value ? GLFW_TRUE : GLFW_FALSE;
switch (attrib)
{
case GLFW_RESIZABLE:
if (window->resizable != value)
{
window->resizable = value;
if (!window->monitor)
_glfwPlatformSetWindowResizable(window, value);
}
return;
case GLFW_DECORATED:
if (window->decorated != value)
{
window->decorated = value;
if (!window->monitor)
_glfwPlatformSetWindowDecorated(window, value);
}
return;
case GLFW_FLOATING:
if (window->floating != value)
{
window->floating = value;
if (!window->monitor)
_glfwPlatformSetWindowFloating(window, value);
}
return;
case GLFW_AUTO_ICONIFY:
window->autoIconify = value;
return;
}
_glfwInputError(GLFW_INVALID_ENUM, "Invalid window attribute %i", attrib);
}
GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* handle)
{
_GLFWwindow* window = (_GLFWwindow*) handle;

View File

@ -634,6 +634,27 @@ int _glfwPlatformWindowMaximized(_GLFWwindow* window)
return window->wl.maximized;
}
void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled)
{
// TODO
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Window attribute setting not implemented yet");
}
void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled)
{
// TODO
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Window attribute setting not implemented yet");
}
void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled)
{
// TODO
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Window attribute setting not implemented yet");
}
void _glfwPlatformPollEvents(void)
{
handleEvents(0);

View File

@ -520,26 +520,7 @@ static GLFWbool createNativeWindow(_GLFWwindow* window,
}
if (!wndconfig->decorated)
{
struct
{
unsigned long flags;
unsigned long functions;
unsigned long decorations;
long input_mode;
unsigned long status;
} hints;
hints.flags = 2; // Set decorations
hints.decorations = 0; // No decorations
XChangeProperty(_glfw.x11.display, window->x11.handle,
_glfw.x11.MOTIF_WM_HINTS,
_glfw.x11.MOTIF_WM_HINTS, 32,
PropModeReplace,
(unsigned char*) &hints,
sizeof(hints) / sizeof(long));
}
_glfwPlatformSetWindowDecorated(window, GLFW_FALSE);
if (_glfw.x11.NET_WM_STATE && !window->monitor)
{
@ -2065,6 +2046,107 @@ int _glfwPlatformWindowMaximized(_GLFWwindow* window)
return maximized;
}
void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled)
{
int width, height;
_glfwPlatformGetWindowSize(window, &width, &height);
updateNormalHints(window, width, height);
}
void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled)
{
if (enabled)
{
XDeleteProperty(_glfw.x11.display,
window->x11.handle,
_glfw.x11.MOTIF_WM_HINTS);
}
else
{
struct
{
unsigned long flags;
unsigned long functions;
unsigned long decorations;
long input_mode;
unsigned long status;
} hints;
hints.flags = 2; // Set decorations
hints.decorations = 0; // No decorations
XChangeProperty(_glfw.x11.display, window->x11.handle,
_glfw.x11.MOTIF_WM_HINTS,
_glfw.x11.MOTIF_WM_HINTS, 32,
PropModeReplace,
(unsigned char*) &hints,
sizeof(hints) / sizeof(long));
}
}
void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled)
{
if (!_glfw.x11.NET_WM_STATE || !_glfw.x11.NET_WM_STATE_ABOVE)
return;
if (_glfwPlatformWindowVisible(window))
{
const Atom action = enabled ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
sendEventToWM(window,
_glfw.x11.NET_WM_STATE,
action,
_glfw.x11.NET_WM_STATE_ABOVE,
0, 1, 0);
}
else
{
Atom* states;
unsigned long i, count;
count = _glfwGetWindowPropertyX11(window->x11.handle,
_glfw.x11.NET_WM_STATE,
XA_ATOM,
(unsigned char**) &states);
if (enabled)
{
for (i = 0; i < count; i++)
{
if (states[i] == _glfw.x11.NET_WM_STATE_ABOVE)
break;
}
if (i == count)
{
XChangeProperty(_glfw.x11.display, window->x11.handle,
_glfw.x11.NET_WM_STATE, XA_ATOM, 32,
PropModeAppend,
(unsigned char*) &_glfw.x11.NET_WM_STATE_ABOVE,
1);
}
}
else
{
for (i = 0; i < count; i++)
{
if (states[i] == _glfw.x11.NET_WM_STATE_ABOVE)
{
states[i] = states[count - 1];
count--;
}
}
XChangeProperty(_glfw.x11.display, window->x11.handle,
_glfw.x11.NET_WM_STATE, XA_ATOM, 32,
PropModeReplace, (unsigned char*) &states, count);
}
XFree(states);
}
XFlush(_glfw.x11.display);
}
void _glfwPlatformPollEvents(void)
{
_glfwPollJoystickEvents();

View File

@ -45,7 +45,6 @@ static void usage(void)
printf(" -a create windows for all monitors\n");
printf(" -f create full screen window(s)\n");
printf(" -h show this help\n");
printf(" -n no automatic iconification of full screen windows\n");
}
static void error_callback(int error, const char* description)
@ -76,6 +75,18 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action,
case GLFW_KEY_ESCAPE:
glfwSetWindowShouldClose(window, GLFW_TRUE);
break;
case GLFW_KEY_A:
glfwSetWindowAttrib(window, GLFW_AUTO_ICONIFY, !glfwGetWindowAttrib(window, GLFW_AUTO_ICONIFY));
break;
case GLFW_KEY_B:
glfwSetWindowAttrib(window, GLFW_RESIZABLE, !glfwGetWindowAttrib(window, GLFW_RESIZABLE));
break;
case GLFW_KEY_D:
glfwSetWindowAttrib(window, GLFW_DECORATED, !glfwGetWindowAttrib(window, GLFW_DECORATED));
break;
case GLFW_KEY_F:
glfwSetWindowAttrib(window, GLFW_FLOATING, !glfwGetWindowAttrib(window, GLFW_FLOATING));
break;
case GLFW_KEY_F11:
case GLFW_KEY_ENTER:
{
@ -143,24 +154,11 @@ static void window_maximize_callback(GLFWwindow* window, int maximized)
static void window_refresh_callback(GLFWwindow* window)
{
int width, height;
printf("%0.2f Window refresh\n", glfwGetTime());
glfwGetFramebufferSize(window, &width, &height);
glfwMakeContextCurrent(window);
glEnable(GL_SCISSOR_TEST);
glScissor(0, 0, width, height);
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
glScissor(0, 0, 640, 480);
glClearColor(1, 1, 1, 0);
glClear(GL_COLOR_BUFFER_BIT);
glfwSwapBuffers(window);
}
@ -203,7 +201,7 @@ static GLFWwindow* create_window(GLFWmonitor* monitor)
int main(int argc, char** argv)
{
int ch, i, window_count;
int auto_iconify = GLFW_TRUE, fullscreen = GLFW_FALSE, all_monitors = GLFW_FALSE;
int fullscreen = GLFW_FALSE, all_monitors = GLFW_FALSE;
GLFWwindow** windows;
while ((ch = getopt(argc, argv, "afhn")) != -1)
@ -222,10 +220,6 @@ int main(int argc, char** argv)
fullscreen = GLFW_TRUE;
break;
case 'n':
auto_iconify = GLFW_FALSE;
break;
default:
usage();
exit(EXIT_FAILURE);
@ -237,8 +231,6 @@ int main(int argc, char** argv)
if (!glfwInit())
exit(EXIT_FAILURE);
glfwWindowHint(GLFW_AUTO_ICONIFY, auto_iconify);
if (fullscreen && all_monitors)
{
int monitor_count;