X11: use the window manager's native full-screen implementation when making windows full-screen
This matches the behavior on Cocoa and Wayland. Fixes #1605
This commit is contained in:
parent
c27cf31a7c
commit
1fa9b8f102
@ -133,6 +133,9 @@ To update |kitty|, :doc:`follow the instructions <binary>`.
|
||||
- When launching child processes set the :code:`PWD` environment variable
|
||||
(:iss:`1595`)
|
||||
|
||||
- X11: use the window manager's native full-screen implementation when
|
||||
making windows full-screen (:iss:`1605`)
|
||||
|
||||
0.13.3 [2019-01-19]
|
||||
------------------------------
|
||||
|
||||
|
||||
@ -2001,6 +2001,29 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
|
||||
updateCursorImage(window);
|
||||
}
|
||||
|
||||
bool _glfwPlatformToggleFullscreen(_GLFWwindow* w, unsigned int flags) {
|
||||
NSWindow *window = w->ns.object;
|
||||
bool made_fullscreen = true;
|
||||
bool traditional = flags & 1;
|
||||
NSWindowStyleMask sm = [window styleMask];
|
||||
bool in_fullscreen = sm & NSWindowStyleMaskFullScreen;
|
||||
if (traditional) {
|
||||
if (!(in_fullscreen)) {
|
||||
sm |= NSWindowStyleMaskBorderless | NSWindowStyleMaskFullScreen;
|
||||
[[NSApplication sharedApplication] setPresentationOptions: NSApplicationPresentationAutoHideMenuBar | NSApplicationPresentationAutoHideDock];
|
||||
} else {
|
||||
made_fullscreen = false;
|
||||
sm &= ~(NSWindowStyleMaskBorderless | NSWindowStyleMaskFullScreen);
|
||||
[[NSApplication sharedApplication] setPresentationOptions: NSApplicationPresentationDefault];
|
||||
}
|
||||
[window setStyleMask: sm];
|
||||
} else {
|
||||
if (in_fullscreen) made_fullscreen = false;
|
||||
[window toggleFullScreen: nil];
|
||||
}
|
||||
return made_fullscreen;
|
||||
}
|
||||
|
||||
void _glfwPlatformSetClipboardString(const char* string)
|
||||
{
|
||||
NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
|
||||
|
||||
1
glfw/glfw3.h
vendored
1
glfw/glfw3.h
vendored
@ -2521,6 +2521,7 @@ GLFWAPI void glfwWindowHintString(int hint, const char* value);
|
||||
* @ingroup window
|
||||
*/
|
||||
GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, const char* title, GLFWmonitor* monitor, GLFWwindow* share);
|
||||
GLFWAPI bool glfwToggleFullscreen(GLFWwindow *window, unsigned int flags);
|
||||
|
||||
/*! @brief Destroys the specified window and its context.
|
||||
*
|
||||
|
||||
1
glfw/internal.h
vendored
1
glfw/internal.h
vendored
@ -673,6 +673,7 @@ void _glfwPlatformFocusWindow(_GLFWwindow* window);
|
||||
void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor,
|
||||
int xpos, int ypos, int width, int height,
|
||||
int refreshRate);
|
||||
bool _glfwPlatformToggleFullscreen(_GLFWwindow *w, unsigned int flags);
|
||||
int _glfwPlatformWindowFocused(_GLFWwindow* window);
|
||||
int _glfwPlatformWindowOccluded(_GLFWwindow* window);
|
||||
int _glfwPlatformWindowIconified(_GLFWwindow* window);
|
||||
|
||||
6
glfw/window.c
vendored
6
glfw/window.c
vendored
@ -1017,6 +1017,12 @@ GLFWAPI void glfwSetWindowMonitor(GLFWwindow* wh,
|
||||
refreshRate);
|
||||
}
|
||||
|
||||
GLFWAPI bool glfwToggleFullscreen(GLFWwindow* wh, unsigned int flags) {
|
||||
_GLFWwindow* window = (_GLFWwindow*) wh;
|
||||
if (window) return _glfwPlatformToggleFullscreen(window, flags);
|
||||
return false;
|
||||
}
|
||||
|
||||
GLFWAPI void glfwSetWindowUserPointer(GLFWwindow* handle, void* pointer)
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
|
||||
3
glfw/wl_platform.h
vendored
3
glfw/wl_platform.h
vendored
@ -167,8 +167,7 @@ typedef struct _GLFWwindowWayland
|
||||
|
||||
struct zwp_idle_inhibitor_v1* idleInhibitor;
|
||||
|
||||
// This is a hack to prevent auto-iconification on creation.
|
||||
GLFWbool wasFullScreen;
|
||||
GLFWbool fullscreened;
|
||||
|
||||
struct {
|
||||
GLFWbool serverSide;
|
||||
|
||||
54
glfw/wl_window.c
vendored
54
glfw/wl_window.c
vendored
@ -475,17 +475,32 @@ static GLFWbool createSurface(_GLFWwindow* window,
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
static void setFullscreen(_GLFWwindow* window, _GLFWmonitor* monitor, int refreshRate)
|
||||
static void
|
||||
setFullscreen(_GLFWwindow* window, _GLFWmonitor* monitor, bool on)
|
||||
{
|
||||
if (window->wl.xdg.toplevel)
|
||||
{
|
||||
xdg_toplevel_set_fullscreen(
|
||||
window->wl.xdg.toplevel,
|
||||
monitor->wl.output);
|
||||
if (on) {
|
||||
xdg_toplevel_set_fullscreen(
|
||||
window->wl.xdg.toplevel,
|
||||
monitor ? monitor->wl.output : NULL);
|
||||
if (!window->wl.decorations.serverSide)
|
||||
destroyDecorations(window);
|
||||
} else {
|
||||
xdg_toplevel_unset_fullscreen(window->wl.xdg.toplevel);
|
||||
if (!_glfw.wl.decorationManager)
|
||||
createDecorations(window);
|
||||
}
|
||||
}
|
||||
setIdleInhibitor(window, GLFW_TRUE);
|
||||
if (!window->wl.decorations.serverSide)
|
||||
destroyDecorations(window);
|
||||
setIdleInhibitor(window, on);
|
||||
}
|
||||
|
||||
bool
|
||||
_glfwPlatformToggleFullscreen(_GLFWwindow *window, unsigned int flags) {
|
||||
(void) flags;
|
||||
bool already_fullscreen = window->wl.fullscreened;
|
||||
setFullscreen(window, NULL, !already_fullscreen);
|
||||
return !already_fullscreen;
|
||||
}
|
||||
|
||||
static void xdgToplevelHandleConfigure(void* data,
|
||||
@ -535,18 +550,8 @@ static void xdgToplevelHandleConfigure(void* data,
|
||||
}
|
||||
}
|
||||
}
|
||||
window->wl.fullscreened = fullscreen;
|
||||
dispatchChangesAfterConfigure(window, width, height);
|
||||
|
||||
if (window->wl.wasFullScreen && window->autoIconify)
|
||||
{
|
||||
if (!activated || !fullscreen)
|
||||
{
|
||||
_glfwPlatformIconifyWindow(window);
|
||||
window->wl.wasFullScreen = GLFW_FALSE;
|
||||
}
|
||||
}
|
||||
if (fullscreen && activated)
|
||||
window->wl.wasFullScreen = GLFW_TRUE;
|
||||
_glfwInputWindowFocus(window, activated);
|
||||
}
|
||||
|
||||
@ -1121,18 +1126,7 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
|
||||
int width, int height,
|
||||
int refreshRate)
|
||||
{
|
||||
if (monitor)
|
||||
{
|
||||
setFullscreen(window, monitor, refreshRate);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (window->wl.xdg.toplevel)
|
||||
xdg_toplevel_unset_fullscreen(window->wl.xdg.toplevel);
|
||||
setIdleInhibitor(window, GLFW_FALSE);
|
||||
if (!_glfw.wl.decorationManager)
|
||||
createDecorations(window);
|
||||
}
|
||||
setFullscreen(window, monitor, monitor != NULL);
|
||||
_glfwInputWindowMonitor(window, monitor);
|
||||
}
|
||||
|
||||
|
||||
93
glfw/x11_window.c
vendored
93
glfw/x11_window.c
vendored
@ -265,6 +265,76 @@ static void updateNormalHints(_GLFWwindow* window, int width, int height)
|
||||
XFree(hints);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
is_window_fullscreen(_GLFWwindow* window)
|
||||
{
|
||||
Atom* states;
|
||||
unsigned long i;
|
||||
GLFWbool ans = GLFW_FALSE;
|
||||
if (!_glfw.x11.NET_WM_STATE || !_glfw.x11.NET_WM_STATE_FULLSCREEN)
|
||||
return ans;
|
||||
const unsigned long count =
|
||||
_glfwGetWindowPropertyX11(window->x11.handle,
|
||||
_glfw.x11.NET_WM_STATE,
|
||||
XA_ATOM,
|
||||
(unsigned char**) &states);
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
if (states[i] == _glfw.x11.NET_WM_STATE_FULLSCREEN)
|
||||
{
|
||||
ans = GLFW_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (states)
|
||||
XFree(states);
|
||||
|
||||
return ans;
|
||||
}
|
||||
|
||||
static inline void
|
||||
set_fullscreen(_GLFWwindow *window, bool on) {
|
||||
if (_glfw.x11.NET_WM_STATE && _glfw.x11.NET_WM_STATE_FULLSCREEN) {
|
||||
sendEventToWM(window,
|
||||
_glfw.x11.NET_WM_STATE,
|
||||
on ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE,
|
||||
_glfw.x11.NET_WM_STATE_FULLSCREEN,
|
||||
0, 1, 0);
|
||||
// Enable compositor bypass
|
||||
if (!window->x11.transparent)
|
||||
{
|
||||
if (on) {
|
||||
const unsigned long value = 1;
|
||||
|
||||
XChangeProperty(_glfw.x11.display, window->x11.handle,
|
||||
_glfw.x11.NET_WM_BYPASS_COMPOSITOR, XA_CARDINAL, 32,
|
||||
PropModeReplace, (unsigned char*) &value, 1);
|
||||
} else {
|
||||
XDeleteProperty(_glfw.x11.display, window->x11.handle,
|
||||
_glfw.x11.NET_WM_BYPASS_COMPOSITOR);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
static bool warned = false;
|
||||
if (!warned) {
|
||||
warned = true;
|
||||
_glfwInputErrorX11(GLFW_PLATFORM_ERROR,
|
||||
"X11: Failed to toggle fullscreen, the window manager does not support it");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
_glfwPlatformToggleFullscreen(_GLFWwindow *window, unsigned int flags) {
|
||||
(void) flags;
|
||||
bool already_fullscreen = is_window_fullscreen(window);
|
||||
set_fullscreen(window, !already_fullscreen);
|
||||
return !already_fullscreen;
|
||||
}
|
||||
|
||||
// Updates the full screen status of the window
|
||||
//
|
||||
static void updateWindowMode(_GLFWwindow* window)
|
||||
@ -285,11 +355,7 @@ static void updateWindowMode(_GLFWwindow* window)
|
||||
|
||||
if (_glfw.x11.NET_WM_STATE && _glfw.x11.NET_WM_STATE_FULLSCREEN)
|
||||
{
|
||||
sendEventToWM(window,
|
||||
_glfw.x11.NET_WM_STATE,
|
||||
_NET_WM_STATE_ADD,
|
||||
_glfw.x11.NET_WM_STATE_FULLSCREEN,
|
||||
0, 1, 0);
|
||||
set_fullscreen(window, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -311,15 +377,6 @@ static void updateWindowMode(_GLFWwindow* window)
|
||||
window->x11.overrideRedirect = GLFW_TRUE;
|
||||
}
|
||||
|
||||
// Enable compositor bypass
|
||||
if (!window->x11.transparent)
|
||||
{
|
||||
const unsigned long value = 1;
|
||||
|
||||
XChangeProperty(_glfw.x11.display, window->x11.handle,
|
||||
_glfw.x11.NET_WM_BYPASS_COMPOSITOR, XA_CARDINAL, 32,
|
||||
PropModeReplace, (unsigned char*) &value, 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -332,11 +389,7 @@ static void updateWindowMode(_GLFWwindow* window)
|
||||
|
||||
if (_glfw.x11.NET_WM_STATE && _glfw.x11.NET_WM_STATE_FULLSCREEN)
|
||||
{
|
||||
sendEventToWM(window,
|
||||
_glfw.x11.NET_WM_STATE,
|
||||
_NET_WM_STATE_REMOVE,
|
||||
_glfw.x11.NET_WM_STATE_FULLSCREEN,
|
||||
0, 1, 0);
|
||||
set_fullscreen(window, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -353,8 +406,6 @@ static void updateWindowMode(_GLFWwindow* window)
|
||||
// Disable compositor bypass
|
||||
if (!window->x11.transparent)
|
||||
{
|
||||
XDeleteProperty(_glfw.x11.display, window->x11.handle,
|
||||
_glfw.x11.NET_WM_BYPASS_COMPOSITOR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -392,29 +392,6 @@ cocoa_get_workspace_ids(void *w, size_t *workspace_ids, size_t array_sz) {
|
||||
return ans;
|
||||
}
|
||||
|
||||
bool
|
||||
cocoa_toggle_fullscreen(void *w, bool traditional) {
|
||||
NSWindow *window = (NSWindow*)w;
|
||||
bool made_fullscreen = true;
|
||||
NSWindowStyleMask sm = [window styleMask];
|
||||
bool in_fullscreen = sm & NSWindowStyleMaskFullScreen;
|
||||
if (traditional) {
|
||||
if (!(in_fullscreen)) {
|
||||
sm |= NSWindowStyleMaskBorderless | NSWindowStyleMaskFullScreen;
|
||||
[[NSApplication sharedApplication] setPresentationOptions: NSApplicationPresentationAutoHideMenuBar | NSApplicationPresentationAutoHideDock];
|
||||
} else {
|
||||
made_fullscreen = false;
|
||||
sm &= ~(NSWindowStyleMaskBorderless | NSWindowStyleMaskFullScreen);
|
||||
[[NSApplication sharedApplication] setPresentationOptions: NSApplicationPresentationDefault];
|
||||
}
|
||||
[window setStyleMask: sm];
|
||||
} else {
|
||||
if (in_fullscreen) made_fullscreen = false;
|
||||
[window toggleFullScreen: nil];
|
||||
}
|
||||
return made_fullscreen;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
cocoa_get_lang(PyObject UNUSED *self) {
|
||||
@autoreleasepool {
|
||||
|
||||
3
kitty/glfw-wrapper.c
generated
3
kitty/glfw-wrapper.c
generated
@ -110,6 +110,9 @@ load_glfw(const char* path) {
|
||||
*(void **) (&glfwCreateWindow_impl) = dlsym(handle, "glfwCreateWindow");
|
||||
if (glfwCreateWindow_impl == NULL) fail("Failed to load glfw function glfwCreateWindow with error: %s", dlerror());
|
||||
|
||||
*(void **) (&glfwToggleFullscreen_impl) = dlsym(handle, "glfwToggleFullscreen");
|
||||
if (glfwToggleFullscreen_impl == NULL) fail("Failed to load glfw function glfwToggleFullscreen with error: %s", dlerror());
|
||||
|
||||
*(void **) (&glfwDestroyWindow_impl) = dlsym(handle, "glfwDestroyWindow");
|
||||
if (glfwDestroyWindow_impl == NULL) fail("Failed to load glfw function glfwDestroyWindow with error: %s", dlerror());
|
||||
|
||||
|
||||
4
kitty/glfw-wrapper.h
generated
4
kitty/glfw-wrapper.h
generated
@ -1536,6 +1536,10 @@ typedef GLFWwindow* (*glfwCreateWindow_func)(int, int, const char*, GLFWmonitor*
|
||||
glfwCreateWindow_func glfwCreateWindow_impl;
|
||||
#define glfwCreateWindow glfwCreateWindow_impl
|
||||
|
||||
typedef bool (*glfwToggleFullscreen_func)(GLFWwindow*, unsigned int);
|
||||
glfwToggleFullscreen_func glfwToggleFullscreen_impl;
|
||||
#define glfwToggleFullscreen glfwToggleFullscreen_impl
|
||||
|
||||
typedef void (*glfwDestroyWindow_func)(GLFWwindow*);
|
||||
glfwDestroyWindow_func glfwDestroyWindow_impl;
|
||||
#define glfwDestroyWindow glfwDestroyWindow_impl
|
||||
|
||||
91
kitty/glfw.c
91
kitty/glfw.c
@ -10,7 +10,6 @@
|
||||
#include "glfw-wrapper.h"
|
||||
extern bool cocoa_make_window_resizable(void *w, bool);
|
||||
extern void cocoa_focus_window(void *w);
|
||||
extern bool cocoa_toggle_fullscreen(void *w, bool);
|
||||
extern void cocoa_create_global_menu(void);
|
||||
extern void cocoa_set_hide_from_tasks(void);
|
||||
extern void cocoa_set_titlebar_color(void *w, color_type color);
|
||||
@ -330,43 +329,6 @@ make_os_window_context_current(OSWindow *w) {
|
||||
}
|
||||
|
||||
|
||||
#ifndef __APPLE__
|
||||
static GLFWmonitor*
|
||||
current_monitor(GLFWwindow *window) {
|
||||
// Find the monitor that has the maximum overlap with this window
|
||||
int nmonitors, i;
|
||||
int wx, wy, ww, wh;
|
||||
int mx, my, mw, mh;
|
||||
int overlap = 0, bestoverlap = 0;
|
||||
GLFWmonitor *bestmonitor = NULL;
|
||||
GLFWmonitor **monitors = NULL;
|
||||
const GLFWvidmode *mode;
|
||||
|
||||
glfwGetWindowPos(window, &wx, &wy);
|
||||
glfwGetWindowSize(window, &ww, &wh);
|
||||
monitors = glfwGetMonitors(&nmonitors);
|
||||
if (monitors == NULL || nmonitors < 1) { PyErr_SetString(PyExc_ValueError, "No monitors connected"); return NULL; }
|
||||
|
||||
for (i = 0; i < nmonitors; i++) {
|
||||
mode = glfwGetVideoMode(monitors[i]);
|
||||
glfwGetMonitorPos(monitors[i], &mx, &my);
|
||||
mw = mode->width;
|
||||
mh = mode->height;
|
||||
|
||||
overlap =
|
||||
MAX(0, MIN(wx + ww, mx + mw) - MAX(wx, mx)) *
|
||||
MAX(0, MIN(wy + wh, my + mh) - MAX(wy, my));
|
||||
|
||||
if (bestoverlap < overlap || bestmonitor == NULL) {
|
||||
bestoverlap = overlap;
|
||||
bestmonitor = monitors[i];
|
||||
}
|
||||
}
|
||||
|
||||
return bestmonitor;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void
|
||||
get_window_content_scale(GLFWwindow *w, float *xscale, float *yscale, double *xdpi, double *ydpi) {
|
||||
if (w) glfwGetWindowContentScale(w, xscale, yscale);
|
||||
@ -397,47 +359,34 @@ set_os_window_dpi(OSWindow *w) {
|
||||
get_window_dpi(w->handle, &w->logical_dpi_x, &w->logical_dpi_y);
|
||||
}
|
||||
|
||||
static bool
|
||||
toggle_fullscreen_for_os_window(OSWindow *w) {
|
||||
static inline bool
|
||||
do_toggle_fullscreen(OSWindow *w) {
|
||||
int width, height, x, y;
|
||||
glfwGetWindowSize(w->handle, &width, &height);
|
||||
glfwGetWindowPos(w->handle, &x, &y);
|
||||
#ifdef __APPLE__
|
||||
if (OPT(macos_traditional_fullscreen)) {
|
||||
if (cocoa_toggle_fullscreen(glfwGetCocoaWindow(w->handle), true)) {
|
||||
w->before_fullscreen.is_set = true;
|
||||
w->before_fullscreen.w = width; w->before_fullscreen.h = height; w->before_fullscreen.x = x; w->before_fullscreen.y = y;
|
||||
return true;
|
||||
}
|
||||
if (w->before_fullscreen.is_set) {
|
||||
glfwSetWindowSize(w->handle, w->before_fullscreen.w, w->before_fullscreen.h);
|
||||
glfwSetWindowPos(w->handle, w->before_fullscreen.x, w->before_fullscreen.y);
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
return cocoa_toggle_fullscreen(glfwGetCocoaWindow(w->handle), false);
|
||||
}
|
||||
#else
|
||||
GLFWmonitor *monitor;
|
||||
if ((monitor = glfwGetWindowMonitor(w->handle)) == NULL) {
|
||||
// make fullscreen
|
||||
monitor = current_monitor(w->handle);
|
||||
if (monitor == NULL) { PyErr_Print(); return false; }
|
||||
const GLFWvidmode* mode = glfwGetVideoMode(monitor);
|
||||
if (glfwToggleFullscreen(w->handle, 1)) {
|
||||
w->before_fullscreen.is_set = true;
|
||||
w->before_fullscreen.w = width; w->before_fullscreen.h = height; w->before_fullscreen.x = x; w->before_fullscreen.y = y;
|
||||
glfwGetWindowSize(w->handle, &w->before_fullscreen.w, &w->before_fullscreen.h);
|
||||
glfwGetWindowPos(w->handle, &w->before_fullscreen.x, &w->before_fullscreen.y);
|
||||
glfwSetWindowMonitor(w->handle, monitor, 0, 0, mode->width, mode->height, mode->refreshRate);
|
||||
return true;
|
||||
} else {
|
||||
// make windowed
|
||||
const GLFWvidmode* mode = glfwGetVideoMode(monitor);
|
||||
if (w->before_fullscreen.is_set) glfwSetWindowMonitor(w->handle, NULL, w->before_fullscreen.x, w->before_fullscreen.y, w->before_fullscreen.w, w->before_fullscreen.h, mode->refreshRate);
|
||||
else glfwSetWindowMonitor(w->handle, NULL, 0, 0, 600, 400, mode->refreshRate);
|
||||
return false;
|
||||
}
|
||||
if (w->before_fullscreen.is_set) {
|
||||
glfwSetWindowSize(w->handle, w->before_fullscreen.w, w->before_fullscreen.h);
|
||||
glfwSetWindowPos(w->handle, w->before_fullscreen.x, w->before_fullscreen.y);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
toggle_fullscreen_for_os_window(OSWindow *w) {
|
||||
if (w && w->handle) {
|
||||
#ifdef __APPLE__
|
||||
if (!OPT(macos_traditional_fullscreen) return glfwToggleFullscreen(w->handle, 0);
|
||||
return do_toggle_fullscreen(w);
|
||||
#else
|
||||
return do_toggle_fullscreen(w);
|
||||
#endif
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user