mirror of
https://github.com/kovidgoyal/kitty.git
synced 2026-05-13 16:37:27 +00:00
Quick access terminal: Allow toggling the window to full screen and map using the standard kitty toggle_fullscreen shortcut
Fixes #8626
This commit is contained in:
parent
cf69385823
commit
9ed6be9272
12 changed files with 91 additions and 22 deletions
|
|
@ -115,6 +115,8 @@ Detailed list of changes
|
|||
|
||||
- Wayland: Fix an abort if the terminal program sets a window title longer than 2KB that contains CSI escape sequences and multibyte UTF-8 (:iss:`8619`)
|
||||
|
||||
- Quick access terminal: Allow toggling the window to full screen and map using the standard kitty :sc:`toggle_fullscreen` shortcut (:iss:`8626`)
|
||||
|
||||
0.42.0 [2025-05-11]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
|||
|
|
@ -1940,6 +1940,11 @@ screen_for_window_center(_GLFWwindow *window) {
|
|||
return NSScreen.mainScreen;
|
||||
}
|
||||
|
||||
const GLFWLayerShellConfig*
|
||||
_glfwPlatformGetLayerShellConfig(_GLFWwindow *window) {
|
||||
return &window->ns.layer_shell.config;
|
||||
}
|
||||
|
||||
bool
|
||||
_glfwPlatformSetLayerShellConfig(_GLFWwindow* window, const GLFWLayerShellConfig *value) {
|
||||
#define config window->ns.layer_shell.config
|
||||
|
|
|
|||
|
|
@ -325,7 +325,6 @@ def generate_wrappers(glfw_header: str) -> None:
|
|||
void glfwWaylandRedrawCSDWindowTitle(GLFWwindow *handle)
|
||||
bool glfwWaylandIsWindowFullyCreated(GLFWwindow *handle)
|
||||
bool glfwWaylandBeep(GLFWwindow *handle)
|
||||
GLFWLayerShellConfig* glfwWaylandLayerShellConfig(GLFWwindow *handle)
|
||||
pid_t glfwWaylandCompositorPID(void)
|
||||
unsigned long long glfwDBusUserNotify(const GLFWDBUSNotificationData *n, GLFWDBusnotificationcreatedfun callback, void *data)
|
||||
void glfwDBusSetUserNotificationHandler(GLFWDBusnotificationactivatedfun handler)
|
||||
|
|
|
|||
6
glfw/glfw3.h
vendored
6
glfw/glfw3.h
vendored
|
|
@ -1309,6 +1309,11 @@ typedef enum { GLFW_FOCUS_NOT_ALLOWED, GLFW_FOCUS_EXCLUSIVE, GLFW_FOCUS_ON_DEMAN
|
|||
typedef struct GLFWLayerShellConfig {
|
||||
GLFWLayerShellType type;
|
||||
GLFWEdge edge;
|
||||
struct {
|
||||
GLFWEdge edge;
|
||||
int requested_top_margin, requested_left_margin, requested_bottom_margin, requested_right_margin;
|
||||
} previous;
|
||||
bool was_toggled_to_fullscreen;
|
||||
char output_name[64];
|
||||
GLFWFocusPolicy focus_policy;
|
||||
unsigned x_size_in_cells, x_size_in_pixels;
|
||||
|
|
@ -2874,6 +2879,7 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, const char* title, G
|
|||
GLFWAPI bool glfwToggleFullscreen(GLFWwindow *window, unsigned int flags);
|
||||
GLFWAPI bool glfwIsFullscreen(GLFWwindow *window, unsigned int flags);
|
||||
GLFWAPI bool glfwAreSwapsAllowed(const GLFWwindow* window);
|
||||
GLFWAPI const GLFWLayerShellConfig* glfwGetLayerShellConfig(GLFWwindow* handle);
|
||||
GLFWAPI bool glfwSetLayerShellConfig(GLFWwindow* handle, const GLFWLayerShellConfig *value);
|
||||
|
||||
/*! @brief Destroys the specified window and its context.
|
||||
|
|
|
|||
1
glfw/internal.h
vendored
1
glfw/internal.h
vendored
|
|
@ -719,6 +719,7 @@ void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title);
|
|||
void _glfwPlatformSetWindowIcon(_GLFWwindow* window,
|
||||
int count, const GLFWimage* images);
|
||||
bool _glfwPlatformSetLayerShellConfig(_GLFWwindow* window, const GLFWLayerShellConfig *value);
|
||||
const GLFWLayerShellConfig* _glfwPlatformGetLayerShellConfig(_GLFWwindow* window);
|
||||
void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos);
|
||||
void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos);
|
||||
void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height);
|
||||
|
|
|
|||
9
glfw/window.c
vendored
9
glfw/window.c
vendored
|
|
@ -551,6 +551,15 @@ GLFWAPI void glfwSetWindowShouldClose(GLFWwindow* handle, int value)
|
|||
window->shouldClose = value;
|
||||
}
|
||||
|
||||
GLFWAPI const GLFWLayerShellConfig* glfwGetLayerShellConfig(GLFWwindow* handle) {
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
assert(window != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(false);
|
||||
return _glfwPlatformGetLayerShellConfig(window);
|
||||
}
|
||||
|
||||
|
||||
GLFWAPI bool glfwSetLayerShellConfig(GLFWwindow* handle, const GLFWLayerShellConfig *value) {
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
assert(window != NULL);
|
||||
|
|
|
|||
5
glfw/wl_window.c
vendored
5
glfw/wl_window.c
vendored
|
|
@ -2892,8 +2892,9 @@ GLFWAPI void glfwWaylandRedrawCSDWindowTitle(GLFWwindow *handle) {
|
|||
if (csd_change_title(window)) commit_window_surface_if_safe(window);
|
||||
}
|
||||
|
||||
GLFWAPI GLFWLayerShellConfig* glfwWaylandLayerShellConfig(GLFWwindow *handle) {
|
||||
return &((_GLFWwindow*)handle)->wl.layer_shell.config;
|
||||
const GLFWLayerShellConfig*
|
||||
_glfwPlatformGetLayerShellConfig(_GLFWwindow *window) {
|
||||
return &window->wl.layer_shell.config;
|
||||
}
|
||||
|
||||
GLFWAPI bool glfwIsLayerShellSupported(void) { return _glfw.wl.zwlr_layer_shell_v1 != NULL; }
|
||||
|
|
|
|||
8
glfw/x11_window.c
vendored
8
glfw/x11_window.c
vendored
|
|
@ -2092,7 +2092,13 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window)
|
|||
XFlush(_glfw.x11.display);
|
||||
}
|
||||
|
||||
bool _glfwPlatformSetLayerShellConfig(_GLFWwindow* window, const GLFWLayerShellConfig *value) {
|
||||
const GLFWLayerShellConfig*
|
||||
_glfwPlatformGetLayerShellConfig(_GLFWwindow *window) {
|
||||
return &window->x11.layer_shell.config;
|
||||
}
|
||||
|
||||
bool
|
||||
_glfwPlatformSetLayerShellConfig(_GLFWwindow* window, const GLFWLayerShellConfig *value) {
|
||||
if (value) window->x11.layer_shell.config = *value;
|
||||
WindowGeometry wg = calculate_layer_geometry(window);
|
||||
update_wm_hints(window, &wg, NULL);
|
||||
|
|
|
|||
6
kitty/glfw-wrapper.c
generated
6
kitty/glfw-wrapper.c
generated
|
|
@ -134,6 +134,9 @@ load_glfw(const char* path) {
|
|||
*(void **) (&glfwAreSwapsAllowed_impl) = dlsym(handle, "glfwAreSwapsAllowed");
|
||||
if (glfwAreSwapsAllowed_impl == NULL) fail("Failed to load glfw function glfwAreSwapsAllowed with error: %s", dlerror());
|
||||
|
||||
*(void **) (&glfwGetLayerShellConfig_impl) = dlsym(handle, "glfwGetLayerShellConfig");
|
||||
if (glfwGetLayerShellConfig_impl == NULL) fail("Failed to load glfw function glfwGetLayerShellConfig with error: %s", dlerror());
|
||||
|
||||
*(void **) (&glfwSetLayerShellConfig_impl) = dlsym(handle, "glfwSetLayerShellConfig");
|
||||
if (glfwSetLayerShellConfig_impl == NULL) fail("Failed to load glfw function glfwSetLayerShellConfig with error: %s", dlerror());
|
||||
|
||||
|
|
@ -497,9 +500,6 @@ load_glfw(const char* path) {
|
|||
*(void **) (&glfwWaylandBeep_impl) = dlsym(handle, "glfwWaylandBeep");
|
||||
if (glfwWaylandBeep_impl == NULL) dlerror(); // clear error indicator
|
||||
|
||||
*(void **) (&glfwWaylandLayerShellConfig_impl) = dlsym(handle, "glfwWaylandLayerShellConfig");
|
||||
if (glfwWaylandLayerShellConfig_impl == NULL) dlerror(); // clear error indicator
|
||||
|
||||
*(void **) (&glfwWaylandCompositorPID_impl) = dlsym(handle, "glfwWaylandCompositorPID");
|
||||
if (glfwWaylandCompositorPID_impl == NULL) dlerror(); // clear error indicator
|
||||
|
||||
|
|
|
|||
13
kitty/glfw-wrapper.h
generated
13
kitty/glfw-wrapper.h
generated
|
|
@ -1047,6 +1047,11 @@ typedef enum { GLFW_FOCUS_NOT_ALLOWED, GLFW_FOCUS_EXCLUSIVE, GLFW_FOCUS_ON_DEMAN
|
|||
typedef struct GLFWLayerShellConfig {
|
||||
GLFWLayerShellType type;
|
||||
GLFWEdge edge;
|
||||
struct {
|
||||
GLFWEdge edge;
|
||||
int requested_top_margin, requested_left_margin, requested_bottom_margin, requested_right_margin;
|
||||
} previous;
|
||||
bool was_toggled_to_fullscreen;
|
||||
char output_name[64];
|
||||
GLFWFocusPolicy focus_policy;
|
||||
unsigned x_size_in_cells, x_size_in_pixels;
|
||||
|
|
@ -1872,6 +1877,10 @@ typedef bool (*glfwAreSwapsAllowed_func)(const GLFWwindow*);
|
|||
GFW_EXTERN glfwAreSwapsAllowed_func glfwAreSwapsAllowed_impl;
|
||||
#define glfwAreSwapsAllowed glfwAreSwapsAllowed_impl
|
||||
|
||||
typedef const GLFWLayerShellConfig* (*glfwGetLayerShellConfig_func)(GLFWwindow*);
|
||||
GFW_EXTERN glfwGetLayerShellConfig_func glfwGetLayerShellConfig_impl;
|
||||
#define glfwGetLayerShellConfig glfwGetLayerShellConfig_impl
|
||||
|
||||
typedef bool (*glfwSetLayerShellConfig_func)(GLFWwindow*, const GLFWLayerShellConfig*);
|
||||
GFW_EXTERN glfwSetLayerShellConfig_func glfwSetLayerShellConfig_impl;
|
||||
#define glfwSetLayerShellConfig glfwSetLayerShellConfig_impl
|
||||
|
|
@ -2356,10 +2365,6 @@ typedef bool (*glfwWaylandBeep_func)(GLFWwindow*);
|
|||
GFW_EXTERN glfwWaylandBeep_func glfwWaylandBeep_impl;
|
||||
#define glfwWaylandBeep glfwWaylandBeep_impl
|
||||
|
||||
typedef GLFWLayerShellConfig* (*glfwWaylandLayerShellConfig_func)(GLFWwindow*);
|
||||
GFW_EXTERN glfwWaylandLayerShellConfig_func glfwWaylandLayerShellConfig_impl;
|
||||
#define glfwWaylandLayerShellConfig glfwWaylandLayerShellConfig_impl
|
||||
|
||||
typedef pid_t (*glfwWaylandCompositorPID_func)(void);
|
||||
GFW_EXTERN glfwWaylandCompositorPID_func glfwWaylandCompositorPID_impl;
|
||||
#define glfwWaylandCompositorPID glfwWaylandCompositorPID_impl
|
||||
|
|
|
|||
49
kitty/glfw.c
49
kitty/glfw.c
|
|
@ -1013,23 +1013,56 @@ do_toggle_fullscreen(OSWindow *w, unsigned int flags, bool restore_sizes) {
|
|||
|
||||
static bool
|
||||
toggle_fullscreen_for_os_window(OSWindow *w) {
|
||||
if (w && w->handle && !w->is_layer_shell) {
|
||||
if (!w || !w->handle) return false;
|
||||
if (!w->is_layer_shell) {
|
||||
#ifdef __APPLE__
|
||||
if (!OPT(macos_traditional_fullscreen)) return do_toggle_fullscreen(w, 1, false);
|
||||
#endif
|
||||
return do_toggle_fullscreen(w, 0, true);
|
||||
}
|
||||
const GLFWLayerShellConfig *prev = glfwGetLayerShellConfig(w->handle);
|
||||
if (!prev) return false;
|
||||
GLFWLayerShellConfig lsc;
|
||||
memcpy(&lsc, prev, sizeof(lsc));
|
||||
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;
|
||||
lsc.requested_top_margin = prev->previous.requested_top_margin;
|
||||
lsc.requested_left_margin = prev->requested_left_margin;
|
||||
lsc.requested_right_margin = prev->requested_right_margin;
|
||||
lsc.was_toggled_to_fullscreen = false;
|
||||
glfwSetLayerShellConfig(w->handle, &lsc);
|
||||
return true;
|
||||
}
|
||||
if (prev->edge == GLFW_EDGE_TOP || prev->edge == GLFW_EDGE_BOTTOM || prev->edge == GLFW_EDGE_LEFT || prev->edge == GLFW_EDGE_RIGHT) {
|
||||
lsc.edge = GLFW_EDGE_CENTER;
|
||||
lsc.previous.edge = prev->edge;
|
||||
lsc.previous.requested_right_margin = prev->requested_right_margin;
|
||||
lsc.previous.requested_left_margin = prev->requested_left_margin;
|
||||
lsc.previous.requested_top_margin = prev->requested_top_margin;
|
||||
lsc.previous.requested_bottom_margin = prev->requested_bottom_margin;
|
||||
lsc.requested_bottom_margin = 0; lsc.requested_top_margin = 0; lsc.requested_left_margin = 0; lsc.requested_right_margin = 0;
|
||||
lsc.was_toggled_to_fullscreen = true;
|
||||
glfwSetLayerShellConfig(w->handle, &lsc);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
is_os_window_fullscreen(OSWindow *w) {
|
||||
unsigned int flags = 0;
|
||||
if (!w || !w->handle) return false;
|
||||
if (w->is_layer_shell) {
|
||||
const GLFWLayerShellConfig *c = glfwGetLayerShellConfig(w->handle);
|
||||
return c && c->was_toggled_to_fullscreen;
|
||||
}
|
||||
#ifdef __APPLE__
|
||||
if (!OPT(macos_traditional_fullscreen)) flags = 1;
|
||||
#endif
|
||||
if (w && w->handle) return glfwIsFullscreen(w->handle, flags);
|
||||
return false;
|
||||
return glfwIsFullscreen(w->handle, flags);
|
||||
}
|
||||
|
||||
static bool
|
||||
|
|
@ -1048,20 +1081,20 @@ toggle_maximized_for_os_window(OSWindow *w) {
|
|||
|
||||
static void
|
||||
change_state_for_os_window(OSWindow *w, int state) {
|
||||
if (!w || !w->handle || w->is_layer_shell) return;
|
||||
if (!w || !w->handle) return;
|
||||
switch (state) {
|
||||
case WINDOW_MAXIMIZED:
|
||||
glfwMaximizeWindow(w->handle);
|
||||
if (!w->is_layer_shell) glfwMaximizeWindow(w->handle);
|
||||
break;
|
||||
case WINDOW_MINIMIZED:
|
||||
glfwIconifyWindow(w->handle);
|
||||
if (!w->is_layer_shell) glfwIconifyWindow(w->handle);
|
||||
break;
|
||||
case WINDOW_FULLSCREEN:
|
||||
if (!is_os_window_fullscreen(w)) toggle_fullscreen_for_os_window(w);
|
||||
break;
|
||||
case WINDOW_NORMAL:
|
||||
if (is_os_window_fullscreen(w)) toggle_fullscreen_for_os_window(w);
|
||||
else glfwRestoreWindow(w->handle);
|
||||
else if (!w->is_layer_shell) glfwRestoreWindow(w->handle);
|
||||
break;
|
||||
case WINDOW_HIDDEN:
|
||||
glfwHideWindow(w->handle); break;
|
||||
|
|
@ -2529,7 +2562,7 @@ layer_shell_config_for_os_window(PyObject *self UNUSED, PyObject *wid) {
|
|||
id_type id = PyLong_AsUnsignedLongLong(wid);
|
||||
OSWindow *w = os_window_for_id(id);
|
||||
if (!w || !w->handle) Py_RETURN_NONE;
|
||||
const GLFWLayerShellConfig *c = glfwWaylandLayerShellConfig(w->handle);
|
||||
const GLFWLayerShellConfig *c = glfwGetLayerShellConfig(w->handle);
|
||||
if (!c) Py_RETURN_NONE;
|
||||
return layer_shell_config_to_python(c);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from kitty.fast_data_types import get_os_window_size, layer_shell_config_for_os_window, set_layer_shell_config, toggle_os_window_visibility
|
||||
from kitty.fast_data_types import get_os_window_size, layer_shell_config_for_os_window, set_layer_shell_config, toggle_fullscreen, toggle_os_window_visibility
|
||||
|
||||
from .base import (
|
||||
MATCH_WINDOW_OPTION,
|
||||
|
|
@ -139,6 +139,10 @@ using this option means that you will not be notified of failures.
|
|||
toggle_os_window_visibility(os_window_id, False)
|
||||
elif ac == 'show':
|
||||
toggle_os_window_visibility(os_window_id, True)
|
||||
elif ac == 'toggle-fullscreen':
|
||||
if not toggle_fullscreen(os_window_id):
|
||||
raise RemoteControlErrorWithoutTraceback(
|
||||
f'The OS Window {os_window_id} is a desktop panel that cannot be made fullscreen')
|
||||
elif is_panel:
|
||||
raise RemoteControlErrorWithoutTraceback(
|
||||
f'The OS Window {os_window_id} is a desktop panel, no actions other than resizing are supported for it')
|
||||
|
|
@ -147,8 +151,6 @@ using this option means that you will not be notified of failures.
|
|||
os_window_id, width=payload_get('width'), height=payload_get('height'),
|
||||
unit=payload_get('unit'), incremental=payload_get('incremental'), metrics=metrics,
|
||||
)
|
||||
elif ac == 'toggle-fullscreen':
|
||||
boss.toggle_fullscreen(os_window_id)
|
||||
elif ac == 'toggle-maximized':
|
||||
boss.toggle_maximized(os_window_id)
|
||||
return None
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue