mirror of
https://github.com/kovidgoyal/kitty.git
synced 2026-05-13 08:26:56 +00:00
Factor out Cocoa layer shell code into the proper function
This commit is contained in:
parent
e93338a81c
commit
c9bf7e4236
5 changed files with 76 additions and 77 deletions
6
glfw/cocoa_platform.h
vendored
6
glfw/cocoa_platform.h
vendored
|
|
@ -152,8 +152,10 @@ typedef struct _GLFWwindowNS
|
|||
UInt32 deadKeyState;
|
||||
|
||||
// Layer shell windows
|
||||
bool is_layer_shell;
|
||||
GLFWLayerShellConfig layer_shell_config;
|
||||
struct {
|
||||
bool is_active;
|
||||
GLFWLayerShellConfig config;
|
||||
} layer_shell;
|
||||
|
||||
// Whether a render frame has been requested for this window
|
||||
bool renderFrameRequested;
|
||||
|
|
|
|||
|
|
@ -1652,8 +1652,8 @@ void _glfwPlatformUpdateIMEState(_GLFWwindow *w, const GLFWIMEUpdateEvent *ev) {
|
|||
|
||||
- (BOOL)canBecomeKeyWindow
|
||||
{
|
||||
if (glfw_window && glfw_window->ns.is_layer_shell) {
|
||||
switch(glfw_window->ns.layer_shell_config.focus_policy) {
|
||||
if (glfw_window && glfw_window->ns.layer_shell.is_active) {
|
||||
switch(glfw_window->ns.layer_shell.config.focus_policy) {
|
||||
case GLFW_FOCUS_NOT_ALLOWED: return NO;
|
||||
case GLFW_FOCUS_EXCLUSIVE: return YES;
|
||||
case GLFW_FOCUS_ON_DEMAND: return YES;
|
||||
|
|
@ -1829,9 +1829,9 @@ static bool createNativeWindow(_GLFWwindow* window,
|
|||
int _glfwPlatformCreateWindow(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig, const GLFWLayerShellConfig *lsc) {
|
||||
window->ns.deadKeyState = 0;
|
||||
if (lsc) {
|
||||
window->ns.is_layer_shell = true;
|
||||
window->ns.layer_shell_config = *lsc;
|
||||
} else window->ns.is_layer_shell = false;
|
||||
window->ns.layer_shell.is_active = true;
|
||||
window->ns.layer_shell.config = *lsc;
|
||||
} else window->ns.layer_shell.is_active = false;
|
||||
if (!_glfw.ns.finishedLaunching)
|
||||
{
|
||||
[NSApp run];
|
||||
|
|
@ -1913,9 +1913,51 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window)
|
|||
window->ns.object = nil;
|
||||
}
|
||||
|
||||
bool _glfwPlatformSetLayerShellConfig(_GLFWwindow* window, const GLFWLayerShellConfig *value) {
|
||||
(void)window; (void)value;
|
||||
return false;
|
||||
static NSScreen*
|
||||
screen_for_window_center(_GLFWwindow *window) {
|
||||
NSRect windowFrame = [window->ns.object frame];
|
||||
NSPoint windowCenter = NSMakePoint(NSMidX(windowFrame), NSMidY(windowFrame));
|
||||
for (NSScreen *screen in [NSScreen screens]) {
|
||||
if (NSPointInRect(windowCenter, [screen frame])) {
|
||||
return screen;
|
||||
}
|
||||
}
|
||||
return NSScreen.mainScreen;
|
||||
}
|
||||
|
||||
bool
|
||||
_glfwPlatformSetLayerShellConfig(_GLFWwindow* window, const GLFWLayerShellConfig *value) {
|
||||
window->resizable = false;
|
||||
const bool is_transparent = ![window->ns.object isOpaque];
|
||||
int background_blur = value->related.background_blur;
|
||||
if (!is_transparent || value->related.background_opacity >= 1.f) { background_blur = 0; }
|
||||
[window->ns.object setBackgroundColor:nil];
|
||||
_glfwPlatformSetWindowBlur(window, background_blur);
|
||||
window->ns.titlebar_hidden = true;
|
||||
window->decorated = false;
|
||||
[window->ns.object setTitlebarAppearsTransparent:false];
|
||||
[window->ns.object setHasShadow:false];
|
||||
[window->ns.object setTitleVisibility:NSWindowTitleHidden];
|
||||
NSColorSpace *cs = nil;
|
||||
switch (value->related.color_space) {
|
||||
case SRGB_COLORSPACE: cs = [NSColorSpace sRGBColorSpace]; break;
|
||||
case DISPLAY_P3_COLORSPACE: cs = [NSColorSpace displayP3ColorSpace]; break;
|
||||
case DEFAULT_COLORSPACE: cs = nil; break; // using deviceRGBColorSpace causes a hang when transitioning to fullscreen
|
||||
}
|
||||
[window->ns.object setColorSpace:cs];
|
||||
[[window->ns.object standardWindowButton: NSWindowCloseButton] setHidden:true];
|
||||
[[window->ns.object standardWindowButton: NSWindowMiniaturizeButton] setHidden:true];
|
||||
[[window->ns.object standardWindowButton: NSWindowZoomButton] setHidden:true];
|
||||
[window->ns.object setStyleMask:NSWindowStyleMaskBorderless];
|
||||
// HACK: Changing the style mask can cause the first responder to be cleared
|
||||
[window->ns.object makeFirstResponder:window->ns.view];
|
||||
uint32_t width = 0, height = 0;
|
||||
NSScreen *screen = screen_for_window_center(window);
|
||||
CGFloat monitor_width = NSWidth(screen.frame), monitor_height = NSHeight(screen.frame);
|
||||
window->ns.layer_shell.config.size_callback((GLFWwindow*)window, &window->ns.layer_shell.config, (unsigned)monitor_width, (unsigned)monitor_height, &width, &height);
|
||||
CGFloat x = NSMinX(screen.visibleFrame), y = NSMinY(screen.visibleFrame);
|
||||
[window->ns.object setFrame:NSMakeRect(x, y, (CGFloat)width, (CGFloat)height) display:YES];
|
||||
return true;
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title)
|
||||
|
|
@ -1966,7 +2008,7 @@ void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height)
|
|||
|
||||
void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
|
||||
{
|
||||
if (window->ns.is_layer_shell) return;
|
||||
if (window->ns.layer_shell.is_active) return;
|
||||
if (window->monitor)
|
||||
{
|
||||
if (window->monitor->window == window)
|
||||
|
|
@ -3003,67 +3045,9 @@ GLFWAPI GLFWcocoarenderframefun glfwCocoaSetWindowResizeCallback(GLFWwindow *w,
|
|||
return current;
|
||||
}
|
||||
|
||||
static NSScreen*
|
||||
screen_for_window_center(_GLFWwindow *window) {
|
||||
NSRect windowFrame = [window->ns.object frame];
|
||||
NSPoint windowCenter = NSMakePoint(NSMidX(windowFrame), NSMidY(windowFrame));
|
||||
for (NSScreen *screen in [NSScreen screens]) {
|
||||
if (NSPointInRect(windowCenter, [screen frame])) {
|
||||
return screen;
|
||||
}
|
||||
}
|
||||
return NSScreen.mainScreen;
|
||||
}
|
||||
|
||||
static void
|
||||
apply_layer_shell_properties(_GLFWwindow *window, int background_blur, unsigned system_color, int color_space) {
|
||||
window->resizable = false;
|
||||
const bool is_transparent = ![window->ns.object isOpaque];
|
||||
if (!is_transparent) { background_blur = 0; }
|
||||
NSAppearance *appearance = nil;
|
||||
NSAppearance *light_appearance = is_transparent ? [NSAppearance appearanceNamed:NSAppearanceNameVibrantLight] : [NSAppearance appearanceNamed:NSAppearanceNameAqua];
|
||||
NSAppearance *dark_appearance = is_transparent ? [NSAppearance appearanceNamed:NSAppearanceNameVibrantDark] : [NSAppearance appearanceNamed:NSAppearanceNameDarkAqua];
|
||||
NSColor *background = nil;
|
||||
switch (system_color) {
|
||||
case 1:
|
||||
appearance = light_appearance; break;
|
||||
case 2:
|
||||
appearance = dark_appearance; break;
|
||||
}
|
||||
[window->ns.object setBackgroundColor:background];
|
||||
[window->ns.object setAppearance:appearance];
|
||||
_glfwPlatformSetWindowBlur(window, background_blur);
|
||||
window->ns.titlebar_hidden = true;
|
||||
window->decorated = false;
|
||||
[window->ns.object setTitlebarAppearsTransparent:false];
|
||||
[window->ns.object setHasShadow:false];
|
||||
[window->ns.object setTitleVisibility:NSWindowTitleHidden];
|
||||
NSColorSpace *cs = nil;
|
||||
switch (color_space) {
|
||||
case SRGB_COLORSPACE: cs = [NSColorSpace sRGBColorSpace]; break;
|
||||
case DISPLAY_P3_COLORSPACE: cs = [NSColorSpace displayP3ColorSpace]; break;
|
||||
case DEFAULT_COLORSPACE: cs = nil; break; // using deviceRGBColorSpace causes a hang when transitioning to fullscreen
|
||||
}
|
||||
[window->ns.object setColorSpace:cs];
|
||||
[[window->ns.object standardWindowButton: NSWindowCloseButton] setHidden:true];
|
||||
[[window->ns.object standardWindowButton: NSWindowMiniaturizeButton] setHidden:true];
|
||||
[[window->ns.object standardWindowButton: NSWindowZoomButton] setHidden:true];
|
||||
[window->ns.object setStyleMask:NSWindowStyleMaskBorderless];
|
||||
// HACK: Changing the style mask can cause the first responder to be cleared
|
||||
[window->ns.object makeFirstResponder:window->ns.view];
|
||||
uint32_t width = 0, height = 0;
|
||||
NSScreen *screen = screen_for_window_center(window);
|
||||
NSRect frame = screen.frame;
|
||||
CGFloat monitor_width = NSWidth(frame), monitor_height = NSHeight(frame);
|
||||
window->ns.layer_shell_config.size_callback((GLFWwindow*)window, &window->ns.layer_shell_config, (unsigned)monitor_width, (unsigned)monitor_height, &width, &height);
|
||||
NSRect window_frame = [window->ns.object frame];
|
||||
CGFloat x = 0, y = NSMinY(window_frame);
|
||||
[window->ns.object setFrame:NSMakeRect(x, y, (CGFloat)width, (CGFloat)height) display:YES];
|
||||
}
|
||||
|
||||
GLFWAPI void glfwCocoaSetWindowChrome(GLFWwindow *w, unsigned int color, bool use_system_color, unsigned int system_color, int background_blur, unsigned int hide_window_decorations, bool show_text_in_titlebar, int color_space, float background_opacity, bool resizable) { @autoreleasepool {
|
||||
_GLFWwindow* window = (_GLFWwindow*)w;
|
||||
if (window->ns.is_layer_shell) { apply_layer_shell_properties(window, background_blur, system_color, color_space); return; }
|
||||
if (window->ns.layer_shell.is_active) return;
|
||||
const bool is_transparent = ![window->ns.object isOpaque];
|
||||
if (!is_transparent) { background_opacity = 1.0; background_blur = 0; }
|
||||
NSColor *background = nil;
|
||||
|
|
|
|||
3
glfw/glfw3.h
vendored
3
glfw/glfw3.h
vendored
|
|
@ -1321,6 +1321,9 @@ typedef struct GLFWLayerShellConfig {
|
|||
unsigned override_exclusive_zone;
|
||||
void (*size_callback)(GLFWwindow *window, const struct GLFWLayerShellConfig *config, unsigned monitor_width, unsigned monitor_height, uint32_t *width, uint32_t *height);
|
||||
struct { double xdpi, ydpi, xscale, yscale; } expected;
|
||||
struct {
|
||||
float background_opacity; int background_blur, color_space;
|
||||
} related;
|
||||
} GLFWLayerShellConfig;
|
||||
|
||||
typedef struct GLFWDBUSNotificationData {
|
||||
|
|
|
|||
3
kitty/glfw-wrapper.h
generated
3
kitty/glfw-wrapper.h
generated
|
|
@ -1059,6 +1059,9 @@ typedef struct GLFWLayerShellConfig {
|
|||
unsigned override_exclusive_zone;
|
||||
void (*size_callback)(GLFWwindow *window, const struct GLFWLayerShellConfig *config, unsigned monitor_width, unsigned monitor_height, uint32_t *width, uint32_t *height);
|
||||
struct { double xdpi, ydpi, xscale, yscale; } expected;
|
||||
struct {
|
||||
float background_opacity; int background_blur, color_space;
|
||||
} related;
|
||||
} GLFWLayerShellConfig;
|
||||
|
||||
typedef struct GLFWDBUSNotificationData {
|
||||
|
|
|
|||
21
kitty/glfw.c
21
kitty/glfw.c
|
|
@ -1067,7 +1067,7 @@ apply_window_chrome_state(GLFWwindow *w, WindowChromeState new_state, int width,
|
|||
|
||||
void
|
||||
set_os_window_chrome(OSWindow *w) {
|
||||
if (!w->handle) return;
|
||||
if (!w->handle || w->is_layer_shell) return;
|
||||
color_type bg = OPT(background);
|
||||
if (w->num_tabs > w->active_tab) {
|
||||
Tab *tab = w->tabs + w->active_tab;
|
||||
|
|
@ -1229,6 +1229,14 @@ layer_shell_config_from_python(PyObject *p, GLFWLayerShellConfig *ans) {
|
|||
#undef A
|
||||
}
|
||||
|
||||
static bool
|
||||
set_layer_shell_config_for(OSWindow *w, GLFWLayerShellConfig *lsc) {
|
||||
lsc->related.background_opacity = w->background_opacity;
|
||||
lsc->related.background_blur = OPT(background_blur);
|
||||
lsc->related.color_space = OPT(macos_colorspace);
|
||||
return glfwSetLayerShellConfig(w->handle, lsc);
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
create_os_window(PyObject UNUSED *self, PyObject *args, PyObject *kw) {
|
||||
int x = INT_MIN, y = INT_MIN, window_state = WINDOW_NORMAL, disallow_override_title = 0;
|
||||
|
|
@ -1446,11 +1454,10 @@ create_os_window(PyObject UNUSED *self, PyObject *args, PyObject *kw) {
|
|||
}
|
||||
}
|
||||
init_window_chrome_state(&w->last_window_chrome, OPT(background), w->is_semi_transparent, w->background_opacity);
|
||||
#ifdef __APPLE__
|
||||
apply_window_chrome_state(w->handle, w->last_window_chrome, width, height, OPT(hide_window_decorations) != 0);
|
||||
#else
|
||||
apply_window_chrome_state(w->handle, w->last_window_chrome, width, height, false);
|
||||
#endif
|
||||
if (w->is_layer_shell) {
|
||||
if (global_state.is_apple) set_layer_shell_config_for(w, lsc);
|
||||
} else apply_window_chrome_state(
|
||||
w->handle, w->last_window_chrome, width, height, global_state.is_apple ? OPT(hide_window_decorations) != 0 : false);
|
||||
// Update window state
|
||||
// We do not call glfwWindowHint to set GLFW_MAXIMIZED before the window is created.
|
||||
// That would cause the window to be set to maximize immediately after creation and use the wrong initial size when restored.
|
||||
|
|
@ -2514,7 +2521,7 @@ set_layer_shell_config(PyObject *self UNUSED, PyObject *args) {
|
|||
if (!window || !window->handle || !window->is_layer_shell) Py_RETURN_FALSE;
|
||||
GLFWLayerShellConfig lsc = {0};
|
||||
if (!layer_shell_config_from_python(pylsc, &lsc)) return NULL;
|
||||
return Py_NewRef(glfwSetLayerShellConfig(window->handle, &lsc) ? Py_True : Py_False);
|
||||
return Py_NewRef(set_layer_shell_config_for(window, &lsc) ? Py_True : Py_False);
|
||||
}
|
||||
|
||||
// Boilerplate {{{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue