Added GLFW_FLOATING.

Fixes #23.
This commit is contained in:
Camilla Berglund 2014-05-23 14:01:02 +02:00
parent c9808586b3
commit 3ce7bfef07
11 changed files with 81 additions and 34 deletions

View File

@ -63,6 +63,7 @@ GLFW bundles a number of dependencies in the `deps/` directory.
- Added `GLFW_DONT_CARE` for indicating that any value is acceptable - Added `GLFW_DONT_CARE` for indicating that any value is acceptable
- Added `GLFW_DOUBLEBUFFER` for controlling whether to use double buffering - Added `GLFW_DOUBLEBUFFER` for controlling whether to use double buffering
- Added `GLFW_INCLUDE_ES31` for including the OpenGL ES 3.1 header - Added `GLFW_INCLUDE_ES31` for including the OpenGL ES 3.1 header
- Added `GLFW_FLOATING` for creating always-on-top windowed mode windows
- Added *partial and experimental* support for Wayland - Added *partial and experimental* support for Wayland
- Bugfix: The debug context attribute was set from `GL_ARB_debug_output` even - Bugfix: The debug context attribute was set from `GL_ARB_debug_output` even
when a debug context had not been requested when a debug context had not been requested

View File

@ -41,6 +41,12 @@ building multi-monitor installations, where you need windows to stay in full
screen despite losing focus. screen despite losing focus.
@subsection news_31_floating Floating windows
GLFW not supports floating windows, also called topmost or always on top, for
easier debugging, with the `GLFW_FLOATING` window hint.
@section news_30 New features in version 3.0 @section news_30 New features in version 3.0
@subsection news_30_cmake CMake build system @subsection news_30_cmake CMake build system

View File

@ -122,6 +122,11 @@ The `GLFW_AUTO_ICONIFY` hint specifies whether the (full screen) window
will automatically iconify and restore the previous video mode on focus loss. will automatically iconify and restore the previous video mode on focus loss.
This hint is ignored for windowed mode windows. This hint is ignored for windowed mode windows.
The `GLFW_FLOATING` hint specifies whether the window will be floating above
other regular windows, also called topmost or always-on-top. This is intended
primarily for debugging purposes and cannot be used to implement proper full
screen windows. This hint is ignored for full screen windows.
@subsection window_hints_fb Framebuffer related hints @subsection window_hints_fb Framebuffer related hints
@ -211,6 +216,7 @@ a robustness strategy.
| `GLFW_VISIBLE` | `GL_TRUE` | `GL_TRUE` or `GL_FALSE` | | `GLFW_VISIBLE` | `GL_TRUE` | `GL_TRUE` or `GL_FALSE` |
| `GLFW_DECORATED` | `GL_TRUE` | `GL_TRUE` or `GL_FALSE` | | `GLFW_DECORATED` | `GL_TRUE` | `GL_TRUE` or `GL_FALSE` |
| `GLFW_AUTO_ICONIFY` | `GL_TRUE` | `GL_TRUE` or `GL_FALSE` | | `GLFW_AUTO_ICONIFY` | `GL_TRUE` | `GL_TRUE` or `GL_FALSE` |
| `GLFW_FLOATING` | `GL_FALSE` | `GL_TRUE` or `GL_FALSE` |
| `GLFW_RED_BITS` | 8 | 0 to `INT_MAX` or `GLFW_DONT_CARE` | | `GLFW_RED_BITS` | 8 | 0 to `INT_MAX` or `GLFW_DONT_CARE` |
| `GLFW_GREEN_BITS` | 8 | 0 to `INT_MAX` or `GLFW_DONT_CARE` | | `GLFW_GREEN_BITS` | 8 | 0 to `INT_MAX` or `GLFW_DONT_CARE` |
| `GLFW_BLUE_BITS` | 8 | 0 to `INT_MAX` or `GLFW_DONT_CARE` | | `GLFW_BLUE_BITS` | 8 | 0 to `INT_MAX` or `GLFW_DONT_CARE` |
@ -445,6 +451,10 @@ The `GLFW_DECORATED` attribute indicates whether the specified window has
decorations such as a border, a close widget, etc. This is controlled by the decorations such as a border, a close widget, etc. This is controlled by the
[window hint](@ref window_hints) with the same name. [window hint](@ref window_hints) with the same name.
The `GLFW_FLOATING` attribute indicates whether the specified window is
floating, also called topmost or always-on-top. This is controlled by the
[window hint](@ref window_hints) with the same name.
@subsection window_attribs_context Context attributes @subsection window_attribs_context Context attributes

View File

@ -498,6 +498,7 @@ extern "C" {
#define GLFW_VISIBLE 0x00020004 #define GLFW_VISIBLE 0x00020004
#define GLFW_DECORATED 0x00020005 #define GLFW_DECORATED 0x00020005
#define GLFW_AUTO_ICONIFY 0x00020006 #define GLFW_AUTO_ICONIFY 0x00020006
#define GLFW_FLOATING 0x00020007
#define GLFW_RED_BITS 0x00021001 #define GLFW_RED_BITS 0x00021001
#define GLFW_GREEN_BITS 0x00021002 #define GLFW_GREEN_BITS 0x00021002

View File

@ -972,6 +972,9 @@ static GLboolean createWindow(_GLFWwindow* window,
} }
#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/ #endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/
if (wndconfig->floating)
[window->ns.object setLevel:NSFloatingWindowLevel];
[window->ns.object setTitle:[NSString stringWithUTF8String:wndconfig->title]]; [window->ns.object setTitle:[NSString stringWithUTF8String:wndconfig->title]];
[window->ns.object setContentView:window->ns.view]; [window->ns.object setContentView:window->ns.view];
[window->ns.object setDelegate:window->ns.delegate]; [window->ns.object setDelegate:window->ns.delegate];

View File

@ -153,6 +153,7 @@ struct _GLFWwndconfig
GLboolean visible; GLboolean visible;
GLboolean decorated; GLboolean decorated;
GLboolean autoIconify; GLboolean autoIconify;
GLboolean floating;
_GLFWmonitor* monitor; _GLFWmonitor* monitor;
}; };
@ -218,6 +219,7 @@ struct _GLFWwindow
GLboolean resizable; GLboolean resizable;
GLboolean decorated; GLboolean decorated;
GLboolean autoIconify; GLboolean autoIconify;
GLboolean floating;
GLboolean visible; GLboolean visible;
GLboolean closed; GLboolean closed;
void* userPointer; void* userPointer;
@ -323,6 +325,7 @@ struct _GLFWlibrary
int visible; int visible;
int decorated; int decorated;
int autoIconify; int autoIconify;
int floating;
int samples; int samples;
int sRGB; int sRGB;
int refreshRate; int refreshRate;

View File

