Finish glfw side support for layer shell

This commit is contained in:
Kovid Goyal
2024-03-24 11:03:34 +05:30
parent 0641ec2d89
commit fe5ccc144b
6 changed files with 147 additions and 14 deletions

View File

@@ -314,7 +314,7 @@ def generate_wrappers(glfw_header: str) -> None:
void glfwWaylandRunWithActivationToken(GLFWwindow *handle, GLFWactivationcallback cb, void *cb_data) void glfwWaylandRunWithActivationToken(GLFWwindow *handle, GLFWactivationcallback cb, void *cb_data)
bool glfwWaylandSetTitlebarColor(GLFWwindow *handle, uint32_t color, bool use_system_color) bool glfwWaylandSetTitlebarColor(GLFWwindow *handle, uint32_t color, bool use_system_color)
void glfwWaylandRedrawCSDWindowTitle(GLFWwindow *handle) void glfwWaylandRedrawCSDWindowTitle(GLFWwindow *handle)
GLFWLayerShellConfig* glfwWaylandSetupLayerShellForNextWindow(void) void glfwWaylandSetupLayerShellForNextWindow(GLFWLayerShellConfig c)
unsigned long long glfwDBusUserNotify(const char *app_name, const char* icon, const char *summary, const char *body, \ unsigned long long glfwDBusUserNotify(const char *app_name, const char* icon, const char *summary, const char *body, \
const char *action_text, int32_t timeout, GLFWDBusnotificationcreatedfun callback, void *data) const char *action_text, int32_t timeout, GLFWDBusnotificationcreatedfun callback, void *data)
void glfwDBusSetUserNotificationHandler(GLFWDBusnotificationactivatedfun handler) void glfwDBusSetUserNotificationHandler(GLFWDBusnotificationactivatedfun handler)

8
glfw/glfw3.h vendored
View File

