macOS: Make full screening of kitty much faster by using the "traditional full screen" mode of cocoa, similar to iTerm and MacVim

Hopefully workaround a bug in glfw that causes crashes when unplugging
monitors with full screen windows.

Fixes #911
Fixes #898
This commit is contained in:
Kovid Goyal 2018-09-12 15:45:08 +05:30
parent 21d586cc86
commit ec1f219850
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
8 changed files with 122 additions and 26 deletions

View File

@ -25,6 +25,11 @@ Changelog
on macs thicker, which makes it similar to the result of
sub-pixel antialiasing (:pull:`950`)
- macOS: Make full screening of kitty much faster by using the "traditional full
screen" mode of cocoa, similar to iTerm and MacVim (:iss:`911`). Also should
hopefully workaround a bug in glfw that causes crashes when unplugging
monitors with full screen windows. (:iss:`898`)
- Fix drag-scrolling not working when the mouse leaves the window confines
(:iss:`917`)

View File

@ -39,6 +39,7 @@ typedef void* id;
typedef VkFlags VkMacOSSurfaceCreateFlagsMVK;
typedef int (* GLFWcocoatextinputfilterfun)(int,int,int);
typedef int (* GLFWapplicationshouldhandlereopenfun)(int);
typedef int (* GLFWcocoatogglefullscreenfun)(GLFWwindow*);
typedef struct VkMacOSSurfaceCreateInfoMVK
{
@ -102,6 +103,8 @@ typedef struct _GLFWwindowNS
// The text input filter callback
GLFWcocoatextinputfilterfun textInputFilterCallback;
// The toggle fullscreen intercept callback
GLFWcocoatogglefullscreenfun toggleFullscreenCallback;
// Dead key state
UInt32 deadKeyState;
} _GLFWwindowNS;

View File

@ -563,6 +563,10 @@ - (void)dealloc
[super dealloc];
}
- (_GLFWwindow*)glfwWindow {
return window;
}
- (BOOL)isOpaque
{
return [window->ns.object isOpaque];
@ -1040,6 +1044,18 @@ - (BOOL)canBecomeMainWindow
return YES;
}
- (void)toggleFullScreen:(nullable id)sender
{
GLFWContentView *view = [self contentView];
if (view)
{
_GLFWwindow *window = [view glfwWindow];
if (window && window->ns.toggleFullscreenCallback && window->ns.toggleFullscreenCallback((GLFWwindow*)window) == 1)
return;
}
[super toggleFullScreen:sender];
}
@end
@ -2114,6 +2130,14 @@ GLFWAPI GLFWcocoatextinputfilterfun glfwSetCocoaTextInputFilter(GLFWwindow *hand
return previous;
}
GLFWAPI GLFWcocoatogglefullscreenfun glfwSetCocoaToggleFullscreenIntercept(GLFWwindow *handle, GLFWcocoatogglefullscreenfun callback) {
_GLFWwindow* window = (_GLFWwindow*) handle;
_GLFW_REQUIRE_INIT_OR_RETURN(nil);
GLFWcocoatogglefullscreenfun previous = window->ns.toggleFullscreenCallback;
window->ns.toggleFullscreenCallback = callback;
return previous;
}
GLFWAPI GLFWapplicationshouldhandlereopenfun glfwSetApplicationShouldHandleReopen(GLFWapplicationshouldhandlereopenfun callback) {
GLFWapplicationshouldhandlereopenfun previous = handle_reopen_callback;
handle_reopen_callback = callback;

View File

@ -194,6 +194,7 @@ def generate_wrappers(glfw_header, glfw_native_header):
void* glfwGetCocoaWindow(GLFWwindow* window)
uint32_t glfwGetCocoaMonitor(GLFWmonitor* monitor)
GLFWcocoatextinputfilterfun glfwSetCocoaTextInputFilter(GLFWwindow* window, GLFWcocoatextinputfilterfun callback)
GLFWcocoatogglefullscreenfun glfwSetCocoaToggleFullscreenIntercept(GLFWwindow *window, GLFWcocoatogglefullscreenfun callback)
GLFWapplicationshouldhandlereopenfun glfwSetApplicationShouldHandleReopen(GLFWapplicationshouldhandlereopenfun callback)
void glfwGetCocoaKeyEquivalent(int glfw_key, int glfw_mods, void* cocoa_key, void* cocoa_mods)
void* glfwGetX11Display(void)
@ -213,11 +214,13 @@ def generate_wrappers(glfw_header, glfw_native_header):
#pragma once
#include <stddef.h>
#include <stdint.h>
typedef int (* GLFWcocoatextinputfilterfun)(int,int,unsigned int);
typedef int (* GLFWapplicationshouldhandlereopenfun)(int);
{}
typedef int (* GLFWcocoatextinputfilterfun)(int,int,unsigned int);
typedef int (* GLFWapplicationshouldhandlereopenfun)(int);
typedef int (* GLFWcocoatogglefullscreenfun)(GLFWwindow*);
{}
const char* load_glfw(const char* path);

View File

@ -224,6 +224,24 @@ + (GlobalMenuTarget *) shared_instance
[window makeKeyWindow];
}
bool
cocoa_toggle_fullscreen(void *w) {
NSWindow *window = (NSWindow*)w;
NSWindowStyleMask sm = [window styleMask];
bool made_fullscreen;
if (!(sm & NSWindowStyleMaskFullScreen)) {
made_fullscreen = true;
sm |= NSWindowStyleMaskBorderless | NSWindowStyleMaskFullScreen;
[[NSApplication sharedApplication] setPresentationOptions: NSApplicationPresentationAutoHideMenuBar | NSApplicationPresentationAutoHideDock];
} else {
made_fullscreen = false;
sm &= ~(NSWindowStyleMaskBorderless | NSWindowStyleMaskFullScreen);
[[NSApplication sharedApplication] setPresentationOptions: NSApplicationPresentationDefault];
}
[window setStyleMask: sm];
return made_fullscreen;
}
static PyObject*
cocoa_get_lang(PyObject UNUSED *self) {
NSString* locale = nil;

2
kitty/glfw-wrapper.c generated
View File

@ -362,6 +362,8 @@ load_glfw(const char* path) {
*(void **) (&glfwSetCocoaTextInputFilter_impl) = dlsym(handle, "glfwSetCocoaTextInputFilter");
*(void **) (&glfwSetCocoaToggleFullscreenIntercept_impl) = dlsym(handle, "glfwSetCocoaToggleFullscreenIntercept");
*(void **) (&glfwSetApplicationShouldHandleReopen_impl) = dlsym(handle, "glfwSetApplicationShouldHandleReopen");
*(void **) (&glfwGetCocoaKeyEquivalent_impl) = dlsym(handle, "glfwGetCocoaKeyEquivalent");

10
kitty/glfw-wrapper.h generated
View File

@ -1,8 +1,6 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
typedef int (* GLFWcocoatextinputfilterfun)(int,int,unsigned int);
typedef int (* GLFWapplicationshouldhandlereopenfun)(int);
@ -1386,6 +1384,10 @@ typedef struct GLFWgamepadstate
*/
typedef int (* GLFWcocoatextinputfilterfun)(int,int,unsigned int);
typedef int (* GLFWapplicationshouldhandlereopenfun)(int);
typedef int (* GLFWcocoatogglefullscreenfun)(GLFWwindow*);
typedef int (*glfwInit_func)();
glfwInit_func glfwInit_impl;
#define glfwInit glfwInit_impl
@ -1854,6 +1856,10 @@ typedef GLFWcocoatextinputfilterfun (*glfwSetCocoaTextInputFilter_func)(GLFWwind
glfwSetCocoaTextInputFilter_func glfwSetCocoaTextInputFilter_impl;
#define glfwSetCocoaTextInputFilter glfwSetCocoaTextInputFilter_impl
typedef GLFWcocoatogglefullscreenfun (*glfwSetCocoaToggleFullscreenIntercept_func)(GLFWwindow*, GLFWcocoatogglefullscreenfun);
glfwSetCocoaToggleFullscreenIntercept_func glfwSetCocoaToggleFullscreenIntercept_impl;
#define glfwSetCocoaToggleFullscreenIntercept glfwSetCocoaToggleFullscreenIntercept_impl
typedef GLFWapplicationshouldhandlereopenfun (*glfwSetApplicationShouldHandleReopen_func)(GLFWapplicationshouldhandlereopenfun);
glfwSetApplicationShouldHandleReopen_func glfwSetApplicationShouldHandleReopen_impl;
#define glfwSetApplicationShouldHandleReopen glfwSetApplicationShouldHandleReopen_impl

View File

@ -10,6 +10,7 @@
#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);
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);
@ -355,11 +356,55 @@ 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) {
int width, height, x, y;
glfwGetWindowSize(w->handle, &width, &height);
glfwGetWindowPos(w->handle, &x, &y);
#ifdef __APPLE__
if (cocoa_toggle_fullscreen(glfwGetCocoaWindow(w->handle))) {
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
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);
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);
#ifdef __APPLE__
if (glfwGetCocoaWindow) cocoa_make_window_resizable(glfwGetCocoaWindow(w->handle), OPT(macos_window_resizable));
#endif
return false;
}
#endif
}
#ifdef __APPLE__
static int
filter_option(int key UNUSED, int mods, unsigned int scancode UNUSED) {
return ((mods == GLFW_MOD_ALT) || (mods == (GLFW_MOD_ALT | GLFW_MOD_SHIFT))) ? 1 : 0;
}
static GLFWwindow *application_quit_canary = NULL;
static int
@ -370,6 +415,14 @@ on_application_reopen(int has_visible_windows) {
unjam_event_loop();
return false;
}
static int
intercept_cocoa_fullscreen(GLFWwindow *w) {
if (!set_callback_window(w)) return 0;
toggle_fullscreen_for_os_window(global_state.callback_os_window);
global_state.callback_os_window = NULL;
return 1;
}
#endif
void
@ -504,6 +557,7 @@ create_os_window(PyObject UNUSED *self, PyObject *args) {
glfwSwapInterval(OPT(sync_to_monitor) ? 1 : 0);
#ifdef __APPLE__
if (OPT(macos_option_as_alt)) glfwSetCocoaTextInputFilter(glfw_window, filter_option);
glfwSetCocoaToggleFullscreenIntercept(glfw_window, intercept_cocoa_fullscreen);
#endif
send_prerendered_sprites_for_window(w);
if (logo.pixels && logo.width && logo.height) glfwSetWindowIcon(glfw_window, 1, &logo);
@ -702,29 +756,10 @@ set_clipboard_string(PyObject UNUSED *self, PyObject *args) {
static PyObject*
toggle_fullscreen(PYNOARG) {
GLFWmonitor *monitor;
OSWindow *w = current_os_window();
if (!w || !w->handle) Py_RETURN_NONE;
if ((monitor = glfwGetWindowMonitor(w->handle)) == NULL) {
// make fullscreen
monitor = current_monitor(w->handle);
if (monitor == NULL) return NULL;
const GLFWvidmode* mode = glfwGetVideoMode(monitor);
w->before_fullscreen.is_set = true;
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);
Py_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);
#ifdef __APPLE__
if (glfwGetCocoaWindow) cocoa_make_window_resizable(glfwGetCocoaWindow(w->handle), OPT(macos_window_resizable));
#endif
Py_RETURN_FALSE;
}
if (!w) Py_RETURN_NONE;
if (toggle_fullscreen_for_os_window(w)) { Py_RETURN_TRUE; }
Py_RETURN_FALSE;
}
static PyObject*