@ -951,6 +951,14 @@ static int createWindow(_GLFWwindow* window,
WM_COPYGLOBALDATA, MSGFLT_ALLOW, NULL); WM_COPYGLOBALDATA, MSGFLT_ALLOW, NULL);
} }
if (wndconfig->floating && !wndconfig->monitor)
{
SetWindowPos(window->win32.handle,
HWND_TOPMOST,
0, 0, 0, 0,
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
}
DragAcceptFiles(window->win32.handle, TRUE); DragAcceptFiles(window->win32.handle, TRUE);
if (!_glfwCreateContext(window, ctxconfig, fbconfig)) if (!_glfwCreateContext(window, ctxconfig, fbconfig))

View File

@ -167,6 +167,7 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height,
wndconfig.visible = _glfw.hints.visible ? GL_TRUE : GL_FALSE; wndconfig.visible = _glfw.hints.visible ? GL_TRUE : GL_FALSE;
wndconfig.decorated = _glfw.hints.decorated ? GL_TRUE : GL_FALSE; wndconfig.decorated = _glfw.hints.decorated ? GL_TRUE : GL_FALSE;
wndconfig.autoIconify = _glfw.hints.autoIconify ? GL_TRUE : GL_FALSE; wndconfig.autoIconify = _glfw.hints.autoIconify ? GL_TRUE : GL_FALSE;
wndconfig.floating = _glfw.hints.floating ? GL_TRUE : GL_FALSE;
wndconfig.monitor = (_GLFWmonitor*) monitor; wndconfig.monitor = (_GLFWmonitor*) monitor;
// Set up desired context config // Set up desired context config
@ -205,6 +206,7 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height,
window->resizable = wndconfig.resizable; window->resizable = wndconfig.resizable;
window->decorated = wndconfig.decorated; window->decorated = wndconfig.decorated;
window->autoIconify = wndconfig.autoIconify; window->autoIconify = wndconfig.autoIconify;
window->floating = wndconfig.floating;
window->cursorMode = GLFW_CURSOR_NORMAL; window->cursorMode = GLFW_CURSOR_NORMAL;
// Save the currently current context so it can be restored later // Save the currently current context so it can be restored later
@ -335,6 +337,9 @@ GLFWAPI void glfwWindowHint(int target, int hint)
case GLFW_AUTO_ICONIFY: case GLFW_AUTO_ICONIFY:
_glfw.hints.autoIconify = hint; _glfw.hints.autoIconify = hint;
break; break;
case GLFW_FLOATING:
_glfw.hints.floating = hint;
break;
case GLFW_VISIBLE: case GLFW_VISIBLE:
_glfw.hints.visible = hint; _glfw.hints.visible = hint;
break; break;
@ -585,6 +590,8 @@ GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib)
return window->resizable; return window->resizable;
case GLFW_DECORATED: case GLFW_DECORATED:
return window->decorated; return window->decorated;
case GLFW_FLOATING:
return window->floating;
case GLFW_VISIBLE: case GLFW_VISIBLE:
return window->visible; return window->visible;
case GLFW_CLIENT_API: case GLFW_CLIENT_API:

View File

@ -419,6 +419,8 @@ static void detectEWMH(void)
// See which of the atoms we support that are supported by the WM // See which of the atoms we support that are supported by the WM
_glfw.x11.NET_WM_STATE = _glfw.x11.NET_WM_STATE =
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE"); getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE");
_glfw.x11.NET_WM_STATE_ABOVE =
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_ABOVE");
_glfw.x11.NET_WM_STATE_FULLSCREEN = _glfw.x11.NET_WM_STATE_FULLSCREEN =
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_FULLSCREEN"); getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_FULLSCREEN");
_glfw.x11.NET_WM_NAME = _glfw.x11.NET_WM_NAME =

View File

@ -122,6 +122,7 @@ typedef struct _GLFWlibraryX11
Atom NET_WM_PID; Atom NET_WM_PID;
Atom NET_WM_PING; Atom NET_WM_PING;
Atom NET_WM_STATE; Atom NET_WM_STATE;
Atom NET_WM_STATE_ABOVE;
Atom NET_WM_STATE_FULLSCREEN; Atom NET_WM_STATE_FULLSCREEN;
Atom NET_WM_BYPASS_COMPOSITOR; Atom NET_WM_BYPASS_COMPOSITOR;
Atom NET_ACTIVE_WINDOW; Atom NET_ACTIVE_WINDOW;

View File

