wip: MacOS-specific config settings

This commit is contained in:
Aleksei Gmitron 2026-06-21 22:31:03 +04:00
parent 511cb7b0b9
commit 8c32f093bb
16 changed files with 171 additions and 37 deletions

View file

@ -2577,6 +2577,71 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window)
window->ns.object = nil;
}
static bool
ns_window_level_constant(const char *name, long *val) {
#define C(x) if (strcmp(name, #x) == 0) { *val = (long)x; return true; }
C(NSNormalWindowLevel); C(NSFloatingWindowLevel); C(NSSubmenuWindowLevel); C(NSTornOffMenuWindowLevel);
C(NSMainMenuWindowLevel); C(NSStatusWindowLevel); C(NSModalPanelWindowLevel); C(NSPopUpMenuWindowLevel);
C(NSScreenSaverWindowLevel);
C(kCGBaseWindowLevel); C(kCGMinimumWindowLevel); C(kCGDesktopWindowLevel); C(kCGBackstopMenuLevel);
C(kCGNormalWindowLevel); C(kCGFloatingWindowLevel); C(kCGTornOffMenuWindowLevel); C(kCGDockWindowLevel);
C(kCGMainMenuWindowLevel); C(kCGStatusWindowLevel); C(kCGModalPanelWindowLevel); C(kCGPopUpMenuWindowLevel);
C(kCGDraggingWindowLevel); C(kCGScreenSaverWindowLevel); C(kCGMaximumWindowLevel); C(kCGOverlayWindowLevel);
C(kCGHelpWindowLevel); C(kCGUtilityWindowLevel); C(kCGDesktopIconWindowLevel); C(kCGAssistiveTechHighWindowLevel);
C(kCGCursorWindowLevel); C(kCGNumberOfWindowLevelKeys);
#undef C
return false;
}
static bool
parse_ns_window_level_term(const char **spec, long *val) {
const char *s = *spec;
while (isspace(*s)) s++;
if (!*s) return false;
if (*s == '+' || *s == '-' || isdigit(*s)) {
errno = 0;
char *end = NULL;
long v = strtol(s, &end, 0);
if (end == s || errno) return false;
*val = v; *spec = end;
return true;
}
char name[96]; size_t i = 0;
while ((isalnum(*s) || *s == '_') && i + 1 < sizeof(name)) name[i++] = *s++;
name[i] = '\0';
if (!i || !ns_window_level_constant(name, val)) return false;
*spec = s;
return true;
}
static bool
parse_ns_window_level(const char *spec, NSWindowLevel *level) {
const char *original = spec;
if (!spec) return false;
while (isspace(*spec)) spec++;
if (!*spec || strcmp(spec, "unset") == 0) return false;
long total = 0;
if (!parse_ns_window_level_term(&spec, &total)) goto invalid;
while (true) {
while (isspace(*spec)) spec++;
if (!*spec) { *level = (NSWindowLevel)total; return true; }
char op = *spec++;
if (op != '+' && op != '-') goto invalid;
long term = 0;
if (!parse_ns_window_level_term(&spec, &term)) goto invalid;
total = op == '+' ? total + term : total - term;
}
invalid:
_glfwInputError(GLFW_INVALID_VALUE, "Cocoa: Invalid macOS NSWindow layer expression: %s", original);
return false;
}
static void
apply_ns_window_layer(_GLFWwindow *window, const char *spec) {
NSWindowLevel level = 0;
if (parse_ns_window_level(spec, &level)) [window->ns.object setLevel:level];
}
static NSScreen*
screen_for_window_center(_GLFWwindow *window) {
NSRect windowFrame = [window->ns.object frame];
@ -2681,9 +2746,9 @@ _glfwPlatformSetLayerShellConfig(_GLFWwindow* window, const GLFWLayerShellConfig
double spacing_y = top_edge_spacing + bottom_edge_spacing;
const unsigned xsz = config.x_size_in_pixels ? (unsigned)(config.x_size_in_pixels * xscale) : (cell_width * config.x_size_in_cells);
const unsigned ysz = config.y_size_in_pixels ? (unsigned)(config.y_size_in_pixels * yscale) : (cell_height * config.y_size_in_cells);
NSRect placement_frame = config.use_physical_screen_frame ? screen.frame : screen.visibleFrame;
NSRect placement_frame = config.related.use_physical_screen_frame ? screen.frame : screen.visibleFrame;
CGFloat dock_height = NSMinY(screen.visibleFrame) - NSMinY(screen.frame);
CGFloat menubar_height = config.use_physical_screen_frame ? 0 : NSHeight(screen.frame) - NSHeight(screen.visibleFrame) - dock_height;
CGFloat menubar_height = config.related.use_physical_screen_frame ? 0 : NSHeight(screen.frame) - NSHeight(screen.visibleFrame) - dock_height;
CGFloat x = NSMinX(placement_frame), y = NSMinY(placement_frame) - 1, width = NSWidth(placement_frame), height = NSHeight(placement_frame) + 2;
if (config.type == GLFW_LAYER_SHELL_BACKGROUND || config.edge == GLFW_EDGE_CENTER) {
x = NSMinX(screen.frame); height = NSHeight(screen.frame) - menubar_height + 1; y = NSMinY(screen.frame); width = NSWidth(screen.frame);
@ -2698,7 +2763,6 @@ _glfwPlatformSetLayerShellConfig(_GLFWwindow* window, const GLFWLayerShellConfig
// See: https://stackoverflow.com/questions/4982584/how-do-i-draw-the-desktop-on-mac-os-x/4982619#4982619
level = kCGDesktopWindowLevel;
break;
case GLFW_LAYER_SHELL_DESKTOP_SHELL: level = kCGBackstopMenuLevel; break;
case GLFW_LAYER_SHELL_OVERLAY: case GLFW_LAYER_SHELL_NONE: break;
case GLFW_LAYER_SHELL_PANEL: level = NSNormalWindowLevel - 1; break;
case GLFW_LAYER_SHELL_TOP: level--; break;
@ -2737,6 +2801,7 @@ _glfwPlatformSetLayerShellConfig(_GLFWwindow* window, const GLFWLayerShellConfig
[nswindow setAnimationBehavior:animation_behavior];
[nswindow setLevel:level];
apply_ns_window_layer(window, config.related.ns_window_layer);
[nswindow setCollectionBehavior: (NSWindowCollectionBehaviorCanJoinAllSpaces | NSWindowCollectionBehaviorStationary | NSWindowCollectionBehaviorIgnoresCycle)];
[nswindow setFrame:NSMakeRect(x, y, width, height) display:YES];
return true;
@ -4036,6 +4101,12 @@ apply_window_corner_curve(_GLFWwindow *window) {
GLFWAPI void glfwCocoaSetWindowLevel(GLFWwindow *w, const char *level_spec) { @autoreleasepool {
_GLFWwindow* window = (_GLFWwindow*)w;
apply_ns_window_layer(window, level_spec);
}}
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.layer_shell.is_active) return;

7
glfw/glfw3.h vendored
View file

@ -1349,7 +1349,7 @@ typedef struct GLFWkeyevent
bool fake_event_on_focus_change;
} GLFWkeyevent;
typedef enum { GLFW_LAYER_SHELL_NONE, GLFW_LAYER_SHELL_BACKGROUND, GLFW_LAYER_SHELL_PANEL, GLFW_LAYER_SHELL_TOP, GLFW_LAYER_SHELL_DESKTOP_SHELL, GLFW_LAYER_SHELL_OVERLAY } GLFWLayerShellType;
typedef enum { GLFW_LAYER_SHELL_NONE, GLFW_LAYER_SHELL_BACKGROUND, GLFW_LAYER_SHELL_PANEL, GLFW_LAYER_SHELL_TOP, GLFW_LAYER_SHELL_OVERLAY } GLFWLayerShellType;
typedef enum { GLFW_EDGE_TOP, GLFW_EDGE_BOTTOM, GLFW_EDGE_LEFT, GLFW_EDGE_RIGHT, GLFW_EDGE_CENTER, GLFW_EDGE_NONE, GLFW_EDGE_CENTER_SIZED } GLFWEdge;
@ -1368,12 +1368,13 @@ typedef struct GLFWLayerShellConfig {
unsigned x_size_in_cells, x_size_in_pixels;
unsigned y_size_in_cells, y_size_in_pixels;
int requested_top_margin, requested_left_margin, requested_bottom_margin, requested_right_margin;
int requested_exclusive_zone, hide_on_focus_loss, use_physical_screen_frame;
int requested_exclusive_zone, hide_on_focus_loss;
unsigned override_exclusive_zone;
void (*size_callback)(GLFWwindow *window, float xscale, float yscale, unsigned *cell_width, unsigned *cell_height, double *left_edge_spacing, double *top_edge_spacing, double *right_edge_spacing, double *bottom_edge_spacing);
struct { float xscale, yscale; } expected;
struct {
float background_opacity; int background_blur, color_space;
float background_opacity; int background_blur, color_space, use_physical_screen_frame;
char ns_window_layer[128];
} related;
} GLFWLayerShellConfig;

3
glfw/wl_window.c vendored
View file

@ -1020,7 +1020,7 @@ get_layer_shell_layer(const _GLFWwindow *window) {
case GLFW_LAYER_SHELL_BACKGROUND: case GLFW_LAYER_SHELL_NONE: break;
case GLFW_LAYER_SHELL_PANEL: which_layer = ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM; break;
case GLFW_LAYER_SHELL_TOP: which_layer = ZWLR_LAYER_SHELL_V1_LAYER_TOP; break;
case GLFW_LAYER_SHELL_DESKTOP_SHELL: case GLFW_LAYER_SHELL_OVERLAY: which_layer = ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY; break;
case GLFW_LAYER_SHELL_OVERLAY: which_layer = ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY; break;
}
return which_layer;
}
@ -1043,7 +1043,6 @@ layer_set_properties(const _GLFWwindow *window, bool during_creation, uint32_t w
case GLFW_LAYER_SHELL_NONE: break;
case GLFW_LAYER_SHELL_BACKGROUND: exclusive_zone = -1; break;
case GLFW_LAYER_SHELL_TOP:
case GLFW_LAYER_SHELL_DESKTOP_SHELL:
case GLFW_LAYER_SHELL_OVERLAY:
case GLFW_LAYER_SHELL_PANEL:
switch (config.edge) {

4
glfw/x11_window.c vendored
View file

@ -644,7 +644,7 @@ calculate_layer_geometry(_GLFWwindow *window) {
double xsz = config.x_size_in_pixels ? (unsigned)(config.x_size_in_pixels * xscale) : (cell_width * config.x_size_in_cells);
double ysz = config.y_size_in_pixels ? (unsigned)(config.y_size_in_pixels * yscale) : (cell_height * config.y_size_in_cells);
ans.width = (int)(1. + spacing_x + xsz); ans.height = (int)(1. + spacing_y + ysz);
GeometryRect m = config.type == GLFW_LAYER_SHELL_TOP || config.type == GLFW_LAYER_SHELL_DESKTOP_SHELL || config.type == GLFW_LAYER_SHELL_OVERLAY ? mg.workarea : mg.full;
GeometryRect m = config.type == GLFW_LAYER_SHELL_TOP || config.type == GLFW_LAYER_SHELL_OVERLAY ? mg.workarea : mg.full;
static const struct {
unsigned left, right, top, bottom, left_start_y, left_end_y, right_start_y, right_end_y, top_start_x, top_end_x, bottom_start_x, bottom_end_x;
} s = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
@ -762,7 +762,7 @@ update_wm_hints(_GLFWwindow *window, const WindowGeometry *wg, const _GLFWwndcon
// i3 does not support NET_WM_STATE_BELOW but panels work without it
if (_glfw.x11.NET_WM_STATE_BELOW) { S(NET_WM_STATE_BELOW); }
break;
case GLFW_LAYER_SHELL_TOP: case GLFW_LAYER_SHELL_DESKTOP_SHELL: case GLFW_LAYER_SHELL_OVERLAY: S(NET_WM_STATE_ABOVE); break;
case GLFW_LAYER_SHELL_TOP: case GLFW_LAYER_SHELL_OVERLAY: S(NET_WM_STATE_ABOVE); break;
}
#undef S
} else if (wndconfig) {

View file

@ -26,7 +26,6 @@ from kitty.fast_data_types import (
GLFW_LAYER_SHELL_BACKGROUND,
GLFW_LAYER_SHELL_OVERLAY,
GLFW_LAYER_SHELL_PANEL,
GLFW_LAYER_SHELL_DESKTOP_SHELL,
GLFW_LAYER_SHELL_TOP,
layer_shell_config_for_os_window,
set_layer_shell_config,
@ -70,7 +69,6 @@ def layer_shell_config(opts: PanelCLIOptions) -> LayerShellConfig:
'background': GLFW_LAYER_SHELL_BACKGROUND,
'bottom': GLFW_LAYER_SHELL_PANEL,
'top': GLFW_LAYER_SHELL_TOP,
'shell': GLFW_LAYER_SHELL_DESKTOP_SHELL,
'overlay': GLFW_LAYER_SHELL_OVERLAY
}.get(opts.layer, GLFW_LAYER_SHELL_PANEL)
ltype = GLFW_LAYER_SHELL_BACKGROUND if opts.edge == 'background' else ltype
@ -96,7 +94,6 @@ def layer_shell_config(opts: PanelCLIOptions) -> LayerShellConfig:
requested_exclusive_zone=opts.exclusive_zone,
override_exclusive_zone=opts.override_exclusive_zone,
hide_on_focus_loss=opts.hide_on_focus_loss,
use_physical_screen_frame=opts.use_physical_screen_frame,
output_name=opts.output_name or '')
@ -115,8 +112,7 @@ def cli_option_to_lsc_configs_map() -> MappingProxyType[str, tuple[str, ...]]:
'focus_policy': ('focus_policy',),
'exclusive_zone': ('requested_exclusive_zone',),
'override_exclusive_zone': ('override_exclusive_zone',),
'hide_on_focus_loss': ('hide_on_focus_loss',),
'use_physical_screen_frame': ('use_physical_screen_frame',)
'hide_on_focus_loss': ('hide_on_focus_loss',)
})

3
kitty/glfw-wrapper.c generated
View file

@ -497,6 +497,9 @@ load_glfw(const char* path) {
*(void **) (&glfwCocoaCycleThroughOSWindows_impl) = dlsym(handle, "glfwCocoaCycleThroughOSWindows");
if (glfwCocoaCycleThroughOSWindows_impl == NULL) dlerror(); // clear error indicator
*(void **) (&glfwCocoaSetWindowLevel_impl) = dlsym(handle, "glfwCocoaSetWindowLevel");
if (glfwCocoaSetWindowLevel_impl == NULL) dlerror(); // clear error indicator
*(void **) (&glfwCocoaSetWindowChrome_impl) = dlsym(handle, "glfwCocoaSetWindowChrome");
if (glfwCocoaSetWindowChrome_impl == NULL) dlerror(); // clear error indicator

11
kitty/glfw-wrapper.h generated
View file

@ -1077,7 +1077,7 @@ typedef struct GLFWkeyevent
bool fake_event_on_focus_change;
} GLFWkeyevent;
typedef enum { GLFW_LAYER_SHELL_NONE, GLFW_LAYER_SHELL_BACKGROUND, GLFW_LAYER_SHELL_PANEL, GLFW_LAYER_SHELL_TOP, GLFW_LAYER_SHELL_DESKTOP_SHELL, GLFW_LAYER_SHELL_OVERLAY } GLFWLayerShellType;
typedef enum { GLFW_LAYER_SHELL_NONE, GLFW_LAYER_SHELL_BACKGROUND, GLFW_LAYER_SHELL_PANEL, GLFW_LAYER_SHELL_TOP, GLFW_LAYER_SHELL_OVERLAY } GLFWLayerShellType;
typedef enum { GLFW_EDGE_TOP, GLFW_EDGE_BOTTOM, GLFW_EDGE_LEFT, GLFW_EDGE_RIGHT, GLFW_EDGE_CENTER, GLFW_EDGE_NONE, GLFW_EDGE_CENTER_SIZED } GLFWEdge;
@ -1096,12 +1096,13 @@ typedef struct GLFWLayerShellConfig {
unsigned x_size_in_cells, x_size_in_pixels;
unsigned y_size_in_cells, y_size_in_pixels;
int requested_top_margin, requested_left_margin, requested_bottom_margin, requested_right_margin;
int requested_exclusive_zone, hide_on_focus_loss, use_physical_screen_frame;
int requested_exclusive_zone, hide_on_focus_loss;
unsigned override_exclusive_zone;
void (*size_callback)(GLFWwindow *window, float xscale, float yscale, unsigned *cell_width, unsigned *cell_height, double *left_edge_spacing, double *top_edge_spacing, double *right_edge_spacing, double *bottom_edge_spacing);
struct { float xscale, yscale; } expected;
struct {
float background_opacity; int background_blur, color_space;
float background_opacity; int background_blur, color_space, use_physical_screen_frame;
char ns_window_layer[128];
} related;
} GLFWLayerShellConfig;
@ -2478,6 +2479,10 @@ typedef void (*glfwCocoaCycleThroughOSWindows_func)(bool);
GFW_EXTERN glfwCocoaCycleThroughOSWindows_func glfwCocoaCycleThroughOSWindows_impl;
#define glfwCocoaCycleThroughOSWindows glfwCocoaCycleThroughOSWindows_impl
typedef void (*glfwCocoaSetWindowLevel_func)(GLFWwindow*, const char*);
GFW_EXTERN glfwCocoaSetWindowLevel_func glfwCocoaSetWindowLevel_impl;
#define glfwCocoaSetWindowLevel glfwCocoaSetWindowLevel_impl
typedef void (*glfwCocoaSetWindowChrome_func)(GLFWwindow*, unsigned int, bool, unsigned int, int, unsigned int, bool, int, float, bool);
GFW_EXTERN glfwCocoaSetWindowChrome_func glfwCocoaSetWindowChrome_impl;
#define glfwCocoaSetWindowChrome glfwCocoaSetWindowChrome_impl

View file

@ -182,6 +182,9 @@ set_layer_shell_config_for(OSWindow *w, GLFWLayerShellConfig *lsc) {
lsc->related.background_opacity = effective_os_window_alpha(w);
lsc->related.background_blur = OPT(background_blur);
lsc->related.color_space = OPT(macos_colorspace);
lsc->related.use_physical_screen_frame = OPT(macos_use_physical_screen_frame);
if (OPT(macos_ns_window_layer)) snprintf(lsc->related.ns_window_layer, sizeof(lsc->related.ns_window_layer), "%s", OPT(macos_ns_window_layer));
else lsc->related.ns_window_layer[0] = '\0';
w->hide_on_focus_loss = lsc->hide_on_focus_loss;
}
return glfwSetLayerShellConfig(w->handle, lsc);
@ -1372,7 +1375,7 @@ toggle_fullscreen_for_os_window(OSWindow *w) {
if (!prev) return false;
GLFWLayerShellConfig lsc;
memcpy(&lsc, prev, sizeof(lsc));
if (prev->type == GLFW_LAYER_SHELL_OVERLAY || prev->type == GLFW_LAYER_SHELL_DESKTOP_SHELL || prev->type == GLFW_LAYER_SHELL_TOP) {
if (prev->type == GLFW_LAYER_SHELL_OVERLAY || prev->type == GLFW_LAYER_SHELL_TOP) {
if (prev->was_toggled_to_fullscreen) {
lsc.edge = prev->previous.edge;
lsc.requested_bottom_margin = prev->previous.requested_bottom_margin;
@ -1642,7 +1645,6 @@ layer_shell_config_to_python(const GLFWLayerShellConfig *c) {
A(requested_right_margin, fl);
A(requested_exclusive_zone, fl);
A(hide_on_focus_loss, b)
A(use_physical_screen_frame, b)
A(override_exclusive_zone, b);
#undef A
#undef fl
@ -1670,7 +1672,6 @@ layer_shell_config_from_python(PyObject *p, GLFWLayerShellConfig *ans) {
A(requested_exclusive_zone, PyLong_Check, PyLong_AsLong);
A(override_exclusive_zone, PyBool_Check, PyLong_AsLong);
A(hide_on_focus_loss, PyBool_Check, PyLong_AsLong);
A(use_physical_screen_frame, PyBool_Check, PyLong_AsLong);
#undef A
#define A(attr) { \
RAII_PyObject(attr, PyObject_GetAttrString(p, #attr)); if (attr == NULL) return false; \
@ -1924,6 +1925,9 @@ create_os_window(PyObject UNUSED *self, PyObject *args, PyObject *kw) {
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);
#ifdef __APPLE__
if (!w->is_layer_shell) glfwCocoaSetWindowLevel(w->handle, OPT(macos_ns_window_layer));
#endif
// 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.
@ -3262,7 +3266,7 @@ init_glfw(PyObject *m) {
ADDC(GLFW_REPEAT);
ADDC(true); ADDC(false);
ADDC(GLFW_PRIMARY_SELECTION); ADDC(GLFW_CLIPBOARD);
ADDC(GLFW_LAYER_SHELL_NONE); ADDC(GLFW_LAYER_SHELL_PANEL); ADDC(GLFW_LAYER_SHELL_BACKGROUND); ADDC(GLFW_LAYER_SHELL_TOP); ADDC(GLFW_LAYER_SHELL_DESKTOP_SHELL); ADDC(GLFW_LAYER_SHELL_OVERLAY);
ADDC(GLFW_LAYER_SHELL_NONE); ADDC(GLFW_LAYER_SHELL_PANEL); ADDC(GLFW_LAYER_SHELL_BACKGROUND); ADDC(GLFW_LAYER_SHELL_TOP); ADDC(GLFW_LAYER_SHELL_OVERLAY);
ADDC(GLFW_FOCUS_NOT_ALLOWED); ADDC(GLFW_FOCUS_EXCLUSIVE); ADDC(GLFW_FOCUS_ON_DEMAND);
ADDC(GLFW_EDGE_TOP); ADDC(GLFW_EDGE_BOTTOM); ADDC(GLFW_EDGE_LEFT); ADDC(GLFW_EDGE_RIGHT); ADDC(GLFW_EDGE_CENTER); ADDC(GLFW_EDGE_NONE);
ADDC(GLFW_EDGE_CENTER_SIZED);

View file

@ -2724,6 +2724,27 @@ full display frame instead of leaving space for the notch area.
'''
)
opt('macos_use_physical_screen_frame', 'no',
option_type='to_bool', ctype='bool',
long_text='''
Use the physical screen frame instead of the visible frame when placing macOS
desktop panels such as those created by :code:`kitty +kitten panel`. This allows
panels to draw in areas normally reserved for the native menu bar or Dock.
'''
)
opt('macos_ns_window_layer', 'unset',
option_type='str', ctype='!macos_ns_window_layer',
long_text='''
Set the macOS NSWindow level for newly created OS windows. The default value
:code:`unset` leaves kitty's normal window-level handling unchanged. Values can
be integer window levels, AppKit/CoreGraphics window-level constant names, or
simple arithmetic expressions combining them with integers. For example:
:code:`NSFloatingWindowLevel`, :code:`kCGBackstopMenuLevel`,
:code:`NSPopUpMenuWindowLevel - 1`.
'''
)
opt('macos_show_window_title_in', 'all',
choices=('all', 'menubar', 'none', 'window'), ctype='window_title_in',
long_text='''

View file

@ -1112,6 +1112,9 @@ class Parser:
def macos_menubar_title_max_length(self, val: str, ans: dict[str, typing.Any]) -> None:
ans['macos_menubar_title_max_length'] = positive_int(val)
def macos_ns_window_layer(self, val: str, ans: dict[str, typing.Any]) -> None:
ans['macos_ns_window_layer'] = str(val)
def macos_option_as_alt(self, val: str, ans: dict[str, typing.Any]) -> None:
ans['macos_option_as_alt'] = macos_option_as_alt(val)
@ -1135,6 +1138,9 @@ class Parser:
def macos_traditional_fullscreen(self, val: str, ans: dict[str, typing.Any]) -> None:
ans['macos_traditional_fullscreen'] = to_bool(val)
def macos_use_physical_screen_frame(self, val: str, ans: dict[str, typing.Any]) -> None:
ans['macos_use_physical_screen_frame'] = to_bool(val)
def macos_window_resizable(self, val: str, ans: dict[str, typing.Any]) -> None:
ans['macos_window_resizable'] = to_bool(val)

View file

@ -1435,6 +1435,32 @@ convert_from_opts_macos_fullscreen_ignore_safe_area_insets(PyObject *py_opts, Op
Py_DECREF(ret);
}
static void
convert_from_python_macos_use_physical_screen_frame(PyObject *val, Options *opts) {
opts->macos_use_physical_screen_frame = PyObject_IsTrue(val);
}
static void
convert_from_opts_macos_use_physical_screen_frame(PyObject *py_opts, Options *opts) {
PyObject *ret = PyObject_GetAttrString(py_opts, "macos_use_physical_screen_frame");
if (ret == NULL) return;
convert_from_python_macos_use_physical_screen_frame(ret, opts);
Py_DECREF(ret);
}
static void
convert_from_python_macos_ns_window_layer(PyObject *val, Options *opts) {
macos_ns_window_layer(val, opts);
}
static void
convert_from_opts_macos_ns_window_layer(PyObject *py_opts, Options *opts) {
PyObject *ret = PyObject_GetAttrString(py_opts, "macos_ns_window_layer");
if (ret == NULL) return;
convert_from_python_macos_ns_window_layer(ret, opts);
Py_DECREF(ret);
}
static void
convert_from_python_macos_show_window_title_in(PyObject *val, Options *opts) {
opts->macos_show_window_title_in = window_title_in(val);
@ -1709,6 +1735,10 @@ convert_opts_from_python_opts(PyObject *py_opts, Options *opts) {
if (PyErr_Occurred()) return false;
convert_from_opts_macos_fullscreen_ignore_safe_area_insets(py_opts, opts);
if (PyErr_Occurred()) return false;
convert_from_opts_macos_use_physical_screen_frame(py_opts, opts);
if (PyErr_Occurred()) return false;
convert_from_opts_macos_ns_window_layer(py_opts, opts);
if (PyErr_Occurred()) return false;
convert_from_opts_macos_show_window_title_in(py_opts, opts);
if (PyErr_Occurred()) return false;
convert_from_opts_macos_menubar_title_max_length(py_opts, opts);

View file

@ -206,6 +206,9 @@ bell_path(PyObject *src, Options *opts) { STR_SETTER(bell_path); }
static inline void
bell_theme(PyObject *src, Options *opts) { STR_SETTER(bell_theme); }
static inline void
macos_ns_window_layer(PyObject *src, Options *opts) { STR_SETTER(macos_ns_window_layer); }
static inline void
window_logo_path(PyObject *src, Options *opts) { STR_SETTER(default_window_logo); }
@ -604,6 +607,6 @@ free_allocs_in_options(Options *opts) {
free_background_images(opts);
#define F(x) free(opts->x); opts->x = NULL;
F(select_by_word_characters); F(url_excluded_characters); F(select_by_word_characters_forward);
F(bell_path); F(bell_theme); F(default_window_logo);
F(bell_path); F(bell_theme); F(macos_ns_window_layer); F(default_window_logo);
#undef F
}

View file

@ -391,12 +391,14 @@ option_names = (
'macos_fullscreen_ignore_safe_area_insets',
'macos_hide_from_tasks',
'macos_menubar_title_max_length',
'macos_ns_window_layer',
'macos_option_as_alt',
'macos_quit_when_last_window_closed',
'macos_show_window_title_in',
'macos_thicken_font',
'macos_titlebar_color',
'macos_traditional_fullscreen',
'macos_use_physical_screen_frame',
'macos_window_resizable',
'map',
'map_timeout',
@ -605,12 +607,14 @@ class Options:
macos_fullscreen_ignore_safe_area_insets: bool = False
macos_hide_from_tasks: bool = False
macos_menubar_title_max_length: int = 0
macos_ns_window_layer: str = 'unset'
macos_option_as_alt: int = 0
macos_quit_when_last_window_closed: bool = False
macos_show_window_title_in: choices_for_macos_show_window_title_in = 'all'
macos_thicken_font: float = 0
macos_titlebar_color: int = 0
macos_traditional_fullscreen: bool = False
macos_use_physical_screen_frame: bool = False
macos_window_resizable: bool = True
map_timeout: float = 0
mark1_background: Color = Color(152, 211, 203)

View file

@ -573,7 +573,7 @@ panel_defaults = {
'edge': 'top', 'layer': 'bottom', 'override': '', 'cls': f'{appname}-panel',
'focus_policy': 'not-allowed', 'exclusive_zone': '-1', 'override_exclusive_zone': 'no',
'single_instance': 'no', 'instance_group': '', 'toggle_visibility': 'no',
'start_as_hidden': 'no', 'detach': 'no', 'detached_log': '', 'use_physical_screen_frame': 'no',
'start_as_hidden': 'no', 'detach': 'no', 'detached_log': '',
}
def build_panel_cli_spec(defaults: dict[str, str]) -> str:
@ -639,20 +639,12 @@ that the panel is centered instead of in the top left corner and the margins hav
--layer
choices=background,bottom,top,shell,overlay
choices=background,bottom,top,overlay
default={layer}
On a Wayland compositor that supports the wlr layer shell protocol, specifies the layer
on which the panel should be drawn. This parameter is ignored and set to
:code:`background` if :option:`--edge` is set to :code:`background`. On macOS, maps
these to appropriate NSWindow *levels*. On macOS, :code:`shell` places the panel
above normal application windows but below native system UI such as the menu bar.
--use-physical-screen-frame
type=bool-set
default={use_physical_screen_frame}
On macOS, use the physical screen frame rather than the visible frame when placing the panel.
This allows panels to draw in areas reserved for the native menu bar or dock. Ignored on other platforms.
these to appropriate NSWindow *levels*.
--config -c

View file

@ -78,11 +78,11 @@ typedef struct Options {
bool on_cross, on_drop;
} focus_follows_mouse;
unsigned int hide_window_decorations;
bool macos_hide_from_tasks, macos_quit_when_last_window_closed, macos_window_resizable, macos_traditional_fullscreen, macos_fullscreen_ignore_safe_area_insets;
bool macos_hide_from_tasks, macos_quit_when_last_window_closed, macos_window_resizable, macos_traditional_fullscreen, macos_fullscreen_ignore_safe_area_insets, macos_use_physical_screen_frame;
unsigned int macos_option_as_alt;
float macos_thicken_font;
WindowTitleIn macos_show_window_title_in;
char *bell_path, *bell_theme;
char *bell_path, *bell_theme, *macos_ns_window_layer;
float background_opacity, dim_opacity;
ScrollbarVisibilityPolicy scrollbar;

View file

@ -85,7 +85,6 @@ class LayerShellConfig(NamedTuple):
requested_exclusive_zone: int = -1
override_exclusive_zone: bool = False
hide_on_focus_loss: bool = False
use_physical_screen_frame: bool = False
def mod_to_names(mods: int, has_kitty_mod: bool = False, kitty_mod: int = 0) -> Iterator[str]: