From d34faf3469b6dfe66c8e66c7061dc536014133e0 Mon Sep 17 00:00:00 2001 From: speckitor Date: Fri, 22 May 2026 19:32:18 +0700 Subject: [PATCH] xwayland --- .clang-format | 2 +- include/cursor.h | 3 ++- include/toplevel.h | 1 + include/types.h | 12 +++++---- src/absinthe.c | 6 +++-- src/cursor.c | 3 ++- src/keybinds.c | 2 +- src/keyboard.c | 3 ++- src/layer-surface.c | 3 ++- src/layers.c | 6 +++-- src/layout.c | 12 ++++++--- src/output.c | 3 ++- src/server.c | 6 +++-- src/toplevel-handlers.c | 57 ++++++++++++++++++++++++++++++----------- src/toplevel.c | 22 +++++++++++++--- src/xwayland.c | 12 ++++++++- 16 files changed, 111 insertions(+), 42 deletions(-) diff --git a/.clang-format b/.clang-format index 0898284..b4b9dac 100644 --- a/.clang-format +++ b/.clang-format @@ -2,7 +2,7 @@ BasedOnStyle: LLVM IndentWidth: 4 TabWidth: 4 UseTab: Never -ColumnLimit: 200 +ColumnLimit: 120 AllowShortFunctionsOnASingleLine: false SortIncludes: true BreakBeforeBraces: Custom diff --git a/include/cursor.h b/include/cursor.h index 7f2d15e..f60a2a1 100644 --- a/include/cursor.h +++ b/include/cursor.h @@ -1,6 +1,7 @@ #include "types.h" -void client_from_coords(absn_server *server, double x, double y, struct wlr_surface **rsurface, absn_toplevel **rtoplevel, absn_layer_surface **rlayer_surface, double *rx, double *ry); +void client_from_coords(absn_server *server, double x, double y, struct wlr_surface **rsurface, + absn_toplevel **rtoplevel, absn_layer_surface **rlayer_surface, double *rx, double *ry); void reset_cursor_mode(absn_server *server); void process_cursor_motion(absn_server *server, uint32_t time); diff --git a/include/toplevel.h b/include/toplevel.h index 06141c6..bd3f01d 100644 --- a/include/toplevel.h +++ b/include/toplevel.h @@ -4,6 +4,7 @@ #include "types.h" bool toplevel_is_unmanaged(absn_toplevel *toplevel); +bool toplevel_wants_focus(absn_toplevel *toplevel); void toplevel_get_geom(absn_toplevel *toplevel); diff --git a/include/types.h b/include/types.h index 62a2725..59f6d74 100644 --- a/include/types.h +++ b/include/types.h @@ -28,10 +28,10 @@ #define MAX(A, B) (A) > (B) ? (A) : (B) #define MIN(A, B) (A) < (B) ? (A) : (B) /* macro for adding listener for event */ -#define LISTEN(L, C, E) \ - do { \ - (L).notify = (C); \ - wl_signal_add(&(E), &(L)); \ +#define LISTEN(L, C, E) \ + do { \ + (L).notify = (C); \ + wl_signal_add(&(E), &(L)); \ } while (0); #define UNUSED(X) (void)(X) #define CLEANMASK(M) (M & ~WLR_MODIFIER_CAPS) @@ -51,7 +51,7 @@ enum { BOTTOM_RIGHT, }; -/* toplevel types */ +/* client types */ enum { TOPLEVEL_XDG, TOPLEVEL_X11, @@ -218,6 +218,8 @@ struct absn_toplevel { struct wlr_scene_rect *border[4]; struct wlr_xdg_toplevel_decoration_v1 *deco; + bool can_be_tiled; + bool floating; bool fullscreen; bool urgent; diff --git a/src/absinthe.c b/src/absinthe.c index aa69d57..769d10a 100644 --- a/src/absinthe.c +++ b/src/absinthe.c @@ -50,7 +50,8 @@ static int setup(absn_server *server) server->scene = wlr_scene_create(); if (wlr_renderer_get_texture_formats(server->renderer, WLR_BUFFER_CAP_DMABUF)) { wlr_drm_create(server->display, server->renderer); - wlr_scene_set_linux_dmabuf_v1(server->scene, wlr_linux_dmabuf_v1_create_with_renderer(server->display, 5, server->renderer)); + wlr_scene_set_linux_dmabuf_v1(server->scene, + wlr_linux_dmabuf_v1_create_with_renderer(server->display, 5, server->renderer)); } server->bg = wlr_scene_rect_create(&server->scene->tree, 0, 0, bgcolor); @@ -74,7 +75,8 @@ static int setup(absn_server *server) wlr_export_dmabuf_manager_v1_create(server->display); wlr_ext_foreign_toplevel_list_v1_create(server->display, 1); - wlr_server_decoration_manager_set_default_mode(wlr_server_decoration_manager_create(server->display), WLR_SERVER_DECORATION_MANAGER_MODE_SERVER); + wlr_server_decoration_manager_set_default_mode(wlr_server_decoration_manager_create(server->display), + WLR_SERVER_DECORATION_MANAGER_MODE_SERVER); server->xdg_deco_mgr = wlr_xdg_decoration_manager_v1_create(server->display); LISTEN(server->new_xdg_deco, new_xdg_decoration, server->xdg_deco_mgr->events.new_toplevel_decoration); diff --git a/src/cursor.c b/src/cursor.c index 747b0d3..36042ce 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -9,7 +9,8 @@ * returns surface at given cursor coordinates * and coordinates inside of it to process input event */ -void client_from_coords(absn_server *server, double x, double y, struct wlr_surface **rsurface, absn_toplevel **rtoplevel, absn_layer_surface **rlayer_surface, double *rx, double *ry) +void client_from_coords(absn_server *server, double x, double y, struct wlr_surface **rsurface, + absn_toplevel **rtoplevel, absn_layer_surface **rlayer_surface, double *rx, double *ry) { struct wlr_scene_node *pnode = NULL, *node = NULL; struct wlr_scene_buffer *buffer = NULL; diff --git a/src/keybinds.c b/src/keybinds.c index 9a8f86d..c40a4a0 100644 --- a/src/keybinds.c +++ b/src/keybinds.c @@ -1,5 +1,5 @@ -#include #include +#include #include #include #include diff --git a/src/keyboard.c b/src/keyboard.c index ee3a3c1..8d71d4c 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -21,7 +21,8 @@ static bool handle_keybind(absn_server *server, uint32_t mods, xkb_keysym_t keys { int nkeyb = sizeof(keybinds) / sizeof(keybinds[0]); for (int i = 0; i < nkeyb; ++i) { - if (CLEANMASK(keybinds[i].mods) == CLEANMASK(mods) && xkb_keysym_to_lower(keybinds[i].keysym) == xkb_keysym_to_lower(keysym)) { + if (CLEANMASK(keybinds[i].mods) == CLEANMASK(mods) && + xkb_keysym_to_lower(keybinds[i].keysym) == xkb_keysym_to_lower(keysym)) { keybinds[i].cb(server, &keybinds[i].arg); return true; } diff --git a/src/layer-surface.c b/src/layer-surface.c index f0879a2..12a1ac2 100644 --- a/src/layer-surface.c +++ b/src/layer-surface.c @@ -1,5 +1,5 @@ -#include #include +#include #include "focus.h" #include "layers.h" @@ -54,6 +54,7 @@ void layer_surface_commit(struct wl_listener *listener, void *data) } layers_arrange(layer_surface->output); + wlr_surface_send_enter(surface->surface, surface->output); } void layer_surface_new_popup(struct wl_listener *listener, void *data) diff --git a/src/layers.c b/src/layers.c index 297ac8f..2a26dea 100644 --- a/src/layers.c +++ b/src/layers.c @@ -19,7 +19,8 @@ static void layer_arrange(absn_output *output, struct wl_list *list, struct wlr_ } wlr_scene_layer_surface_v1_configure(layer_surface->scene_layer, &output->geom, usable_area); - wlr_scene_node_set_position(&layer_surface->popups->node, layer_surface->scene_tree->node.x, layer_surface->scene_tree->node.y); + wlr_scene_node_set_position(&layer_surface->popups->node, layer_surface->scene_tree->node.x, + layer_surface->scene_tree->node.y); } } @@ -64,7 +65,8 @@ void layers_arrange(absn_output *output) output->server->exclusive_focus = layer_surface; struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(output->server->seat); if (keyboard) { - wlr_seat_keyboard_notify_enter(output->server->seat, layer_surface->wlr->surface, keyboard->keycodes, keyboard->num_keycodes, &keyboard->modifiers); + wlr_seat_keyboard_notify_enter(output->server->seat, layer_surface->wlr->surface, keyboard->keycodes, + keyboard->num_keycodes, &keyboard->modifiers); } return; } diff --git a/src/layout.c b/src/layout.c index 6cfb5c1..4086b9a 100644 --- a/src/layout.c +++ b/src/layout.c @@ -44,7 +44,8 @@ static void tile(struct absn_output *output) break; } } - new_geom.x = output->usable_area.x + og, new_geom.y = output->usable_area.y + og, new_geom.width = output->usable_area.width - 2 * og, new_geom.height = output->usable_area.height - 2 * og, + new_geom.x = output->usable_area.x + og, new_geom.y = output->usable_area.y + og, + new_geom.width = output->usable_area.width - 2 * og, new_geom.height = output->usable_area.height - 2 * og, toplevel_set_geom(toplevel, &new_geom); return; @@ -56,7 +57,8 @@ static void tile(struct absn_output *output) int mcount = output->workspace->count; float msize = output->workspace->size; - int32_t main_stack_width = (toplevels_count <= mcount) ? output->usable_area.width - 2 * og : msize * (output->usable_area.width - 2 * og); + int32_t main_stack_width = + (toplevels_count <= mcount) ? output->usable_area.width - 2 * og : msize * (output->usable_area.width - 2 * og); int32_t w = output->usable_area.width - main_stack_width - 2 * og - lg; int32_t pure_h; @@ -163,7 +165,8 @@ static void tile_left(struct absn_output *output) break; } } - new_geom.x = output->usable_area.x + og, new_geom.y = output->usable_area.y + og, new_geom.width = output->usable_area.width - 2 * og, new_geom.height = output->usable_area.height - 2 * og, + new_geom.x = output->usable_area.x + og, new_geom.y = output->usable_area.y + og, + new_geom.width = output->usable_area.width - 2 * og, new_geom.height = output->usable_area.height - 2 * og, toplevel_set_geom(toplevel, &new_geom); return; @@ -175,7 +178,8 @@ static void tile_left(struct absn_output *output) int mcount = output->workspace->count; float msize = output->workspace->size; - int32_t main_stack_width = (toplevels_count <= mcount) ? output->usable_area.width - 2 * og : msize * (output->usable_area.width - 2 * og); + int32_t main_stack_width = + (toplevels_count <= mcount) ? output->usable_area.width - 2 * og : msize * (output->usable_area.width - 2 * og); int32_t w = output->usable_area.width - main_stack_width - 2 * og - lg; int32_t pure_h; diff --git a/src/output.c b/src/output.c index 2452ba2..0f2e9ff 100644 --- a/src/output.c +++ b/src/output.c @@ -17,12 +17,13 @@ void output_frame(struct wl_listener *listener, void *data) absn_toplevel *toplevel; wl_list_for_each(toplevel, &output->server->toplevels, link) { - if (toplevel->resizing && toplevel->output == output) { + if (toplevel->resizing && !toplevel->floating && toplevel->output == output) { goto skip; } } wlr_scene_output_commit(scene_output, NULL); + skip: clock_gettime(CLOCK_MONOTONIC, &now); wlr_scene_output_send_frame_done(scene_output, &now); diff --git a/src/server.c b/src/server.c index 764c1ae..43ac9a5 100644 --- a/src/server.c +++ b/src/server.c @@ -156,7 +156,8 @@ void new_layer_surface(struct wl_listener *listener, void *data) struct wlr_scene_tree *scene_layer = server->layers[layermap[surface->pending.layer]]; layer_surface->scene_layer = wlr_scene_layer_surface_v1_create(scene_layer, surface); layer_surface->scene_tree = layer_surface->scene_layer->tree; - layer_surface->popups = wlr_scene_tree_create(surface->current.layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP ? server->layers[LAYER_TOP] : scene_layer); + layer_surface->popups = wlr_scene_tree_create( + surface->current.layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP ? server->layers[LAYER_TOP] : scene_layer); wl_list_insert(&layer_surface->output->layers[surface->pending.layer], &layer_surface->link); wlr_surface_send_enter(surface->surface, surface->output); @@ -300,7 +301,8 @@ void cursor_axis(struct wl_listener *listener, void *data) { absn_server *server = wl_container_of(listener, server, cursor_axis); struct wlr_pointer_axis_event *event = data; - wlr_seat_pointer_notify_axis(server->seat, event->time_msec, event->orientation, event->delta, event->delta_discrete, event->source, event->relative_direction); + wlr_seat_pointer_notify_axis(server->seat, event->time_msec, event->orientation, event->delta, + event->delta_discrete, event->source, event->relative_direction); } void cursor_frame(struct wl_listener *listener, void *data) diff --git a/src/toplevel-handlers.c b/src/toplevel-handlers.c index 72167d6..bc990a4 100644 --- a/src/toplevel-handlers.c +++ b/src/toplevel-handlers.c @@ -17,10 +17,20 @@ void toplevel_map(struct wl_listener *listener, void *data) toplevel->scene_tree->node.data = toplevel; wlr_scene_node_set_enabled(&toplevel->scene_tree->node, toplevel_is_unmanaged(toplevel)); - if (toplevel->type != TOPLEVEL_X11 && wl_resource_get_version(toplevel->xdg->resource) >= XDG_TOPLEVEL_STATE_TILED_RIGHT_SINCE_VERSION) { + update_focused_output(toplevel->server); + toplevel->output = toplevel->server->focused_output; + toplevel->workspace = toplevel->output->workspace; + toplevel->fullscreen = false; + +#ifdef XWAYLAND + if (toplevel->type == TOPLEVEL_X11) { + toplevel->xw->surface->data = toplevel; + } +#endif + + if (toplevel->type != TOPLEVEL_X11 && + wl_resource_get_version(toplevel->xdg->resource) >= XDG_TOPLEVEL_STATE_TILED_RIGHT_SINCE_VERSION) { wlr_xdg_toplevel_set_tiled(toplevel->xdg, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | WLR_EDGE_RIGHT); - } else { - wlr_xdg_toplevel_set_maximized(toplevel->xdg, true); } #ifdef XWAYLAND @@ -36,27 +46,42 @@ void toplevel_map(struct wl_listener *listener, void *data) toplevel_get_geom(toplevel); toplevel->bw = toplevel_is_unmanaged(toplevel) ? 0 : TOPLEVEL_BW; -#ifdef XWAYLAND - if (toplevel->type == TOPLEVEL_X11) { - toplevel->xw->surface->data = toplevel; + if (toplevel_is_unmanaged(toplevel)) { + toplevel_set_floating(toplevel, true); + toplevel_set_size(toplevel, toplevel->geom.width, toplevel->geom.height); + if (toplevel_wants_focus(toplevel)) { + focus_toplevel(toplevel); + server->exclusive_focus = toplevel; + } + goto unset_fullscreen; } -#endif for (int i = 0; i < 4; ++i) { toplevel->border[i] = wlr_scene_rect_create(toplevel->scene_tree, 0, 0, unfocused_bc); toplevel->border[i]->node.data = toplevel; } - update_focused_output(toplevel->server); - toplevel->output = toplevel->server->focused_output; - toplevel->workspace = toplevel->output->workspace; - toplevel->fullscreen = false; - wl_list_insert(&toplevel->server->toplevels, &toplevel->link); wl_list_insert(&toplevel->server->focus_stack, &toplevel->flink); - layout_arrange(toplevel->output); focus_toplevel(focus_get_topmost(toplevel->server)); + + if (toplevel->type == TOPLEVEL_XDG && toplevel->xdg->parent) { + toplevel->floating = 1; + } else if (toplevel->type == TOPLEVEL_X11 && toplevel->xw->parent) { + toplevel->floating = 1; + } + +unset_fullscreen: + absn_toplevel *t; + wl_list_for_each(t, &server->toplevels, link) + { + if (t->workspace == toplevel->workspace && t->fullscreen) { + toplevel_set_fullscreen(t, false); + } + } + + layout_arrange(toplevel->output); } void toplevel_unmap(struct wl_listener *listener, void *data) @@ -73,8 +98,10 @@ void toplevel_unmap(struct wl_listener *listener, void *data) toplevel->server->exclusive_focus = NULL; } - wl_list_remove(&toplevel->link); - wl_list_remove(&toplevel->flink); + if (!toplevel_is_unmanaged(toplevel)) { + wl_list_remove(&toplevel->link); + wl_list_remove(&toplevel->flink); + } layout_arrange(toplevel->output); focus_toplevel(focus_get_topmost(toplevel->server)); diff --git a/src/toplevel.c b/src/toplevel.c index 9129f20..d6c4e0f 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -22,6 +22,14 @@ bool toplevel_is_unmanaged(absn_toplevel *toplevel) return false; } +bool toplevel_wants_focus(absn_toplevel *toplevel) +{ +#ifdef XWAYLAND + return toplevel_is_unmanaged(toplevel) && wlr_xwayland_surface_override_redirect_wants_focus(toplevel->xw) && + wlr_xwayland_surface_icccm_input_model(toplevel->xw) != WLR_ICCCM_INPUT_MODEL_NONE; +#endif +} + /* used only to get initial window size */ void toplevel_get_geom(absn_toplevel *toplevel) { @@ -69,7 +77,8 @@ void toplevel_set_pos(absn_toplevel *toplevel, int32_t x, int32_t y) void toplevel_set_size(absn_toplevel *toplevel, int32_t width, int32_t height) { - if (width <= 2 * toplevel->bw || height <= 2 * toplevel->bw || (width == toplevel->geom.width && height == toplevel->geom.height)) { + if (width <= 2 * toplevel->bw || height <= 2 * toplevel->bw || + (width == toplevel->geom.width && height == toplevel->geom.height)) { return; } toplevel->geom.width = width; @@ -94,13 +103,14 @@ void toplevel_set_size(absn_toplevel *toplevel, int32_t width, int32_t height) } #ifdef XWAYLAND else if (toplevel->type == TOPLEVEL_X11) { - wlr_xwayland_surface_configure(toplevel->xw, toplevel->geom.x, toplevel->geom.y, width - 2 * bw, height - 2 * toplevel->bw); + wlr_xwayland_surface_configure(toplevel->xw, toplevel->geom.x, toplevel->geom.y, width - 2 * bw, + height - 2 * toplevel->bw); /* manually update position */ toplevel_set_pos(toplevel, toplevel->geom.x, toplevel->geom.y); - } else + } #endif - wlr_scene_subsurface_tree_set_clip(&toplevel->scene_surface->node, &clip); + wlr_scene_subsurface_tree_set_clip(&toplevel->scene_surface->node, &clip); } void toplevel_set_geom(absn_toplevel *toplevel, struct wlr_box *geom) @@ -115,6 +125,10 @@ void toplevel_set_floating(absn_toplevel *toplevel, bool floating) return; } + if (floating && !toplevel->can_be_tiled) { + return; + } + toplevel->floating = floating; if (floating) { diff --git a/src/xwayland.c b/src/xwayland.c index 6335422..329c8cb 100644 --- a/src/xwayland.c +++ b/src/xwayland.c @@ -1,5 +1,6 @@ #ifdef XWAYLAND +#include "config.h" #include "xwayland.h" #include "toplevel-handlers.h" #include "toplevel.h" @@ -53,7 +54,16 @@ void xwayland_configure(struct wl_listener *listener, void *data) void xwayland_set_hints(struct wl_listener *listener, void *data) { - UNUSED(listener); UNUSED(data); + absn_toplevel *toplevel = wl_container_of(listener, toplevel, xw_set_hints); + if (toplevel == toplevel->server->focused_toplevel || !toplevel->xw->hints) { + return; + } + + toplevel->urgent = xcb_icccm_wm_hints_get_urgency(toplevel->xw->hints); + struct wlr_surface *surface = toplevel->xw->surface; + if (toplevel->urgent && surface && surface->mapped) { + toplevel_set_border_color(toplevel, urgent_bc); + } } #endif