@ -108,6 +108,29 @@ static int translateChar(XKeyEvent* event)
return (int) _glfwKeySym2Unicode(keysym); return (int) _glfwKeySym2Unicode(keysym);
} }
// Adds or removes an EWMH state to a window
//
static void changeWindowState(_GLFWwindow* window, Atom state, int action)
{
XEvent event;
memset(&event, 0, sizeof(event));
event.type = ClientMessage;
event.xclient.window = window->x11.handle;
event.xclient.format = 32; // Data is 32-bit longs
event.xclient.message_type = _glfw.x11.NET_WM_STATE;
event.xclient.data.l[0] = action;
event.xclient.data.l[1] = state;
event.xclient.data.l[2] = 0; // No secondary property
event.xclient.data.l[3] = 1; // Sender is a normal application
XSendEvent(_glfw.x11.display,
_glfw.x11.root,
False,
SubstructureNotifyMask | SubstructureRedirectMask,
&event);
}
// Splits and translates a text/uri-list into separate file paths // Splits and translates a text/uri-list into separate file paths
// //
static char** parseUriList(char* text, int* count) static char** parseUriList(char* text, int* count)
@ -382,6 +405,16 @@ static GLboolean createWindow(_GLFWwindow* window,
XIfEvent(_glfw.x11.display, &event, isFrameExtentsEvent, (XPointer) window); XIfEvent(_glfw.x11.display, &event, isFrameExtentsEvent, (XPointer) window);
} }
if (wndconfig->floating && !wndconfig->monitor)
{
if (_glfw.x11.NET_WM_STATE && _glfw.x11.NET_WM_STATE_ABOVE)
{
changeWindowState(window,
_glfw.x11.NET_WM_STATE_ABOVE,
_NET_WM_STATE_ADD);
}
}
_glfwPlatformSetWindowTitle(window, wndconfig->title); _glfwPlatformSetWindowTitle(window, wndconfig->title);
XRRSelectInput(_glfw.x11.display, window->x11.handle, XRRSelectInput(_glfw.x11.display, window->x11.handle,
@ -490,23 +523,9 @@ static void enterFullscreenMode(_GLFWwindow* window)
// Fullscreen windows are undecorated and, when focused, are kept // Fullscreen windows are undecorated and, when focused, are kept
// on top of all other windows // on top of all other windows
XEvent event; changeWindowState(window,
memset(&event, 0, sizeof(event)); _glfw.x11.NET_WM_STATE_FULLSCREEN,
_NET_WM_STATE_ADD);
event.type = ClientMessage;
event.xclient.window = window->x11.handle;
event.xclient.format = 32; // Data is 32-bit longs
event.xclient.message_type = _glfw.x11.NET_WM_STATE;
event.xclient.data.l[0] = _NET_WM_STATE_ADD;
event.xclient.data.l[1] = _glfw.x11.NET_WM_STATE_FULLSCREEN;
event.xclient.data.l[2] = 0; // No secondary property
event.xclient.data.l[3] = 1; // Sender is a normal application
XSendEvent(_glfw.x11.display,
_glfw.x11.root,
False,
SubstructureNotifyMask | SubstructureRedirectMask,
&event);
} }
else if (window->x11.overrideRedirect) else if (window->x11.overrideRedirect)
{ {
@ -557,23 +576,9 @@ static void leaveFullscreenMode(_GLFWwindow* window)
// Ask the window manager to make the GLFW window a normal window // Ask the window manager to make the GLFW window a normal window
// Normal windows usually have frames and other decorations // Normal windows usually have frames and other decorations
XEvent event; changeWindowState(window,
memset(&event, 0, sizeof(event)); _glfw.x11.NET_WM_STATE_FULLSCREEN,
_NET_WM_STATE_REMOVE);
event.type = ClientMessage;
event.xclient.window = window->x11.handle;
event.xclient.format = 32; // Data is 32-bit longs
event.xclient.message_type = _glfw.x11.NET_WM_STATE;
event.xclient.data.l[0] = _NET_WM_STATE_REMOVE;
event.xclient.data.l[1] = _glfw.x11.NET_WM_STATE_FULLSCREEN;
event.xclient.data.l[2] = 0; // No secondary property
event.xclient.data.l[3] = 1; // Sender is a normal application
XSendEvent(_glfw.x11.display,
_glfw.x11.root,
False,
SubstructureNotifyMask | SubstructureRedirectMask,
&event);
} }
} }