@@ -1294,10 +1294,16 @@ typedef struct GLFWkeyevent
typedef enum { GLFW_LAYER_SHELL_NONE, GLFW_LAYER_SHELL_BACKGROUND, GLFW_LAYER_SHELL_PANEL } GLFWLayerShellType; typedef enum { GLFW_LAYER_SHELL_NONE, GLFW_LAYER_SHELL_BACKGROUND, GLFW_LAYER_SHELL_PANEL } GLFWLayerShellType;
typedef enum { GLFW_EDGE_TOP, GLFW_EDGE_BOTTOM, GLFW_EDGE_LEFT, GLFW_EDGE_RIGHT } GLFWEdge;
typedef enum { GLFW_FOCUS_NOT_ALLOWED, GLFW_FOCUS_EXCLUSIVE, GLFW_FOCUS_ON_DEMAND} GLFWFocusPolicy;
typedef struct GLFWLayerShellConfig { typedef struct GLFWLayerShellConfig {
GLFWLayerShellType type; GLFWLayerShellType type;
GLFWEdge edge;
const char *output_name; const char *output_name;
const char *edge; GLFWFocusPolicy focus_policy;
void (*size_callback)(GLFWwindow *window, const struct GLFWLayerShellConfig *config, float scale, unsigned monitor_width, unsigned monitor_height, uint32_t *width, uint32_t *height);
} GLFWLayerShellConfig; } GLFWLayerShellConfig;
/*! @brief The function pointer type for error callbacks. /*! @brief The function pointer type for error callbacks.

4
glfw/wl_init.c vendored
View File

@@ -739,7 +739,7 @@ static void registryHandleGlobal(void* data UNUSED,
_glfw.wl.org_kde_kwin_blur_manager = wl_registry_bind(registry, name, &org_kde_kwin_blur_manager_interface, 1); _glfw.wl.org_kde_kwin_blur_manager = wl_registry_bind(registry, name, &org_kde_kwin_blur_manager_interface, 1);
} }
else if (is(zwlr_layer_shell_v1)) { else if (is(zwlr_layer_shell_v1)) {
if (version > 3) { if (version >= 4) {
_glfw.wl.zwlr_layer_shell_v1_version = version; _glfw.wl.zwlr_layer_shell_v1_version = version;
_glfw.wl.zwlr_layer_shell_v1 = wl_registry_bind(registry, name, &zwlr_layer_shell_v1_interface, version); _glfw.wl.zwlr_layer_shell_v1 = wl_registry_bind(registry, name, &zwlr_layer_shell_v1_interface, version);
} }
@@ -986,6 +986,8 @@ void _glfwPlatformTerminate(void)
wp_fractional_scale_manager_v1_destroy(_glfw.wl.wp_fractional_scale_manager_v1); wp_fractional_scale_manager_v1_destroy(_glfw.wl.wp_fractional_scale_manager_v1);
if (_glfw.wl.org_kde_kwin_blur_manager) if (_glfw.wl.org_kde_kwin_blur_manager)
org_kde_kwin_blur_manager_destroy(_glfw.wl.org_kde_kwin_blur_manager); org_kde_kwin_blur_manager_destroy(_glfw.wl.org_kde_kwin_blur_manager);
if (_glfw.wl.zwlr_layer_shell_v1)
zwlr_layer_shell_v1_destroy(_glfw.wl.zwlr_layer_shell_v1);
if (_glfw.wl.registry) if (_glfw.wl.registry)
wl_registry_destroy(_glfw.wl.registry); wl_registry_destroy(_glfw.wl.registry);

4
glfw/wl_platform.h vendored
View File

@@ -169,6 +169,10 @@ typedef struct _GLFWwindowWayland
struct wp_viewport *wp_viewport; struct wp_viewport *wp_viewport;
struct org_kde_kwin_blur *org_kde_kwin_blur; struct org_kde_kwin_blur *org_kde_kwin_blur;
bool has_blur; bool has_blur;
struct {
GLFWLayerShellConfig config;
struct zwlr_layer_surface_v1* zwlr_layer_surface_v1;
} layer_shell;
_GLFWcursor* currentCursor; _GLFWcursor* currentCursor;
double cursorPosX, cursorPosY, allCursorPosX, allCursorPosY; double cursorPosX, cursorPosY, allCursorPosX, allCursorPosY;

133
glfw/wl_window.c vendored
View File

@@ -45,6 +45,9 @@
static GLFWLayerShellConfig layer_shell_config_for_next_window = {0}; static GLFWLayerShellConfig layer_shell_config_for_next_window = {0};
static bool
is_layer_shell(_GLFWwindow *window) { return window->wl.layer_shell.config.type != GLFW_LAYER_SHELL_NONE; }
static void static void
activation_token_done(void *data, struct xdg_activation_token_v1 *xdg_token, const char *token) { activation_token_done(void *data, struct xdg_activation_token_v1 *xdg_token, const char *token) {
for (size_t i = 0; i < _glfw.wl.activation_requests.sz; i++) { for (size_t i = 0; i < _glfw.wl.activation_requests.sz; i++) {
@@ -312,6 +315,14 @@ commit_window_surface_if_safe(_GLFWwindow *window) {
static void static void
update_regions(_GLFWwindow* window) { update_regions(_GLFWwindow* window) {
if (is_layer_shell(window) && window->wl.layer_shell.config.type == GLFW_LAYER_SHELL_PANEL) {
int32_t exclusive_zone = 1;
switch (window->wl.layer_shell.config.edge) {
case GLFW_EDGE_TOP: case GLFW_EDGE_BOTTOM: exclusive_zone = window->wl.height; break;
case GLFW_EDGE_LEFT: case GLFW_EDGE_RIGHT: exclusive_zone = window->wl.width; break;
}
zwlr_layer_surface_v1_set_exclusive_zone(window->wl.layer_shell.zwlr_layer_surface_v1, exclusive_zone);
}
if (window->wl.transparent && !window->wl.org_kde_kwin_blur) return; if (window->wl.transparent && !window->wl.org_kde_kwin_blur) return;
struct wl_region* region = wl_compositor_create_region(_glfw.wl.compositor); struct wl_region* region = wl_compositor_create_region(_glfw.wl.compositor);
if (!region) return; if (!region) return;
@@ -766,9 +777,110 @@ setXdgDecorations(_GLFWwindow* window)
} }
} }
static struct wl_output*
find_output_by_name(const char* name) {
if (!name) return NULL;
int count;
GLFWmonitor** monitors = glfwGetMonitors(&count);
for (int i = 0; i < count; ++i) {
_GLFWmonitor *m = (_GLFWmonitor*)monitors + i;
if (strcmp(m->name, name) == 0) {
return m->wl.output;
}
}
return NULL;
}
static void
layer_surface_handle_configure(void* data, struct zwlr_layer_surface_v1* surface, uint32_t serial, uint32_t width, uint32_t height) {
debug("Layer shell configure event: width: %u height: %u\n", width, height);
_GLFWwindow* window = data;
unsigned monitor_width = 0, monitor_height = 0;
if (window->wl.monitorsCount) {
_GLFWmonitor *m = window->wl.monitors[0];
monitor_width = m->currentMode.width; monitor_height = m->currentMode.height;
}
window->wl.layer_shell.config.size_callback(
(GLFWwindow*)window, &window->wl.layer_shell.config, _glfwWaylandWindowScale(window), monitor_width, monitor_height,
&width, &height);
zwlr_layer_surface_v1_ack_configure(surface, serial);
if ((int)width != window->wl.width || (int)height != window->wl.height) {
debug("Layer shell size changed to %ux%u in layer_surface_handle_configure\n", width, height);
_glfwInputWindowSize(window, width, height);
window->wl.width = width; window->wl.height = height;
resizeFramebuffer(window);
}
commit_window_surface_if_safe(window);
}
static void
layer_surface_handle_close_requested(void* data, struct zwlr_layer_surface_v1* surface UNUSED) {
_GLFWwindow* window = data;
_glfwInputWindowCloseRequest(window);
}
static const struct zwlr_layer_surface_v1_listener zwlr_layer_surface_v1_listener = {
.configure=layer_surface_handle_configure,
.closed=layer_surface_handle_close_requested,
};
static bool static bool
createXdgSurface(_GLFWwindow* window) create_layer_shell_surface(_GLFWwindow *window) {
if (!_glfw.wl.zwlr_layer_shell_v1) {
_glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: wlr-layer-shell protocol unsupported by compositor");
return false;
}
window->decorated = false; // shell windows must not have decorations
struct wl_output *wl_output = find_output_by_name(window->wl.layer_shell.config.output_name);
enum zwlr_layer_shell_v1_layer which_layer = ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND;
enum zwlr_layer_surface_v1_anchor which_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
int exclusive_zone = 0;
enum zwlr_layer_surface_v1_keyboard_interactivity focus_policy = ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE;
switch(window->wl.layer_shell.config.focus_policy) {
case GLFW_FOCUS_NOT_ALLOWED: focus_policy = ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE; break;
case GLFW_FOCUS_EXCLUSIVE: focus_policy = ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE; break;
case GLFW_FOCUS_ON_DEMAND: focus_policy = ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND; break;
}
switch (window->wl.layer_shell.config.type) {
case GLFW_LAYER_SHELL_BACKGROUND:
exclusive_zone = -1;
which_layer = ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND; break;
case GLFW_LAYER_SHELL_PANEL:
exclusive_zone = 1; // we dont know height of window otherwise this should be height
which_layer = ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM; break;
switch (window->wl.layer_shell.config.edge) {
case GLFW_EDGE_TOP: which_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP; break;
case GLFW_EDGE_BOTTOM: which_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; break;
case GLFW_EDGE_LEFT: which_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT; break;
case GLFW_EDGE_RIGHT: which_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; break;
}
case GLFW_LAYER_SHELL_NONE: break;
}
#define ls window->wl.layer_shell.zwlr_layer_surface_v1
ls = zwlr_layer_shell_v1_get_layer_surface(
_glfw.wl.zwlr_layer_shell_v1, window->wl.surface, wl_output, which_layer, "kitty");
if (!ls) {
_glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: layer-surface creation failed");
return false;
}
zwlr_layer_surface_v1_set_size(ls, 0, 0);
zwlr_layer_surface_v1_set_anchor(ls, which_anchor);
zwlr_layer_surface_v1_set_exclusive_zone(ls, exclusive_zone);
zwlr_layer_surface_v1_set_margin(ls, 0, 0, 0, 0);
zwlr_layer_surface_v1_set_keyboard_interactivity(ls, focus_policy);
zwlr_layer_surface_v1_add_listener(ls, &zwlr_layer_surface_v1_listener, window);
wl_surface_commit(window->wl.surface);
wl_display_roundtrip(_glfw.wl.display);
#undef ls
return true;
}
static bool
create_window_desktop_surface(_GLFWwindow* window)
{ {
if (is_layer_shell(window)) return create_layer_shell_surface(window);
window->wl.xdg.surface = xdg_wm_base_get_xdg_surface(_glfw.wl.wmBase, window->wl.xdg.surface = xdg_wm_base_get_xdg_surface(_glfw.wl.wmBase,
window->wl.surface); window->wl.surface);
if (!window->wl.xdg.surface) if (!window->wl.xdg.surface)
@@ -995,13 +1107,14 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
const _GLFWctxconfig* ctxconfig, const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig) const _GLFWfbconfig* fbconfig)
{ {
window->wl.layer_shell.config = layer_shell_config_for_next_window;
memset(&layer_shell_config_for_next_window, 0, sizeof(layer_shell_config_for_next_window));
initialize_csd_metrics(window); initialize_csd_metrics(window);
window->wl.transparent = fbconfig->transparent; window->wl.transparent = fbconfig->transparent;
strncpy(window->wl.appId, wndconfig->wl.appId, sizeof(window->wl.appId)); strncpy(window->wl.appId, wndconfig->wl.appId, sizeof(window->wl.appId));
window->swaps_disallowed = true; window->swaps_disallowed = true;
if (!createSurface(window, wndconfig)) if (!createSurface(window, wndconfig)) return false;
return false;
if (ctxconfig->client != GLFW_NO_API) if (ctxconfig->client != GLFW_NO_API)
{ {
@@ -1029,7 +1142,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
if (wndconfig->visible) if (wndconfig->visible)
{ {
if (!createXdgSurface(window)) if (!create_window_desktop_surface(window))
return false; return false;
window->wl.visible = true; window->wl.visible = true;
@@ -1038,6 +1151,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
{ {
window->wl.xdg.surface = NULL; window->wl.xdg.surface = NULL;
window->wl.xdg.toplevel = NULL; window->wl.xdg.toplevel = NULL;
window->wl.layer_shell.zwlr_layer_surface_v1 = NULL;
window->wl.visible = false; window->wl.visible = false;
} }
@@ -1073,6 +1187,7 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window)
wp_viewport_destroy(window->wl.wp_viewport); wp_viewport_destroy(window->wl.wp_viewport);
if (window->wl.org_kde_kwin_blur) if (window->wl.org_kde_kwin_blur)
org_kde_kwin_blur_release(window->wl.org_kde_kwin_blur); org_kde_kwin_blur_release(window->wl.org_kde_kwin_blur);
if (window->wl.layer_shell.config.output_name) free((void*)window->wl.layer_shell.config.output_name);
if (window->context.destroy) if (window->context.destroy)
window->context.destroy(window); window->context.destroy(window);
@@ -1270,7 +1385,7 @@ void _glfwPlatformShowWindow(_GLFWwindow* window)
{ {
if (!window->wl.visible) if (!window->wl.visible)
{ {
createXdgSurface(window); create_window_desktop_surface(window);
window->wl.visible = true; window->wl.visible = true;
} }
} }
@@ -2428,8 +2543,8 @@ GLFWAPI void glfwWaylandRedrawCSDWindowTitle(GLFWwindow *handle) {
change_csd_title(window); change_csd_title(window);
} }
GLFWAPI void glfwWaylandSetupLayerShellForNextWindow(GLFWLayerShellConfig c) {
GLFWAPI GLFWLayerShellConfig* glfwWaylandSetupLayerShellForNextWindow(void) { if (layer_shell_config_for_next_window.output_name) free((void*)layer_shell_config_for_next_window.output_name);
memset(&layer_shell_config_for_next_window, 0, sizeof(layer_shell_config_for_next_window)); layer_shell_config_for_next_window = c;
return &layer_shell_config_for_next_window; if (layer_shell_config_for_next_window.output_name) layer_shell_config_for_next_window.output_name = strdup(layer_shell_config_for_next_window.output_name);
} }

10
kitty/glfw-wrapper.h generated
View File

@@ -1032,10 +1032,16 @@ typedef struct GLFWkeyevent
typedef enum { GLFW_LAYER_SHELL_NONE, GLFW_LAYER_SHELL_BACKGROUND, GLFW_LAYER_SHELL_PANEL } GLFWLayerShellType; typedef enum { GLFW_LAYER_SHELL_NONE, GLFW_LAYER_SHELL_BACKGROUND, GLFW_LAYER_SHELL_PANEL } GLFWLayerShellType;
typedef enum { GLFW_EDGE_TOP, GLFW_EDGE_BOTTOM, GLFW_EDGE_LEFT, GLFW_EDGE_RIGHT } GLFWEdge;
typedef enum { GLFW_FOCUS_NOT_ALLOWED, GLFW_FOCUS_EXCLUSIVE, GLFW_FOCUS_ON_DEMAND} GLFWFocusPolicy;
typedef struct GLFWLayerShellConfig { typedef struct GLFWLayerShellConfig {
GLFWLayerShellType type; GLFWLayerShellType type;
GLFWEdge edge;
const char *output_name; const char *output_name;
const char *edge; GLFWFocusPolicy focus_policy;
void (*size_callback)(GLFWwindow *window, const struct GLFWLayerShellConfig *config, float scale, unsigned monitor_width, unsigned monitor_height, uint32_t *width, uint32_t *height);
} GLFWLayerShellConfig; } GLFWLayerShellConfig;
/*! @brief The function pointer type for error callbacks. /*! @brief The function pointer type for error callbacks.
@@ -2301,7 +2307,7 @@ typedef void (*glfwWaylandRedrawCSDWindowTitle_func)(GLFWwindow*);
GFW_EXTERN glfwWaylandRedrawCSDWindowTitle_func glfwWaylandRedrawCSDWindowTitle_impl; GFW_EXTERN glfwWaylandRedrawCSDWindowTitle_func glfwWaylandRedrawCSDWindowTitle_impl;
#define glfwWaylandRedrawCSDWindowTitle glfwWaylandRedrawCSDWindowTitle_impl #define glfwWaylandRedrawCSDWindowTitle glfwWaylandRedrawCSDWindowTitle_impl
typedef GLFWLayerShellConfig* (*glfwWaylandSetupLayerShellForNextWindow_func)(void); typedef void (*glfwWaylandSetupLayerShellForNextWindow_func)(GLFWLayerShellConfig);
GFW_EXTERN glfwWaylandSetupLayerShellForNextWindow_func glfwWaylandSetupLayerShellForNextWindow_impl; GFW_EXTERN glfwWaylandSetupLayerShellForNextWindow_func glfwWaylandSetupLayerShellForNextWindow_impl;
#define glfwWaylandSetupLayerShellForNextWindow glfwWaylandSetupLayerShellForNextWindow_impl #define glfwWaylandSetupLayerShellForNextWindow glfwWaylandSetupLayerShellForNextWindow_impl