From 5d81826183fa8763750e7ae2d34525bd69f11275 Mon Sep 17 00:00:00 2001 From: speckitor Date: Sun, 17 May 2026 20:03:02 +0700 Subject: [PATCH] layer shell and others --- .clang-format | 2 +- clip | 2916 +++++++++++++++++++++++++++++++++ include/layer-surface.h | 1 - include/{layer.h => layers.h} | 2 +- include/output.h | 1 + include/toplevel.h | 3 +- include/types.h | 22 +- include/xdg-popup.h | 7 +- src/absinthe.c | 72 +- src/cursor.c | 33 +- src/focus.c | 33 +- src/keybinds.c | 91 +- src/keyboard.c | 18 +- src/layer-surface.c | 75 +- src/layer.c | 21 - src/layers.c | 87 + src/layout.c | 75 +- src/output.c | 84 +- src/seat.c | 15 +- src/server.c | 181 +- src/toplevel-handlers.c | 41 +- src/toplevel.c | 76 +- src/xdg-decoration.c | 9 +- src/xdg-popup.c | 25 +- src/xdg-toplevel.c | 6 +- src/xwayland.c | 18 +- 26 files changed, 3616 insertions(+), 298 deletions(-) create mode 100644 clip rename include/{layer.h => layers.h} (71%) delete mode 100644 src/layer.c create mode 100644 src/layers.c diff --git a/.clang-format b/.clang-format index 45a5bab..5c79c02 100644 --- a/.clang-format +++ b/.clang-format @@ -2,9 +2,9 @@ BasedOnStyle: LLVM IndentWidth: 4 TabWidth: 4 UseTab: Never -ColumnLimit: 120 AllowShortFunctionsOnASingleLine: false SortIncludes: true +InsertBraces: true BreakBeforeBraces: Custom BraceWrapping: AfterFunction: true diff --git a/clip b/clip new file mode 100644 index 0000000..724e1ef --- /dev/null +++ b/clip @@ -0,0 +1,2916 @@ +#ifndef __CONFIG_H_ +#define __CONFIG_H_ + +#include "keybinds.h" +#include "types.h" + +#define CURSOR_MOD WLR_MODIFIER_ALT +#define CURSOR_MOVE_BUTTON BTN_LEFT +#define CURSOR_RESIZE_BUTTON BTN_RIGHT + +#define TOPLEVEL_BW 2 + +static const float bgcolor[4] = {0.0, 0.0, 0.0, 1.0}; + +static const float focused_bc[4] = {1.0, 0.4, 0.6, 1.0}; +static const float urgent_bc[4] = {1.0, 0.0, 0.0, 1.0}; +static const float unfocused_bc[4] = {0.28, 0.28, 0.28, 1.0}; + +#define STACK_COUNT 1 +#define STACK_SIZE 0.5 + +#define OUTPUT_GAP 10 +#define LAYOUT_GAP 5 + +#define ALT WLR_MODIFIER_ALT +#define CTRL WLR_MODIFIER_CTRL +#define SHIFT WLR_MODIFIER_SHIFT +#define LOGO WLR_MODIFIER_LOGO + +static const char *workspaces[] = { + "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", +}; + +static const absn_keybind keybinds[] = { + {ALT, XKB_KEY_Escape, quit, {0}}, + + {ALT, XKB_KEY_Return, &run, {.v = "alacritty"}}, + {ALT, XKB_KEY_q, kill_focus, {0}}, + + {ALT, XKB_KEY_j, cycle_focus, {.i = +1}}, + {ALT, XKB_KEY_k, cycle_focus, {.i = -1}}, + + {ALT | SHIFT, XKB_KEY_j, swap_focus, {.i = +1}}, + {ALT | SHIFT, XKB_KEY_k, swap_focus, {.i = -1}}, + + {ALT, XKB_KEY_f, toggle_fullscreen, {0}}, + {ALT, XKB_KEY_v, toggle_floating, {0}}, + + {ALT, XKB_KEY_h, increase_master_count, {.i = +1}}, + {ALT, XKB_KEY_l, increase_master_count, {.i = -1}}, + + {ALT | SHIFT, XKB_KEY_h, increase_master_width, {.f = -0.05}}, + {ALT | SHIFT, XKB_KEY_l, increase_master_width, {.f = +0.05}}, + + {ALT, XKB_KEY_t, set_layout, {.i = LAYOUT_TILE}}, + {ALT, XKB_KEY_r, set_layout, {.i = LAYOUT_TILELEFT}}, + {ALT, XKB_KEY_m, set_layout, {.i = LAYOUT_MONOCLE}}, + + {ALT, XKB_KEY_1, switch_workspace, {.v = "1"}}, + {ALT, XKB_KEY_2, switch_workspace, {.v = "2"}}, + {ALT, XKB_KEY_3, switch_workspace, {.v = "3"}}, + {ALT, XKB_KEY_4, switch_workspace, {.v = "4"}}, + {ALT, XKB_KEY_5, switch_workspace, {.v = "5"}}, + {ALT, XKB_KEY_6, switch_workspace, {.v = "6"}}, + {ALT, XKB_KEY_7, switch_workspace, {.v = "7"}}, + {ALT, XKB_KEY_8, switch_workspace, {.v = "8"}}, + {ALT, XKB_KEY_9, switch_workspace, {.v = "9"}}, + {ALT, XKB_KEY_0, switch_workspace, {.v = "10"}}, + + {ALT | SHIFT, XKB_KEY_exclam, move_focus_to_workspace, {.v = "1"}}, + {ALT | SHIFT, XKB_KEY_at, move_focus_to_workspace, {.v = "2"}}, + {ALT | SHIFT, XKB_KEY_numbersign, move_focus_to_workspace, {.v = "3"}}, + {ALT | SHIFT, XKB_KEY_dollar, move_focus_to_workspace, {.v = "4"}}, + {ALT | SHIFT, XKB_KEY_percent, move_focus_to_workspace, {.v = "5"}}, + {ALT | SHIFT, XKB_KEY_asciicircum, move_focus_to_workspace, {.v = "6"}}, + {ALT | SHIFT, XKB_KEY_ampersand, move_focus_to_workspace, {.v = "7"}}, + {ALT | SHIFT, XKB_KEY_asterisk, move_focus_to_workspace, {.v = "8"}}, + {ALT | SHIFT, XKB_KEY_parenleft, move_focus_to_workspace, {.v = "9"}}, + {ALT | SHIFT, XKB_KEY_parenright, move_focus_to_workspace, {.v = "10"}}, +}; + +#endif +#include "types.h" + +void reset_cursor_mode(absn_server *server); +void process_cursor_motion(absn_server *server, uint32_t time); +#ifndef __FOCUS_H_ +#define __FOCUS_H_ + +#include "types.h" + +void unfocus_toplevel(absn_toplevel *toplevel); +void focus_toplevel(absn_toplevel *toplevel); +absn_toplevel *focus_get_topmost(absn_server *server); + +#endif +#ifndef __KEYBINDS_CALLBACKS_H +#define __KEYBINDS_CALLBACKS_H + +#include "types.h" + +void run(absn_server *server, const absn_arg *arg); + +void kill_focus(absn_server *server, const absn_arg *arg); + +void cycle_focus(absn_server *server, const absn_arg *arg); +void swap_focus(absn_server *server, const absn_arg *arg); + +void toggle_fullscreen(absn_server *server, const absn_arg *arg); +void toggle_floating(absn_server *server, const absn_arg *arg); + +void increase_master_width(absn_server *server, const absn_arg *arg); +void increase_master_count(absn_server *server, const absn_arg *arg); + +void switch_workspace(absn_server *server, const absn_arg *arg); +void move_focus_to_workspace(absn_server *server, const absn_arg *arg); + +void set_layout(absn_server *server, const absn_arg *arg); + +void quit(absn_server *server, const absn_arg *arg); + +#endif +#ifndef __KEYBOARD_H_ +#define __KEYBOARD_H_ + +#include + +void handle_modifiers(struct wl_listener *listener, void *data); +void handle_key(struct wl_listener *listener, void *data); +void handle_destroy(struct wl_listener *listener, void *data); + +#endif +#ifndef __LAYER_ARRANGE_H_ +#define __LAYER_ARRANGE_H_ + +#include "output.h" +#include "types.h" + +void layers_arrange(absn_output *output); + +#endif +#ifndef __LAYER_SURFACE_H_ +#define __LAYER_SURFACE_H_ + +#include + +void layer_surface_unmap(struct wl_listener *listener, void *data); +void layer_surface_commit(struct wl_listener *listener, void *data); +void layer_surface_new_popup(struct wl_listener *listener, void *data); +void layer_surface_destroy(struct wl_listener *listener, void *data); + +#endif +#ifndef __LAYOUT_H_ +#define __LAYOUT_H_ + +#include "types.h" + +void layout_arrange(absn_output *output); + +#endif +#ifndef __OUTPUT_H_ +#define __OUTPUT_H_ + +#include + +#include "types.h" + +void output_frame(struct wl_listener *listener, void *data); +void output_request_state(struct wl_listener *listener, void *data); +void output_destroy(struct wl_listener *listener, void *data); +void output_layout_change(struct wl_listener *listener, void *data); + +void update_focused_output(absn_server *server); +void output_arrange(absn_output *output); + +#endif +#ifndef __SEAT_H_ +#define __SEAT_H_ + +#include + +void request_cursor(struct wl_listener *listener, void *data); +void pointer_focus_change(struct wl_listener *listener, void *data); +void request_set_selection(struct wl_listener *listener, void *data); + +#endif +#ifndef __SERVER_H_ +#define __SERVER_H_ + +#include + +void new_output(struct wl_listener *listener, void *data); + +void new_xdg_toplevel(struct wl_listener *listener, void *data); +void new_xdg_popup(struct wl_listener *listener, void *data); +void new_xdg_decoration(struct wl_listener *listener, void *data); + +void new_layer_surface(struct wl_listener *listener, void *data); + +#ifdef XWAYLAND +void xwayland_ready(struct wl_listener *listener, void *data); +void xwayland_new_surface(struct wl_listener *listener, void *data); +#endif + +void cursor_motion(struct wl_listener *listener, void *data); +void cursor_motion_abs(struct wl_listener *listener, void *data); +void cursor_button(struct wl_listener *listener, void *data); +void cursor_axis(struct wl_listener *listener, void *data); +void cursor_frame(struct wl_listener *listener, void *data); + +void new_input(struct wl_listener *listener, void *data); + +#endif +#ifndef __TOPLEVEL_H_ +#define __TOPLEVEL_H_ + +#include "types.h" + +absn_toplevel *toplevel_at(absn_server *server, double lx, double ly, struct wlr_surface **surface, double *sx, + double *sy); + +bool toplevel_is_unmanaged(absn_toplevel *toplevel); + +void toplevel_get_geom(absn_toplevel *toplevel); + +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); +void toplevel_set_geom(absn_toplevel *toplevel, struct wlr_box *geom); +void toplevel_set_floating(absn_toplevel *toplevel, bool floating); +void toplevel_set_fullscreen(absn_toplevel *toplevel, bool fullscreen); +void toplevel_set_border_color(absn_toplevel *toplevel, const float color[4]); + +#endif +#ifndef __TOPLEVLE_HANDLERS_H_ +#define __TOPLEVLE_HANDLERS_H_ + +#include + +void toplevel_map(struct wl_listener *listener, void *data); +void toplevel_unmap(struct wl_listener *listener, void *data); +void toplevel_destroy(struct wl_listener *listener, void *data); +void toplevel_request_move(struct wl_listener *listener, void *data); +void toplevel_request_resize(struct wl_listener *listener, void *data); +void toplevel_request_maximize(struct wl_listener *listener, void *data); +void toplevel_request_fullscreen(struct wl_listener *listener, void *data); + +#endif +#ifndef __TYPES_H_ +#define __TYPES_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef XWAYLAND +#include +#include +#include +#endif + +#define BTN_LEFT 0x110 +#define BTN_RIGHT 0x111 +#define BTN_MIDDLE 0x112 + +#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)); \ + } while (0); +#define UNUSED(X) (void)(X) +#define CLEANMASK(M) (M & ~WLR_MODIFIER_CAPS) + +/* cursor mode */ +enum { + CURSOR_PASSTHROUGH, + CURSOR_MOVE, + CURSOR_RESIZE, +}; + +/* resizing corners */ +enum { + TOP_LEFT, + TOP_RIGHT, + BOTTOM_LEFT, + BOTTOM_RIGHT, +}; + +/* toplevel types */ +enum { + TOPLEVEL_XDG, + TOPLEVEL_X11, + LAYER_SURFACE, +}; + +/* layers for wlr layer shell */ +enum { + LAYER_BACKGROUND, + LAYER_BOTTOM, + LAYER_TILE, + LAYER_FLOAT, + LAYER_FULLSCREEN, + LAYER_TOP, + LAYER_OVERLAY, + LAYERS_COUNT, +}; + +static const int layermap[] = { + LAYER_BACKGROUND, + LAYER_BOTTOM, + LAYER_TOP, + LAYER_OVERLAY, +}; + +enum { + LAYOUT_TILE, + LAYOUT_TILELEFT, + LAYOUT_TILETOP, + LAYOUT_TILEBOTTOM, + LAYOUT_MONOCLE, + LAYOUT_SPIRAL, + LAYOUT_DWINDLE, + LAYOUT_VGRID, + LAYOUT_HGRID, +}; + +typedef struct absn_output absn_output; +typedef struct absn_toplevel absn_toplevel; + +typedef struct { + int layout; + const char *name; + absn_output *output; + int count; + float size; +} absn_workspace; + +typedef struct { + struct wl_display *display; + struct wlr_backend *backend; + struct wlr_renderer *renderer; + struct wlr_allocator *allocator; + struct wlr_compositor *compositor; + struct wlr_scene *scene; + struct wlr_scene_output_layout *scene_layout; + struct wlr_scene_rect *bg; + + struct wlr_xdg_shell *xdg_shell; + struct wl_listener new_xdg_toplevel; + struct wl_listener new_xdg_popup; + struct wlr_xdg_decoration_manager_v1 *xdg_deco_mgr; + struct wl_listener new_xdg_deco; + + struct wlr_layer_shell_v1 *layer_shell; + struct wl_listener new_layer_surface; + struct wlr_scene_tree *layers[LAYERS_COUNT]; + +#ifdef XWAYLAND + struct wlr_xwayland *xwayland; + struct wl_listener xw_new_surface; + struct wl_listener xw_ready; +#endif + + struct wlr_cursor *cursor; + struct wlr_xcursor_manager *cursor_mgr; + struct wl_listener cursor_motion; + struct wl_listener cursor_motion_abs; + struct wl_listener cursor_button; + struct wl_listener cursor_axis; + struct wl_listener cursor_frame; + + struct wlr_seat *seat; + struct wl_listener new_input; + struct wl_listener request_cursor; + struct wl_listener pointer_focus_change; + struct wl_listener request_set_selection; + struct wl_list keyboards; + + int cursor_mode; + int resize_corner; + struct wlr_box grab_geom; + int32_t grab_x, grab_y; + + struct wl_list toplevels; + struct wl_list focus_stack; + absn_toplevel *focused_toplevel; + + absn_output *focused_output; + struct wl_list outputs; + struct wl_listener new_output; + struct wlr_output_layout *output_layout; + struct wl_listener layout_change; + struct wlr_output_manager_v1 *output_mgr; + struct wl_listener mgr_apply; + struct wl_listener mgr_test; + + int workspaces_count; + absn_workspace *workspaces; +} absn_server; + +struct absn_output { + struct wl_list link; + absn_server *server; + + absn_workspace *workspace; + + struct wlr_box geom; + struct wlr_box usable_area; + + struct wlr_output *wlr; + struct wl_listener frame; + struct wl_listener request_state; + struct wl_listener destroy; + + struct wl_list layers[4]; +}; + +typedef struct { + struct wl_list link; + + absn_server *server; + absn_output *output; + + bool mapped; + struct wlr_scene_tree *scene_tree; + struct wlr_scene_layer_surface_v1 *scene_layer; + struct wlr_scene_tree *popups; + + struct wlr_layer_surface_v1 *wlr; + struct wl_listener map; + struct wl_listener unmap; + struct wl_listener commit; + struct wl_listener new_popup; + struct wl_listener destroy; +} absn_layer_surface; + +struct absn_toplevel { + struct wl_list link; + struct wl_list flink; /* link for focus stack */ + uint32_t tag; + absn_server *server; + absn_output *output; + absn_workspace *workspace; + + struct wlr_scene_tree *scene_tree; + struct wlr_scene_tree *scene_surface; + + int32_t bw; + struct wlr_scene_rect *border[4]; + struct wlr_xdg_toplevel_decoration_v1 *deco; + + bool floating; + bool fullscreen; + bool urgent; + uint32_t resizing; + + struct wlr_box geom; + struct wlr_box prev_geom; + + int type; + union { + struct wlr_xdg_toplevel *xdg; + struct wlr_xwayland_surface *xw; + }; + + struct wl_listener map; + struct wl_listener unmap; + struct wl_listener commit; + struct wl_listener destroy; + struct wl_listener request_move; + struct wl_listener request_resize; + struct wl_listener request_maximize; + struct wl_listener request_fullscreen; + struct wl_listener deco_request_mode; + struct wl_listener deco_destroy; + +#ifdef XWAYLAND + struct wl_listener xw_activate; + struct wl_listener xw_associate; + struct wl_listener xw_dissociate; + struct wl_listener xw_configure; + struct wl_listener xw_set_hints; +#endif +}; + +typedef struct { + struct wlr_xdg_popup *wlr; + + int parent_type; + void *parent; + + struct wl_listener commit; +} absn_popup; + +typedef struct { + struct wl_list link; + absn_server *server; + + struct wlr_keyboard *wlr; + struct wl_listener modifiers; + struct wl_listener key; + struct wl_listener destroy; +} absn_keyboard; + +typedef struct { + int i; + float f; + const void *v; +} absn_arg; + +typedef struct { + uint32_t mods; + xkb_keysym_t keysym; + void (*cb)(absn_server *, const absn_arg *); + const absn_arg arg; +} absn_keybind; + +#endif /* __TYPES_H_ */ +#ifndef __XDG_DECORATION_H_ +#define __XDG_DECORATION_H_ + +#include + +void deco_request_mode(struct wl_listener *listener, void *data); +void deco_destroy(struct wl_listener *listener, void *data); + +#endif +#ifndef __XDG_POPUP_H +#define __XDG_POPUP_H + +void xdg_popup_commit(struct wl_listener *listener, void *data); + +#endif +#ifndef __XDG_TOPLEVEL_H_ +#define __XDG_TOPLEVEL_H_ + +#include + +void toplevel_commit(struct wl_listener *listener, void *data); + +#endif +#ifndef __XWAYLAND_H_ +#define __XWAYLAND_H_ + +#include + +void xwayland_activate(struct wl_listener *listener, void *data); +void xwayland_associate(struct wl_listener *listener, void *data); +void xwayland_dissociate(struct wl_listener *listener, void *data); +void xwayland_configure(struct wl_listener *listener, void *data); +void xwayland_set_hints(struct wl_listener *listener, void *data); + +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "output.h" +#include "seat.h" +#include "server.h" +#include "types.h" + +static int setup(absn_server *server) +{ + wlr_log_init(WLR_DEBUG, NULL); + server->display = wl_display_create(); + if (!server->display) { + wlr_log(WLR_ERROR, "Failed to create wl_display"); + return 1; + } + + server->backend = wlr_backend_autocreate(wl_display_get_event_loop(server->display), NULL); + if (!server->backend) { + wlr_log(WLR_ERROR, "Failed to create wlr_backend"); + return 1; + } + + server->renderer = wlr_renderer_autocreate(server->backend); + if (!server->renderer) { + wlr_log(WLR_ERROR, "Failed to create wlr_renderer"); + return 1; + } + + wlr_renderer_init_wl_shm(server->renderer, server->display); + + 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)); + } + server->bg = wlr_scene_rect_create(&server->scene->tree, 0, 0, bgcolor); + + server->allocator = wlr_allocator_autocreate(server->backend, server->renderer); + if (!server->allocator) { + wlr_log(WLR_ERROR, "Failed to create wlr_allocator"); + return 1; + } + + /* wlroots managers */ + server->compositor = wlr_compositor_create(server->display, 6, server->renderer); + wlr_subcompositor_create(server->display); + wlr_data_device_manager_create(server->display); + wlr_screencopy_manager_v1_create(server->display); + wlr_data_control_manager_v1_create(server->display); + wlr_viewporter_create(server->display); + wlr_single_pixel_buffer_manager_v1_create(server->display); + wlr_fractional_scale_manager_v1_create(server->display, 1); + wlr_presentation_create(server->display, server->backend, 2); + wlr_alpha_modifier_v1_create(server->display); + 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); + 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); + + /* toplevels lists */ + wl_list_init(&server->toplevels); + wl_list_init(&server->focus_stack); + + /* output */ + wl_list_init(&server->outputs); + LISTEN(server->new_output, new_output, server->backend->events.new_output); + + server->output_layout = wlr_output_layout_create(server->display); + LISTEN(server->layout_change, output_layout_change, server->output_layout->events.change); + + server->output_mgr = wlr_output_manager_v1_create(server->display); + + wlr_xdg_output_manager_v1_create(server->display, server->output_layout); + + server->scene_layout = wlr_scene_attach_output_layout(server->scene, server->output_layout); + + /* xdg_shell */ + server->xdg_shell = wlr_xdg_shell_create(server->display, 6); + LISTEN(server->new_xdg_toplevel, new_xdg_toplevel, server->xdg_shell->events.new_toplevel); + LISTEN(server->new_xdg_popup, new_xdg_popup, server->xdg_shell->events.new_popup); + + /* cursor */ + server->cursor = wlr_cursor_create(); + wlr_cursor_attach_output_layout(server->cursor, server->output_layout); + + server->cursor_mgr = wlr_xcursor_manager_create(NULL, 24); + + server->cursor_mode = CURSOR_PASSTHROUGH; + LISTEN(server->cursor_motion, cursor_motion, server->cursor->events.motion); + LISTEN(server->cursor_motion_abs, cursor_motion_abs, server->cursor->events.motion_absolute); + LISTEN(server->cursor_button, cursor_button, server->cursor->events.button); + LISTEN(server->cursor_axis, cursor_axis, server->cursor->events.axis); + LISTEN(server->cursor_frame, cursor_frame, server->cursor->events.frame); + + /* keyboard */ + wl_list_init(&server->keyboards); + server->seat = wlr_seat_create(server->display, "seat0"); + LISTEN(server->new_input, new_input, server->backend->events.new_input); + LISTEN(server->request_cursor, request_cursor, server->seat->events.request_set_cursor); + LISTEN(server->pointer_focus_change, pointer_focus_change, server->seat->pointer_state.events.focus_change); + LISTEN(server->request_set_selection, request_cursor, server->seat->events.request_set_selection); + + /* layer shell */ + server->layer_shell = wlr_layer_shell_v1_create(server->display, 1); + for (int i = 0; i < LAYERS_COUNT; ++i) { + server->layers[i] = wlr_scene_tree_create(&server->scene->tree); + } + + /* workspaces */ + int workspaces_count = sizeof(workspaces) / sizeof(workspaces[0]); + server->workspaces_count = workspaces_count; + server->workspaces = calloc(workspaces_count, sizeof(absn_workspace)); + for (int i = 0; i < workspaces_count; ++i) { + server->workspaces[i].layout = LAYOUT_TILE; + server->workspaces[i].name = workspaces[i]; + server->workspaces[i].count = STACK_COUNT; + server->workspaces[i].size = STACK_SIZE; + server->workspaces[i].output = NULL; + } + + unsetenv("DISPLAY"); +#ifdef XWAYLAND + if ((server->xwayland = wlr_xwayland_create(server->display, server->compositor, 1))) { + LISTEN(server->xw_ready, xwayland_ready, server->xwayland->events.ready); + LISTEN(server->xw_new_surface, xwayland_new_surface, server->xwayland->events.new_surface); + + setenv("DISPLAY", server->xwayland->display_name, 1); + wlr_log(WLR_INFO, "Running XWayland, DISPLAY=%s", server->xwayland->display_name); + } else { + wlr_log(WLR_ERROR, "Failed to setup XWayland, continuing without it"); + } +#endif + + const char *socket = wl_display_add_socket_auto(server->display); + if (!socket) { + wlr_log(WLR_ERROR, "Failed to add socket"); + wlr_backend_destroy(server->backend); + return 1; + } + + if (!wlr_backend_start(server->backend)) { + wlr_log(WLR_ERROR, "Failed to start wlr_backend"); + wlr_backend_destroy(server->backend); + wl_display_destroy(server->display); + return 1; + } + + setenv("WAYLAND_DISPLAY", socket, true); + wlr_log(WLR_INFO, "Running absinthe on WAYLAND_DISPLAY=%s", socket); + + return 0; +} + +static void cleanup(absn_server *server) +{ + wl_display_destroy_clients(server->display); + + wl_list_remove(&server->new_xdg_toplevel.link); + wl_list_remove(&server->new_xdg_popup.link); + wl_list_remove(&server->new_xdg_deco.link); + + wl_list_remove(&server->cursor_motion.link); + wl_list_remove(&server->cursor_motion_abs.link); + wl_list_remove(&server->cursor_button.link); + wl_list_remove(&server->cursor_axis.link); + wl_list_remove(&server->cursor_frame.link); + + wl_list_remove(&server->new_input.link); + wl_list_remove(&server->request_cursor.link); + wl_list_remove(&server->pointer_focus_change.link); + wl_list_remove(&server->request_set_selection.link); + + wl_list_remove(&server->new_output.link); + + wl_list_remove(&server->new_layer_surface.link); + + wlr_scene_node_destroy(&server->scene->tree.node); + wlr_xcursor_manager_destroy(server->cursor_mgr); + wlr_cursor_destroy(server->cursor); + wlr_allocator_destroy(server->allocator); + wlr_renderer_destroy(server->renderer); + wlr_backend_destroy(server->backend); + wl_display_destroy(server->display); +} + +int main(void) +{ + absn_server server = {0}; + int err = setup(&server); + if (err) { + return EXIT_FAILURE; + } + wl_display_run(server.display); + cleanup(&server); + return EXIT_SUCCESS; +} +#include +#include + +#include "layout.h" +#include "toplevel.h" +#include "types.h" + +void reset_cursor_mode(absn_server *server) +{ + server->cursor_mode = CURSOR_PASSTHROUGH; + wlr_cursor_set_xcursor(server->cursor, server->cursor_mgr, "default"); + if (server->focused_toplevel) { + wlr_xdg_toplevel_set_resizing(server->focused_toplevel->xdg, false); + } +} + +static void process_cursor_move(absn_server *server) +{ + struct absn_toplevel *toplevel = server->focused_toplevel; + + if (!toplevel) { + return; + } + + if (toplevel->fullscreen) { + toplevel->prev_geom = toplevel->geom; + toplevel_set_fullscreen(toplevel, false); + } + + uint32_t new_x, new_y; + new_x = server->cursor->x - server->grab_x + server->grab_geom.x; + new_y = server->cursor->y - server->grab_y + server->grab_geom.y; + toplevel_set_pos(toplevel, new_x, new_y); + + if (!toplevel->floating) { + toplevel_set_floating(toplevel, true); + } +} + +static void apply_resize(absn_toplevel *toplevel, struct wlr_box *new_geom) +{ + if (toplevel->type == TOPLEVEL_XDG) { + int32_t min_width = toplevel->xdg->current.min_width; + int32_t min_height = toplevel->xdg->current.min_height; + + int32_t max_width = toplevel->xdg->current.max_width; + int32_t max_height = toplevel->xdg->current.max_height; + + if (max_width == 0) { + max_width = 10000; + } + + if (max_height == 0) { + max_height = 10000; + } + + if (!(new_geom->width >= min_width && new_geom->width <= max_width)) { + new_geom->width = toplevel->geom.width; + new_geom->x = toplevel->geom.x; + } + + if (!(new_geom->height >= min_height && new_geom->height <= max_height)) { + new_geom->height = toplevel->geom.height; + new_geom->y = toplevel->geom.y; + } + } + + toplevel_set_geom(toplevel, new_geom); +} + +static void process_cursor_resize(absn_server *server) +{ + struct absn_toplevel *toplevel = server->focused_toplevel; + + if (!toplevel) { + return; + } + + if (toplevel->resizing) { + return; + } + + if (toplevel->fullscreen) { + toplevel_set_fullscreen(toplevel, false); + } + + if (!toplevel->floating) { + toplevel_set_floating(toplevel, true); + } + + int32_t new_x, new_y, new_width, new_height; + new_x = server->grab_geom.x; + new_y = server->grab_geom.y; + new_width = server->grab_geom.width; + new_height = server->grab_geom.height; + + int32_t dx = server->cursor->x - server->grab_x; + int32_t dy = server->cursor->y - server->grab_y; + + if (dx == 0 && dy == 0) { + return; + } + + switch (server->resize_corner) { + case TOP_LEFT: + new_x += dx; + new_y += dy; + new_width -= dx; + new_height -= dy; + break; + case TOP_RIGHT: + new_y += dy; + new_width += dx; + new_height -= dy; + break; + case BOTTOM_LEFT: + new_x += dx; + new_width -= dx; + new_height += dy; + break; + case BOTTOM_RIGHT: + new_width += dx; + new_height += dy; + break; + default: // unreachable + break; + } + + if (new_width > 0 && new_height > 0) { + struct wlr_box new_geometry = { + .x = new_x, + .y = new_y, + .width = new_width, + .height = new_height, + }; + + apply_resize(server->focused_toplevel, &new_geometry); + } +} + +void process_cursor_motion(absn_server *server, uint32_t time) +{ + double sx, sy; + struct wlr_surface *surface = NULL; + toplevel_at(server, server->cursor->x, server->cursor->y, &surface, &sx, &sy); + struct wlr_seat *seat = server->seat; + + if (server->cursor_mode == CURSOR_MOVE) { + process_cursor_move(server); + return; + } else if (server->cursor_mode == CURSOR_RESIZE) { + process_cursor_resize(server); + return; + } + + if (surface) { + wlr_seat_pointer_notify_enter(seat, surface, sx, sy); + wlr_seat_pointer_notify_motion(seat, time, sx, sy); + } else { + wlr_seat_pointer_clear_focus(seat); + } +} +#include +#include + +#include "config.h" +#include "focus.h" +#include "toplevel.h" +#include "types.h" + +void unfocus_toplevel(absn_toplevel *toplevel) +{ + if (!toplevel) { + return; + } + + if (toplevel->type == TOPLEVEL_XDG) { + wlr_xdg_toplevel_set_activated(toplevel->xdg, false); + } + toplevel_set_border_color(toplevel, unfocused_bc); +} + +void focus_toplevel(absn_toplevel *toplevel) +{ + if (!toplevel) { + return; + } + + absn_server *server = toplevel->server; + struct wlr_seat *seat = server->seat; + struct wlr_surface *prev_surface = seat->keyboard_state.focused_surface; + struct wlr_surface *surface; +#ifdef XWAYLAND + if (toplevel->type == TOPLEVEL_X11) { + surface = toplevel->xw->surface; + } else +#endif + surface = toplevel->xdg->base->surface; + + if (surface == prev_surface) { + return; + } + + if (prev_surface) { + unfocus_toplevel(prev_surface->data); + } + + toplevel->server->focused_toplevel = toplevel; + + struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat); + wlr_scene_node_raise_to_top(&toplevel->scene_tree->node); + wl_list_remove(&toplevel->flink); + wl_list_insert(&server->focus_stack, &toplevel->flink); + if (toplevel->type != TOPLEVEL_X11) { + wlr_xdg_toplevel_set_activated(toplevel->xdg, true); + } + toplevel_set_border_color(toplevel, focused_bc); + + if (keyboard) { + wlr_seat_keyboard_notify_enter(seat, surface, keyboard->keycodes, keyboard->num_keycodes, &keyboard->modifiers); + } +} + +/* + * get first toplevel on monitor + * (last focused toplevel) + */ +absn_toplevel *focus_get_topmost(absn_server *server) +{ + absn_toplevel *toplevel; + wl_list_for_each(toplevel, &server->focus_stack, flink) + { + if (toplevel && toplevel->workspace == server->focused_output->workspace) { + return toplevel; + } + } + return NULL; +} +#include +#include +#include +#include + +#include "focus.h" +#include "layout.h" +#include "output.h" +#include "toplevel.h" +#include "types.h" + +void run(absn_server *server, const absn_arg *arg) +{ + UNUSED(server); + if (fork() == 0) { + setsid(); + execl("/bin/sh", "sh", "-c", arg->v, NULL); + } +} + +void kill_focus(absn_server *server, const absn_arg *arg) +{ + UNUSED(arg); + if (!server->focused_toplevel) { + return; + } + + absn_toplevel *focus = server->focused_toplevel; + +#ifdef XWAYLAND + if (focus->type == TOPLEVEL_X11) { + wlr_xwayland_surface_close(focus->xw); + } else +#endif + { + wlr_xdg_toplevel_send_close(focus->xdg); + } +} + +void cycle_focus(absn_server *server, const absn_arg *arg) +{ + absn_toplevel *toplevel = focus_get_topmost(server); + if (!toplevel || toplevel->fullscreen) { + return; + } + + absn_toplevel *new_focus; + if (arg->i > 0) { + wl_list_for_each(new_focus, &toplevel->link, link) + { + if (toplevel->workspace == new_focus->workspace) { + break; + } + } + } else { + wl_list_for_each_reverse(new_focus, &toplevel->link, link) + { + if (toplevel->workspace == new_focus->workspace) { + break; + } + } + } + focus_toplevel(new_focus); +} + +void swap_focus(absn_server *server, const absn_arg *arg) +{ + + absn_toplevel *toplevel = focus_get_topmost(server); + if (!toplevel || toplevel->fullscreen || toplevel->floating) { + return; + } + + absn_toplevel *temp = NULL; + absn_toplevel *first = NULL; + absn_toplevel *last = NULL; + + wl_list_for_each(temp, &server->toplevels, link) + { + if (temp->workspace == toplevel->workspace) { + last = temp; + } + if (!first && temp->workspace == toplevel->workspace) { + first = temp; + } + } + + if (first == last) { + return; + } + + absn_toplevel *swap = NULL; + if (arg->i > 0) { + if (toplevel == last) { + wl_list_remove(&toplevel->link); + wl_list_insert(&server->toplevels, &toplevel->link); + goto arrange; + } + + wl_list_for_each(swap, &toplevel->link, link) + { + if (toplevel->workspace == swap->workspace) { + break; + } + } + + wl_list_remove(&toplevel->link); + wl_list_insert(&swap->link, &toplevel->link); + } else { + if (toplevel == first) { + wl_list_remove(&toplevel->link); + wl_list_insert(server->toplevels.prev, &toplevel->link); + goto arrange; + } + + wl_list_for_each_reverse(swap, &toplevel->link, link) + { + if (toplevel->workspace == swap->workspace) { + break; + } + } + + wl_list_remove(&swap->link); + wl_list_insert(&toplevel->link, &swap->link); + } + +arrange: + layout_arrange(toplevel->output); +} + +void toggle_fullscreen(absn_server *server, const absn_arg *arg) +{ + UNUSED(arg); + if (!server->focused_toplevel) { + return; + } + + absn_toplevel *focus = server->focused_toplevel; + toplevel_set_fullscreen(focus, !focus->fullscreen); +} + +void toggle_floating(absn_server *server, const absn_arg *arg) +{ + UNUSED(arg); + if (!server->focused_toplevel) { + return; + } + + absn_toplevel *focus = server->focused_toplevel; + toplevel_set_floating(focus, !focus->floating); + + if (focus->floating) { + int32_t new_x = focus->output->geom.x + (focus->output->geom.width / 2 - focus->geom.width / 2); + int32_t new_y = focus->output->geom.y + (focus->output->geom.height / 2 - focus->geom.height / 2); + toplevel_set_pos(focus, new_x, new_y); + } +} + +void increase_master_width(absn_server *server, const absn_arg *arg) +{ + absn_workspace *workspace = server->focused_output->workspace; + + if (workspace->size + arg->f >= 1.0 || workspace->size + arg->f <= 0.0) { + return; + } + + workspace->size += arg->f; + layout_arrange(workspace->output); +} + +void increase_master_count(absn_server *server, const absn_arg *arg) +{ + absn_workspace *workspace = server->focused_output->workspace; + + if (workspace->count + arg->i <= 0) { + return; + } + + workspace->count += arg->i; + layout_arrange(workspace->output); +} + +void switch_workspace(absn_server *server, const absn_arg *arg) +{ + int i; + for (i = 0; i < server->workspaces_count; ++i) { + if (arg->v == server->workspaces[i].name) { + break; /* found it */ + } + } + + if (&server->workspaces[i] == server->focused_output->workspace) { + return; + } + + int toplevels_count = 0; + absn_toplevel *toplevel; + wl_list_for_each(toplevel, &server->toplevels, link) + { + if (toplevel->workspace == server->focused_output->workspace) { + toplevels_count++; + } + } + + if (toplevels_count == 0) { + server->focused_output->workspace->output = NULL; + } + + if (!server->workspaces[i].output) { + server->workspaces[i].output = server->focused_output; + } else if (server->focused_output == server->workspaces[i].output) { + server->focused_output->workspace = &server->workspaces[i]; + } else { + server->focused_output = server->workspaces[i].output; + + struct wlr_box *geom = &server->focused_output->geom; + + int32_t new_x = geom->x + (geom->width / 2); + int32_t new_y = geom->y + (geom->height / 2); + + wlr_cursor_warp(server->cursor, NULL, new_x, new_y); + } + server->focused_output->workspace = &server->workspaces[i]; + + absn_toplevel *focus = NULL; + wl_list_for_each(toplevel, &server->toplevels, link) + { + if (!focus && toplevel && toplevel->workspace == &server->workspaces[i]) { + focus = toplevel; /* found it */ + } + + if (toplevel && toplevel->workspace == &server->workspaces[i] && toplevel->fullscreen) { + /* overwrite if there is a fullscreen window */ + focus = toplevel; + break; + } + } + + unfocus_toplevel(server->focused_toplevel); + if (focus) { + /* crazy way to make toplevel focus properly if it was focused before */ + struct wlr_surface *surface; +#ifdef XWAYLAND + if (focus->type == TOPLEVEL_X11) { + surface = focus->xw->surface; + } else +#endif + surface = focus->xdg->base->surface; + + if (surface == server->seat->keyboard_state.focused_surface) { + server->seat->keyboard_state.focused_surface = NULL; + } + + focus_toplevel(focus); + } + + layout_arrange(server->focused_output); +} + +void move_focus_to_workspace(absn_server *server, const absn_arg *arg) +{ + if (!server->focused_toplevel) { + return; + } + + if (server->focused_toplevel->fullscreen) { + toplevel_set_fullscreen(server->focused_toplevel, false); + } + + int i; + for (i = 0; i < server->workspaces_count; ++i) { + if (arg->v == server->workspaces[i].name) { + break; /* found it */ + } + } + + if (&server->workspaces[i] == server->focused_toplevel->workspace) { + return; + } + + if (!server->workspaces[i].output) { + server->workspaces[i].output = server->focused_output; + } + server->focused_toplevel->output = server->workspaces[i].output; + + server->focused_toplevel->workspace = &server->workspaces[i]; + + focus_toplevel(focus_get_topmost(server)); + + layout_arrange(server->focused_output); + layout_arrange(server->focused_toplevel->output); +} + +void set_layout(absn_server *server, const absn_arg *arg) +{ + server->focused_output->workspace->layout = arg->i; + layout_arrange(server->focused_output); +} + +noreturn void quit(absn_server *server, const absn_arg *arg) +{ + UNUSED(arg); + wl_display_terminate(server->display); + exit(EXIT_SUCCESS); +} +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "types.h" + +void handle_modifiers(struct wl_listener *listener, void *data) +{ + UNUSED(data); + absn_keyboard *keyboard = wl_container_of(listener, keyboard, modifiers); + + wlr_seat_set_keyboard(keyboard->server->seat, keyboard->wlr); + wlr_seat_keyboard_notify_modifiers(keyboard->server->seat, &keyboard->wlr->modifiers); +} + +static bool handle_keybind(absn_server *server, uint32_t mods, xkb_keysym_t keysym) +{ + 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)) { + keybinds[i].cb(server, &keybinds[i].arg); + return true; + } + } + return false; +} + +void handle_key(struct wl_listener *listener, void *data) +{ + absn_keyboard *keyboard = wl_container_of(listener, keyboard, key); + struct wlr_keyboard_key_event *event = data; + + /* translate keycode to xkbcommon */ + uint32_t code = event->keycode + 8; + uint32_t mods = wlr_keyboard_get_modifiers(keyboard->wlr); + const xkb_keysym_t *syms; + int nsyms = xkb_state_key_get_syms(keyboard->wlr->xkb_state, code, &syms); + + bool handled = false; + if (event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { + for (int i = 0; i < nsyms; ++i) { + handled = handle_keybind(keyboard->server, mods, syms[i]) || handled; + } + } + + if (handled) { + return; + } + + wlr_seat_set_keyboard(keyboard->server->seat, keyboard->wlr); + wlr_seat_keyboard_notify_key(keyboard->server->seat, event->time_msec, event->keycode, event->state); +} + +void handle_destroy(struct wl_listener *listener, void *data) +{ + UNUSED(data); + absn_keyboard *keyboard = wl_container_of(listener, keyboard, modifiers); + + wl_list_remove(&keyboard->modifiers.link); + wl_list_remove(&keyboard->key.link); + wl_list_remove(&keyboard->destroy.link); + wl_list_remove(&keyboard->link); + + free(keyboard); +} +#include + +#include "layout.h" +#include "output.h" +#include "types.h" + +/* arrange layers logic from dwl */ + +static void layer_arrange(absn_output *output, struct wl_list *list, struct wlr_box *usable_area, int exclusive) +{ + absn_layer_surface *layer_surface; + wl_list_for_each(layer_surface, list, link) + { + struct wlr_layer_surface_v1 *surface = layer_surface->wlr; + + if (!surface->initialized) { + continue; + } + + if (exclusive != (surface->current.exclusive_zone > 0)) { + continue; + } + + 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); + } +} + +void layers_arrange(absn_output *output) +{ + if (!output->wlr->enabled) { + return; + } + + struct wlr_box usable_area = output->usable_area; + + /* Arrange non-exclusive surfaces from top->bottom */ + for (int i = 3; i >= 0; --i) { + layer_arrange(output, &output->layers[i], &usable_area, 1); + } + + if (!wlr_box_equal(&output->usable_area, &usable_area)) { + output->usable_area = usable_area; + output_arrange(output); + } + + /* Arrange non-exclusive surfaces from top->bottom */ + for (int i = 3; i >= 0; --i) { + layer_arrange(output, &output->layers[i], &usable_area, 0); + } + + /* disabled for now + + uint32_t layers_above_shell[] = { + ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, + ZWLR_LAYER_SHELL_V1_LAYER_TOP, + }; + + + int layers_above_shell_count = sizeof(layers_above_shell) / sizeof(layers_above_shell[0]); + absn_layer_surface *layer_surface; + for (int i = 0; i < layers_above_shell_count; ++i) { + wl_list_for_each_reverse(layer_surface, &output->layers[layers_above_shell[i]], link) + { + if (!layer_surface->wlr->current.keyboard_interactive || !layer_surface->mapped) + continue; + + unfocus_toplevel(output->server->focused_toplevel); + output->server->exclusive_focus = l; + client_notify_enter(l->layer_surface->surface, wlr_seat_get_keyboard(seat)); + return; + } + } + + */ +} +#include + +#include "focus.h" +#include "layers.h" +#include "xdg-popup.h" +#include "types.h" + +void layer_surface_unmap(struct wl_listener *listener, void *data) +{ + UNUSED(data); + absn_layer_surface *layer_surface = wl_container_of(listener, layer_surface, unmap); + + if (layer_surface->wlr->surface == layer_surface->server->seat->keyboard_state.focused_surface) { + focus_toplevel(focus_get_topmost(layer_surface->server)); + } + + layer_surface->mapped = false; +} + +void layer_surface_commit(struct wl_listener *listener, void *data) +{ + UNUSED(data); + absn_layer_surface *layer_surface = wl_container_of(listener, layer_surface, commit); + struct wlr_layer_surface_v1 *surface = layer_surface->wlr; + struct wlr_scene_tree *scene_layer = layer_surface->server->layers[layermap[surface->current.layer]]; + + if (surface->initial_commit) { + struct wlr_layer_surface_v1_state old_state = surface->current; + surface->current = surface->pending; + layers_arrange(layer_surface->output); + surface->current = old_state; + return; + } + + if (surface->current.committed == 0 || layer_surface->mapped == surface->surface->mapped) { + return; + } + layer_surface->mapped = surface->surface->mapped; + + if (scene_layer != layer_surface->scene_tree->node.parent) { + wlr_scene_node_reparent(&layer_surface->scene_tree->node, scene_layer); + wl_list_remove(&layer_surface->link); + wl_list_insert(&layer_surface->output->layers[surface->current.layer], &layer_surface->link); + bool on_top_layer = surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP; + if (on_top_layer) { + wlr_scene_node_reparent(&layer_surface->popups->node, layer_surface->output->server->layers[LAYER_TOP]); + } else { + wlr_scene_node_reparent(&layer_surface->popups->node, scene_layer); + } + } + + layers_arrange(layer_surface->output); +} + +void layer_surface_new_popup(struct wl_listener *listener, void *data) +{ + UNUSED(data); + absn_layer_surface *layer_surface = wl_container_of(listener, layer_surface, new_popup); + struct wlr_xdg_popup *xdg_popup = data; + + wlr_scene_xdg_surface_create(layer_surface->popups, xdg_popup->base); + + absn_popup *popup = calloc(1, sizeof(*popup)); + popup->wlr = xdg_popup; + popup->parent_type = LAYER_SURFACE; + popup->parent = layer_surface; + + LISTEN(popup->commit, xdg_popup_commit, xdg_popup->base->surface->events.commit); +} + +void layer_surface_destroy(struct wl_listener *listener, void *data) +{ + UNUSED(data); + absn_layer_surface *layer_surface = wl_container_of(listener, layer_surface, destroy); + + wl_list_remove(&layer_surface->link); + wl_list_remove(&layer_surface->map.link); + wl_list_remove(&layer_surface->unmap.link); + wl_list_remove(&layer_surface->commit.link); + wl_list_remove(&layer_surface->new_popup.link); + wl_list_remove(&layer_surface->destroy.link); + wlr_scene_node_destroy(&layer_surface->scene_tree->node); + + free(layer_surface); +} +#include + +#include "config.h" +#include "output.h" +#include "toplevel.h" +#include "types.h" + +/* returns number of toplevels on workspace */ +static int prepare_output(struct absn_output *output) +{ + int res = 0; + absn_toplevel *toplevel; + wl_list_for_each(toplevel, &output->server->toplevels, link) + { + if (toplevel->workspace == output->workspace) { + wlr_scene_node_set_enabled(&toplevel->scene_tree->node, true); + if (!toplevel->floating && !toplevel->fullscreen) { + res++; + } + } else if (toplevel->output == output && toplevel->workspace != output->workspace) { + wlr_scene_node_set_enabled(&toplevel->scene_tree->node, false); + } + } + + return res; +} + +static void tile(struct absn_output *output) +{ + int toplevels_count = prepare_output(output); + + if (toplevels_count < 1) { + return; + } + + int32_t og = OUTPUT_GAP; + struct wlr_box new_geom; + + absn_toplevel *toplevel; + if (toplevels_count == 1) { + wl_list_for_each(toplevel, &output->server->toplevels, link) + { + if (toplevel->workspace == output->workspace && !toplevel->floating && !toplevel->fullscreen) { + 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, + + toplevel_set_geom(toplevel, &new_geom); + return; + } + + int32_t lg = LAYOUT_GAP; + int32_t total_lg; + + 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 w = output->usable_area.width - main_stack_width - 2 * og - lg; + + int32_t pure_h; + int32_t h; + int32_t cur_h; + int32_t r; + + int32_t dy = og; + int i = 0; + + if (toplevels_count <= mcount) { + total_lg = (toplevels_count - 1) * lg; + pure_h = output->usable_area.height - 2 * og - total_lg; + h = pure_h / toplevels_count; + r = pure_h % toplevels_count; + + wl_list_for_each(toplevel, &output->server->toplevels, link) + { + if (toplevel->workspace != output->workspace || toplevel->floating || toplevel->fullscreen) { + continue; + } + + cur_h = h + (i < r ? 1 : 0); + + new_geom.x = output->usable_area.x + og; + new_geom.y = output->usable_area.y + dy; + new_geom.width = main_stack_width; + new_geom.height = cur_h; + + toplevel_set_geom(toplevel, &new_geom); + + dy += cur_h + lg; + + i++; + } + return; + } + + wl_list_for_each(toplevel, &output->server->toplevels, link) + { + if (toplevel->workspace != output->workspace || toplevel->floating || toplevel->fullscreen) { + continue; + } + + if (i < mcount) { + total_lg = (mcount - 1) * lg; + pure_h = output->usable_area.height - 2 * og - total_lg; + h = pure_h / mcount; + r = pure_h % mcount; + + cur_h = h + (i < r ? 1 : 0); + + new_geom.x = output->usable_area.x + og; + new_geom.y = output->usable_area.y + dy; + new_geom.width = main_stack_width; + new_geom.height = cur_h; + + toplevel_set_geom(toplevel, &new_geom); + + dy += cur_h + lg; + } else { + if (i == mcount) { + dy = og; + } + + int32_t stack_count = toplevels_count - mcount; + total_lg = (stack_count - 1) * lg; + pure_h = output->usable_area.height - 2 * og - total_lg; + h = pure_h / stack_count; + r = pure_h % stack_count; + + cur_h = h + (i - mcount < r ? 1 : 0); + + new_geom.x = output->usable_area.x + main_stack_width + lg + og; + new_geom.y = output->usable_area.y + dy; + new_geom.width = w; + new_geom.height = cur_h; + + toplevel_set_geom(toplevel, &new_geom); + + dy += cur_h + lg; + } + + i++; + } +} + +static void tile_left(struct absn_output *output) +{ + int toplevels_count = prepare_output(output); + + if (toplevels_count < 1) { + return; + } + + int32_t og = OUTPUT_GAP; + struct wlr_box new_geom; + + absn_toplevel *toplevel; + if (toplevels_count == 1) { + wl_list_for_each(toplevel, &output->server->toplevels, link) + { + if (toplevel->workspace == output->workspace && !toplevel->floating && !toplevel->fullscreen) { + 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, + + toplevel_set_geom(toplevel, &new_geom); + return; + } + + int32_t lg = LAYOUT_GAP; + int32_t total_lg; + + 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 w = output->usable_area.width - main_stack_width - 2 * og - lg; + + int32_t pure_h; + int32_t h; + int32_t cur_h; + int32_t r; + + int32_t dy = og; + int i = 0; + + if (toplevels_count <= mcount) { + total_lg = (toplevels_count - 1) * lg; + pure_h = output->usable_area.height - 2 * og - total_lg; + h = pure_h / toplevels_count; + r = pure_h % toplevels_count; + + wl_list_for_each(toplevel, &output->server->toplevels, link) + { + if (toplevel->workspace != output->workspace || toplevel->floating || toplevel->fullscreen) { + continue; + } + + cur_h = h + (i < r ? 1 : 0); + + new_geom.x = output->usable_area.x + og; + new_geom.y = output->usable_area.y + dy; + new_geom.width = main_stack_width; + new_geom.height = cur_h; + + toplevel_set_geom(toplevel, &new_geom); + + dy += cur_h + lg; + + i++; + } + return; + } + + wl_list_for_each(toplevel, &output->server->toplevels, link) + { + if (toplevel->workspace != output->workspace || toplevel->floating || toplevel->fullscreen) { + continue; + } + + if (i < mcount) { + total_lg = (mcount - 1) * lg; + pure_h = output->usable_area.height - 2 * og - total_lg; + h = pure_h / mcount; + r = pure_h % mcount; + + cur_h = h + (i < r ? 1 : 0); + + new_geom.x = output->usable_area.x + output->usable_area.width - og - main_stack_width; + new_geom.y = output->usable_area.y + dy; + new_geom.width = main_stack_width; + new_geom.height = cur_h; + + toplevel_set_geom(toplevel, &new_geom); + + dy += cur_h + lg; + } else { + if (i == mcount) { + dy = og; + } + + int32_t stack_count = toplevels_count - mcount; + total_lg = (stack_count - 1) * lg; + pure_h = output->usable_area.height - 2 * og - total_lg; + h = pure_h / stack_count; + r = pure_h % stack_count; + + cur_h = h + (i - mcount < r ? 1 : 0); + + new_geom.x = output->usable_area.x + og; + new_geom.y = output->usable_area.y + dy; + new_geom.width = w; + new_geom.height = cur_h; + + toplevel_set_geom(toplevel, &new_geom); + + dy += cur_h + lg; + } + + i++; + } +} + +static void monocle(struct absn_output *output) +{ + int toplevels_count = prepare_output(output); + + if (toplevels_count < 1) { + return; + } + + int32_t og = OUTPUT_GAP; + + struct wlr_box new_geom = { + .x = output->usable_area.x + og, + .y = output->usable_area.y + og, + .width = output->usable_area.width - 2 * og, + .height = output->usable_area.height - 2 * og, + }; + + absn_toplevel *toplevel; + wl_list_for_each(toplevel, &output->server->toplevels, link) + { + if (toplevel->workspace != output->workspace || toplevel->floating || toplevel->fullscreen) { + continue; + } + + toplevel_set_geom(toplevel, &new_geom); + } +} + +void layout_arrange(struct absn_output *output) +{ + if (!output) { + return; + } + + switch (output->workspace->layout) { + case LAYOUT_TILE: + tile(output); + break; + case LAYOUT_TILELEFT: + tile_left(output); + break; + case LAYOUT_MONOCLE: + monocle(output); + break; + default: /* currently not implemented layouts */ + tile(output); + break; + } +} +#include +#include + +#include "focus.h" +#include "layout.h" +#include "toplevel.h" +#include "types.h" + +void output_frame(struct wl_listener *listener, void *data) +{ + UNUSED(data); + struct timespec now; + absn_output *output = wl_container_of(listener, output, frame); + + struct wlr_scene *scene = output->server->scene; + struct wlr_scene_output *scene_output = wlr_scene_get_scene_output(scene, output->wlr); + // absn_toplevel *toplevel; + // wl_list_for_each(toplevel, &output->server->toplevels, link) + // { + // if (toplevel->resizing && 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); +} + +void output_request_state(struct wl_listener *listener, void *data) +{ + struct absn_output *output = wl_container_of(listener, output, request_state); + const struct wlr_output_event_request_state *event = data; + wlr_output_commit_state(output->wlr, event->state); +} + +void output_destroy(struct wl_listener *listener, void *data) +{ + UNUSED(data); + struct absn_output *output = wl_container_of(listener, output, request_state); + + wl_list_remove(&output->frame.link); + wl_list_remove(&output->request_state.link); + wl_list_remove(&output->destroy.link); + wl_list_remove(&output->link); + free(output); +} + +void output_layout_change(struct wl_listener *listener, void *data) +{ + UNUSED(data); + absn_server *server = wl_container_of(listener, server, layout_change); + struct wlr_output_configuration_v1 *config = wlr_output_configuration_v1_create(); + + absn_toplevel *toplevel = NULL; + absn_output *output; + struct wlr_output_configuration_head_v1 *config_head; + + wl_list_for_each(output, &server->outputs, link) + { + if (output->wlr->enabled) { + continue; + } + config_head = wlr_output_configuration_head_v1_create(config, output->wlr); + config_head->state.enabled = 0; + wlr_output_layout_remove(server->output_layout, output->wlr); + + // closemon(m); + output->geom = output->usable_area = (struct wlr_box){0}; + } + + wl_list_for_each(output, &server->outputs, link) + { + if (output->wlr->enabled && !wlr_output_layout_get(server->output_layout, output->wlr)) { + wlr_output_layout_add_auto(server->output_layout, toplevel->output->wlr); + } + } + + struct wlr_box layout_geom; + wlr_output_layout_get_box(server->output_layout, NULL, &layout_geom); + + wlr_scene_node_set_position(&server->bg->node, layout_geom.x, layout_geom.y); + wlr_scene_rect_set_size(server->bg, layout_geom.width, layout_geom.height); + + wl_list_for_each(output, &server->outputs, link) + { + if (!output->wlr->enabled) { + continue; + } + config_head = wlr_output_configuration_head_v1_create(config, output->wlr); + + wlr_output_layout_get_box(server->output_layout, output->wlr, &output->geom); + output->usable_area = output->geom; + + if ((toplevel = focus_get_topmost(server)) && toplevel->fullscreen) { + toplevel_set_size(toplevel, output->geom.width, output->geom.height); + } + + config_head->state.x = output->geom.x; + config_head->state.y = output->geom.y; + + if (!server->focused_output) { + server->focused_output = output; + } + } + + if (server->focused_output && server->focused_output->wlr->enabled) { + wl_list_for_each(toplevel, &server->toplevels, link) + { + if (!toplevel->output) { + toplevel->output = server->focused_output; + } + } + layout_arrange(server->focused_output); + } + + focus_toplevel(focus_get_topmost(server)); + wlr_cursor_move(server->cursor, NULL, 0, 0); + wlr_output_manager_v1_set_configuration(server->output_mgr, config); +} + +void update_focused_output(absn_server *server) +{ + absn_output *output; + int32_t cursor_x = server->cursor->x; + int32_t cursor_y = server->cursor->y; + wl_list_for_each(output, &server->outputs, link) + { + bool cursor_in_output_x = cursor_x >= output->geom.x && cursor_x <= output->geom.x + output->geom.width; + bool cursor_in_output_y = cursor_y >= output->geom.y && cursor_y <= output->geom.y + output->geom.height; + if (cursor_in_output_x && cursor_in_output_y) { + server->focused_output = output; + break; + } + } +} + +void +output_arrange(absn_output *output) +{ + if (!output->wlr->enabled) + return; + absn_server *server = output->server; + bool enabled; + absn_toplevel *toplevel; + wl_list_for_each(toplevel, &server->toplevels, link) { + if (toplevel->output == output) { + enabled = output->workspace == toplevel->workspace; + wlr_scene_node_set_enabled(&toplevel->scene_tree->node, enabled); + } + } + + wl_list_for_each(toplevel, &server->toplevels, link) { + if (toplevel->output != output || toplevel->scene_tree->node.parent == server->layers[LAYER_FULLSCREEN]) { + continue; + } + wlr_scene_node_reparent(&toplevel->scene_tree->node, toplevel->scene_tree->node.parent); + } +} +#include +#include + +#include "types.h" + +void request_cursor(struct wl_listener *listener, void *data) +{ + absn_server *server = wl_container_of(listener, server, request_cursor); + struct wlr_seat_pointer_request_set_cursor_event *event = data; + struct wlr_seat_client *client = server->seat->pointer_state.focused_client; + + if (client == event->seat_client) { + wlr_cursor_set_surface(server->cursor, event->surface, event->hotspot_x, event->hotspot_y); + } +} + +void pointer_focus_change(struct wl_listener *listener, void *data) +{ + absn_server *server = wl_container_of(listener, server, pointer_focus_change); + struct wlr_seat_pointer_focus_change_event *event = data; + + if (!event->new_surface) { + wlr_cursor_set_xcursor(server->cursor, server->cursor_mgr, "default"); + } +} + +void request_set_selection(struct wl_listener *listener, void *data) +{ + absn_server *server = wl_container_of(listener, server, request_set_selection); + struct wlr_seat_request_set_selection_event *event = data; + + wlr_seat_set_selection(server->seat, event->source, event->serial); +} +#include +#include +#include +#include +#include + +#include "config.h" +#include "cursor.h" +#include "focus.h" +#include "keyboard.h" +#include "layers.h" +#include "layer-surface.h" +#include "output.h" +#include "xdg-popup.h" +#include "toplevel-handlers.h" +#include "toplevel.h" +#include "types.h" +#include "xdg-decoration.h" +#include "xdg-toplevel.h" + +#ifdef XWAYLAND +#include + +#include "xwayland.h" +#endif + +void new_output(struct wl_listener *listener, void *data) +{ + absn_server *server = wl_container_of(listener, server, new_output); + struct wlr_output *wlr_output = data; + + wlr_output_init_render(wlr_output, server->allocator, server->renderer); + + struct wlr_output_state state; + wlr_output_state_init(&state); + wlr_output_state_set_enabled(&state, true); + + struct wlr_output_mode *mode = wlr_output_preferred_mode(wlr_output); + if (mode) { + wlr_output_state_set_mode(&state, mode); + } + + wlr_output_commit_state(wlr_output, &state); + wlr_output_state_finish(&state); + + struct absn_output *output = calloc(1, sizeof(*output)); + output->wlr = wlr_output; + output->server = server; + + for (int i = 0; i < server->workspaces_count; ++i) { + if (!server->workspaces[i].output) { + server->workspaces[i].output = output; + output->workspace = &server->workspaces[i]; + break; + } + } + + LISTEN(output->frame, output_frame, wlr_output->events.frame); + LISTEN(output->request_state, output_request_state, wlr_output->events.request_state); + LISTEN(output->destroy, output_destroy, wlr_output->events.destroy); + + wl_list_insert(&server->outputs, &output->link); + + for (int i = 0; i < 4; ++i) { + wl_list_init(&output->layers[i]); + } + + struct wlr_output_layout_output *l_layout = wlr_output_layout_add_auto(server->output_layout, output->wlr); + struct wlr_scene_output *scene_output = wlr_scene_output_create(server->scene, wlr_output); + wlr_scene_output_layout_add_output(server->scene_layout, l_layout, scene_output); + wlr_output_layout_get_box(server->output_layout, output->wlr, &output->geom); + output->usable_area = output->geom; +} + +void new_xdg_toplevel(struct wl_listener *listener, void *data) +{ + absn_server *server = wl_container_of(listener, server, new_xdg_toplevel); + struct wlr_xdg_toplevel *xdg_toplevel = data; + + absn_toplevel *toplevel = calloc(1, sizeof(*toplevel)); + toplevel->type = TOPLEVEL_XDG; + toplevel->server = server; + toplevel->xdg = xdg_toplevel; + toplevel->xdg->base->data = toplevel; + toplevel->xdg->base->surface->data = toplevel; + + wlr_surface_set_preferred_buffer_scale(toplevel->xdg->base->surface, 1); + + LISTEN(toplevel->commit, toplevel_commit, xdg_toplevel->base->surface->events.commit); + LISTEN(toplevel->map, toplevel_map, xdg_toplevel->base->surface->events.map); + LISTEN(toplevel->unmap, toplevel_unmap, xdg_toplevel->base->surface->events.unmap); + LISTEN(toplevel->destroy, toplevel_destroy, xdg_toplevel->events.destroy); + LISTEN(toplevel->request_move, toplevel_request_move, xdg_toplevel->events.request_move); + LISTEN(toplevel->request_resize, toplevel_request_resize, xdg_toplevel->events.request_resize); + LISTEN(toplevel->request_maximize, toplevel_request_maximize, xdg_toplevel->events.request_maximize); + LISTEN(toplevel->request_fullscreen, toplevel_request_fullscreen, xdg_toplevel->events.request_fullscreen); +} + +void new_xdg_popup(struct wl_listener *listener, void *data) +{ + absn_server *server = wl_container_of(listener, server, new_xdg_popup); + struct wlr_xdg_popup *xdg_popup = data; + + struct wlr_xdg_surface *parent = wlr_xdg_surface_try_from_wlr_surface(xdg_popup->parent); + if (!parent) { + return; + } + absn_toplevel *toplevel = parent->data; + + wlr_scene_xdg_surface_create(toplevel->scene_tree, xdg_popup->base); + + absn_popup *popup = calloc(1, sizeof(*popup)); + popup->wlr = xdg_popup; + popup->parent_type = TOPLEVEL_XDG; + popup->parent = toplevel; + + LISTEN(popup->commit, xdg_popup_commit, xdg_popup->base->surface->events.commit); +} + +void new_xdg_decoration(struct wl_listener *listener, void *data) +{ + UNUSED(listener); + struct wlr_xdg_toplevel_decoration_v1 *deco = data; + absn_toplevel *toplevel = deco->toplevel->base->data; + toplevel->deco = deco; + + LISTEN(toplevel->deco_request_mode, deco_request_mode, deco->events.request_mode); + LISTEN(toplevel->deco_destroy, deco_destroy, deco->events.destroy); + + /* Forse server side decoration mode */ + deco_request_mode(&toplevel->deco_request_mode, toplevel->deco); +} + +void new_layer_surface(struct wl_listener *listener, void *data) +{ + absn_server *server = wl_container_of(listener, server, new_layer_surface); + struct wlr_layer_surface_v1 *surface = data; + + if (!surface->output && !(surface->output = server->focused_output->wlr)) { + wlr_layer_surface_v1_destroy(surface); + return; + } + + absn_layer_surface *layer_surface = calloc(1, sizeof(*layer_surface)); + + LISTEN(layer_surface->unmap, layer_surface_unmap, surface->surface->events.unmap); + LISTEN(layer_surface->commit, layer_surface_commit, surface->surface->events.commit); + LISTEN(layer_surface->new_popup, layer_surface_new_popup, surface->events.new_popup); + LISTEN(layer_surface->destroy, layer_surface_destroy, surface->surface->events.destroy); + + layer_surface->wlr = surface; + layer_surface->output = surface->output->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); + + wl_list_insert(&layer_surface->output->layers[surface->pending.layer], &layer_surface->link); + wlr_surface_send_enter(surface->surface, surface->output); +} + +#ifdef XWAYLAND +void xwayland_ready(struct wl_listener *listener, void *data) +{ + UNUSED(data); + absn_server *server = wl_container_of(listener, server, xw_ready); + + wlr_xwayland_set_seat(server->xwayland, server->seat); + + struct wlr_xcursor *xcursor; + if ((xcursor = wlr_xcursor_manager_get_xcursor(server->cursor_mgr, "default", 1))) { + struct wlr_buffer *buffer = wlr_xcursor_image_get_buffer(xcursor->images[0]); + wlr_xwayland_set_cursor(server->xwayland, buffer, xcursor->images[0]->hotspot_x, xcursor->images[0]->hotspot_y); + } +} + +void xwayland_new_surface(struct wl_listener *listener, void *data) +{ + absn_server *server = wl_container_of(listener, server, xw_new_surface); + struct wlr_xwayland_surface *surface = data; + absn_toplevel *toplevel = calloc(1, sizeof(*toplevel)); + + toplevel->type = TOPLEVEL_X11; + toplevel->server = server; + toplevel->xw = surface; + toplevel->bw = toplevel_is_unmanaged(toplevel) ? 0 : TOPLEVEL_BW; + surface->data = toplevel; + + LISTEN(toplevel->destroy, toplevel_destroy, surface->events.destroy); + LISTEN(toplevel->request_maximize, toplevel_request_maximize, surface->events.request_maximize); + LISTEN(toplevel->request_fullscreen, toplevel_request_fullscreen, surface->events.request_fullscreen); + + LISTEN(toplevel->xw_activate, xwayland_activate, surface->events.request_activate); + LISTEN(toplevel->xw_associate, xwayland_associate, surface->events.associate); + LISTEN(toplevel->xw_dissociate, xwayland_dissociate, surface->events.dissociate); + LISTEN(toplevel->xw_configure, xwayland_configure, surface->events.request_configure); + LISTEN(toplevel->xw_set_hints, xwayland_set_hints, surface->events.set_hints); +} +#endif + +void cursor_motion(struct wl_listener *listener, void *data) +{ + absn_server *server = wl_container_of(listener, server, cursor_motion); + struct wlr_pointer_motion_event *event = data; + update_focused_output(server); + wlr_cursor_move(server->cursor, &event->pointer->base, event->delta_x, event->delta_y); + process_cursor_motion(server, event->time_msec); +} + +void cursor_motion_abs(struct wl_listener *listener, void *data) +{ + absn_server *server = wl_container_of(listener, server, cursor_motion_abs); + struct wlr_pointer_motion_absolute_event *event = data; + update_focused_output(server); + wlr_cursor_warp_absolute(server->cursor, &event->pointer->base, event->x, event->y); + process_cursor_motion(server, event->time_msec); +} + +void cursor_button(struct wl_listener *listener, void *data) +{ + absn_server *server = wl_container_of(listener, server, cursor_button); + struct wlr_pointer_button_event *event = data; + bool handled = false; + + if (event->state == WL_POINTER_BUTTON_STATE_RELEASED) { + reset_cursor_mode(server); + } else { + double sx, sy; + struct wlr_surface *surface = NULL; + absn_toplevel *toplevel = toplevel_at(server, server->cursor->x, server->cursor->y, &surface, &sx, &sy); + + if (!toplevel) { + goto handle; + } + + struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(server->seat); + uint32_t mods = wlr_keyboard_get_modifiers(keyboard); + if (mods & CURSOR_MOD) { + if (event->button == CURSOR_MOVE_BUTTON) { + server->cursor_mode = CURSOR_MOVE; + wlr_cursor_set_xcursor(server->cursor, server->cursor_mgr, "all-scroll"); + handled = true; + } else if (event->button == CURSOR_RESIZE_BUTTON) { + server->cursor_mode = CURSOR_RESIZE; + handled = true; + } + } + + focus_toplevel(toplevel); + server->grab_x = server->cursor->x; + server->grab_y = server->cursor->y; + + int32_t lx, ly; + wlr_scene_node_coords(&toplevel->scene_tree->node, &lx, &ly); + server->grab_geom.x = lx; + server->grab_geom.y = ly; + server->grab_geom.width = toplevel->geom.width; + server->grab_geom.height = toplevel->geom.height; + + if (server->cursor_mode != CURSOR_RESIZE) { + goto handle; + } + + int32_t width = toplevel->xdg->base->geometry.width; + int32_t height = toplevel->xdg->base->geometry.height; + + if (server->grab_x > (lx + width / 2) && server->grab_y > (ly + height / 2)) { + server->resize_corner = BOTTOM_RIGHT; + wlr_cursor_set_xcursor(server->cursor, server->cursor_mgr, "se-resize"); + } else if (server->grab_x < (lx + width / 2) && server->grab_y > (ly + height / 2)) { + server->resize_corner = BOTTOM_LEFT; + wlr_cursor_set_xcursor(server->cursor, server->cursor_mgr, "sw-resize"); + } else if (server->grab_x > (lx + width / 2) && server->grab_y < (ly + height / 2)) { + server->resize_corner = TOP_RIGHT; + wlr_cursor_set_xcursor(server->cursor, server->cursor_mgr, "ne-resize"); + } else { + server->resize_corner = TOP_LEFT; + wlr_cursor_set_xcursor(server->cursor, server->cursor_mgr, "nw-resize"); + } + + wlr_xdg_toplevel_set_resizing(toplevel->xdg, true); + } + +handle: + if (!handled) { + wlr_seat_pointer_notify_button(server->seat, event->time_msec, event->button, event->state); + } +} + +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); +} + +void cursor_frame(struct wl_listener *listener, void *data) +{ + UNUSED(data); + absn_server *server = wl_container_of(listener, server, cursor_frame); + wlr_seat_pointer_notify_frame(server->seat); +} + +static void new_keyboard(absn_server *server, struct wlr_input_device *device) +{ + struct wlr_keyboard *wlr_keyboard = wlr_keyboard_from_input_device(device); + absn_keyboard *keyboard = calloc(1, sizeof(*keyboard)); + keyboard->server = server; + keyboard->wlr = wlr_keyboard; + + struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + struct xkb_keymap *keymap = xkb_keymap_new_from_names(context, NULL, XKB_KEYMAP_COMPILE_NO_FLAGS); + + wlr_keyboard_set_keymap(wlr_keyboard, keymap); + xkb_keymap_unref(keymap); + xkb_context_unref(context); + wlr_keyboard_set_repeat_info(wlr_keyboard, 25, 600); + + LISTEN(keyboard->modifiers, handle_modifiers, wlr_keyboard->events.modifiers); + LISTEN(keyboard->key, handle_key, wlr_keyboard->events.key); + LISTEN(keyboard->destroy, handle_destroy, wlr_keyboard->base.events.destroy); + + wlr_seat_set_keyboard(server->seat, wlr_keyboard); + + wl_list_insert(&server->keyboards, &keyboard->link); +} + +static void new_pointer(absn_server *server, struct wlr_input_device *device) +{ + wlr_cursor_attach_input_device(server->cursor, device); +} + +void new_input(struct wl_listener *listener, void *data) +{ + absn_server *server = wl_container_of(listener, server, new_input); + struct wlr_input_device *device = data; + switch (device->type) { + case WLR_INPUT_DEVICE_KEYBOARD: + new_keyboard(server, device); + break; + case WLR_INPUT_DEVICE_POINTER: + new_pointer(server, device); + default: + break; + } + + uint32_t caps = WL_SEAT_CAPABILITY_POINTER; + if (!wl_list_empty(&server->keyboards)) { + caps |= WL_SEAT_CAPABILITY_KEYBOARD; + } + wlr_seat_set_capabilities(server->seat, caps); +} +#include +#include + +#include "config.h" +#include "layout.h" +#include "toplevel.h" +#include "types.h" +#include "xdg-shell-protocol.h" + +/* + * returns toplevel at given cursor coordinates, + * its surface and coordinates inside of it + * to process input event + */ +absn_toplevel *toplevel_at(absn_server *server, double lx, double ly, struct wlr_surface **surface, double *sx, + double *sy) +{ + struct wlr_scene_node *node = wlr_scene_node_at(&server->scene->tree.node, lx, ly, sx, sy); + if (!node) { + return NULL; + } + + struct wlr_scene_buffer *scene_buffer = NULL; + struct wlr_scene_surface *scene_surface = NULL; + + switch (node->type) { + case WLR_SCENE_NODE_BUFFER: + scene_buffer = wlr_scene_buffer_from_node(node); + scene_surface = wlr_scene_surface_try_from_buffer(scene_buffer); + if (!scene_surface) { + return NULL; + } + + *surface = scene_surface->surface; + struct wlr_scene_tree *tree = node->parent; + while (tree != NULL && tree->node.data == NULL) { + tree = tree->node.parent; + } + return tree->node.data; + break; + case WLR_SCENE_NODE_RECT: + return node->data; + break; + default: + return NULL; + } +} + +/* + * if toplevel is unmanaged we should not + * move or resize it and just draw it + * where it wants + */ +bool toplevel_is_unmanaged(absn_toplevel *toplevel) +{ +#ifdef XWAYLAND + if (toplevel->type == TOPLEVEL_X11) { + return toplevel->xw->override_redirect; + } +#endif + return false; +} + +/* used only to get initial window size */ +void toplevel_get_geom(absn_toplevel *toplevel) +{ +#ifdef XWAYLAND + if (toplevel->type == TOPLEVEL_X11) { + toplevel->geom.x = toplevel->xw->x; + toplevel->geom.y = toplevel->xw->y; + toplevel->geom.width = toplevel->xw->width; + toplevel->geom.height = toplevel->xw->height; + } else +#endif + { + toplevel->geom = toplevel->xdg->base->geometry; + } +} + +static void toplevel_update_borders_geom(absn_toplevel *toplevel) +{ + int32_t bw = toplevel->bw; + + if (toplevel->geom.width - 2 * bw < 0 || toplevel->geom.height - 2 * bw < 0) { + return; + } + + wlr_scene_node_set_position(&toplevel->scene_tree->node, toplevel->geom.x, toplevel->geom.y); + wlr_scene_node_set_position(&toplevel->scene_surface->node, bw, bw); + + wlr_scene_rect_set_size(toplevel->border[0], toplevel->geom.width - 2 * bw, bw); + wlr_scene_rect_set_size(toplevel->border[1], toplevel->geom.width - 2 * bw, bw); + wlr_scene_rect_set_size(toplevel->border[2], bw, toplevel->geom.height); + wlr_scene_rect_set_size(toplevel->border[3], bw, toplevel->geom.height); + + wlr_scene_node_set_position(&toplevel->border[0]->node, bw, 0); + wlr_scene_node_set_position(&toplevel->border[1]->node, bw, toplevel->geom.height - bw); + wlr_scene_node_set_position(&toplevel->border[2]->node, 0, 0); + wlr_scene_node_set_position(&toplevel->border[3]->node, toplevel->geom.width - bw, 0); +} + +void toplevel_set_pos(absn_toplevel *toplevel, int32_t x, int32_t y) +{ + toplevel->geom.x = x; + toplevel->geom.y = y; + wlr_scene_node_set_position(&toplevel->scene_tree->node, x, 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)) { + return; + } + toplevel->geom.width = width; + toplevel->geom.height = height; + + toplevel_update_borders_geom(toplevel); + + int32_t bw = toplevel->bw; + + struct wlr_box clip = { + .x = 0, + .y = 0, + .width = width - bw, + .height = height - bw, + }; + + if (toplevel->type == TOPLEVEL_XDG) { + if (wl_resource_get_version(toplevel->xdg->resource) >= XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION) { + wlr_xdg_toplevel_set_bounds(toplevel->xdg, width, height); + } + toplevel->resizing = wlr_xdg_toplevel_set_size(toplevel->xdg, width - 2 * bw, height - 2 * bw); + } +#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); + /* manually update position */ + toplevel_set_pos(toplevel, toplevel->geom.x, toplevel->geom.y); + } +#endif + + wlr_scene_subsurface_tree_set_clip(&toplevel->scene_surface->node, &clip); +} + +void toplevel_set_geom(absn_toplevel *toplevel, struct wlr_box *geom) +{ + toplevel_set_pos(toplevel, geom->x, geom->y); + toplevel_set_size(toplevel, geom->width, geom->height); +} + +void toplevel_set_floating(absn_toplevel *toplevel, bool floating) +{ + if (!toplevel || toplevel->floating == floating) { + return; + } + + toplevel->floating = floating; + + if (floating) { + wlr_scene_node_reparent(&toplevel->scene_tree->node, toplevel->server->layers[LAYER_FLOAT]); + } else { + wlr_scene_node_reparent(&toplevel->scene_tree->node, toplevel->server->layers[LAYER_TILE]); + } + + layout_arrange(toplevel->output); +} + +void toplevel_set_fullscreen(absn_toplevel *toplevel, bool fullscreen) +{ + if (!toplevel || toplevel->fullscreen == fullscreen) { + return; + } + + absn_output *output = toplevel->server->focused_output; + toplevel->fullscreen = fullscreen; + wlr_xdg_toplevel_set_fullscreen(toplevel->xdg, fullscreen); + + if (fullscreen) { + toplevel->prev_geom = toplevel->geom; + toplevel->bw = 0; + toplevel_set_geom(toplevel, &output->geom); + + wlr_scene_node_reparent(&toplevel->scene_tree->node, toplevel->server->layers[LAYER_FULLSCREEN]); + } else { + toplevel->bw = toplevel_is_unmanaged(toplevel) ? 0 : TOPLEVEL_BW; + toplevel_set_geom(toplevel, &toplevel->prev_geom); + if (toplevel->floating) { + wlr_scene_node_reparent(&toplevel->scene_tree->node, toplevel->server->layers[LAYER_FLOAT]); + } else { + wlr_scene_node_reparent(&toplevel->scene_tree->node, toplevel->server->layers[LAYER_TILE]); + } + } + + toplevel_update_borders_geom(toplevel); + + layout_arrange(toplevel->output); +} + +void toplevel_set_border_color(absn_toplevel *toplevel, const float color[4]) +{ + if (!toplevel) { + return; + } + for (int i = 0; i < 4; ++i) { + wlr_scene_rect_set_color(toplevel->border[i], color); + } +} +#include +#include + +#include "config.h" +#include "focus.h" +#include "layout.h" +#include "output.h" +#include "toplevel.h" + +void toplevel_map(struct wl_listener *listener, void *data) +{ + UNUSED(data); + absn_toplevel *toplevel = wl_container_of(listener, toplevel, map); + absn_server *server = toplevel->server; + + toplevel->scene_tree = wlr_scene_tree_create(server->layers[LAYER_TILE]); + 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) { + 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); + } + + toplevel->bw = toplevel_is_unmanaged(toplevel) ? 0 : TOPLEVEL_BW; + +#ifdef XWAYLAND + if (toplevel->type == TOPLEVEL_X11) { + toplevel->scene_surface = wlr_scene_subsurface_tree_create(toplevel->scene_tree, toplevel->xw->surface); + } else +#endif + { + toplevel->scene_surface = wlr_scene_xdg_surface_create(toplevel->scene_tree, toplevel->xdg->base); + } + toplevel->scene_surface->node.data = toplevel; + + toplevel_get_geom(toplevel); + toplevel->bw = toplevel_is_unmanaged(toplevel) ? 0 : TOPLEVEL_BW; + + 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)); +} + +void toplevel_unmap(struct wl_listener *listener, void *data) +{ + UNUSED(data); + absn_toplevel *toplevel = wl_container_of(listener, toplevel, unmap); + + if (toplevel == toplevel->server->focused_toplevel) { + toplevel->server->focused_toplevel = NULL; + toplevel->server->seat->keyboard_state.focused_surface = NULL; + } + + wl_list_remove(&toplevel->link); + wl_list_remove(&toplevel->flink); + + layout_arrange(toplevel->output); + focus_toplevel(focus_get_topmost(toplevel->server)); + + wlr_scene_node_destroy(&toplevel->scene_tree->node); +} + +void toplevel_destroy(struct wl_listener *listener, void *data) +{ + UNUSED(data); + absn_toplevel *toplevel = wl_container_of(listener, toplevel, destroy); + +#ifdef XWAYLAND + if (toplevel->type == TOPLEVEL_X11) { + wl_list_remove(&toplevel->xw_activate.link); + wl_list_remove(&toplevel->xw_associate.link); + wl_list_remove(&toplevel->xw_dissociate.link); + wl_list_remove(&toplevel->xw_configure.link); + wl_list_remove(&toplevel->xw_set_hints.link); + } else +#endif + { + wl_list_remove(&toplevel->map.link); + wl_list_remove(&toplevel->unmap.link); + wl_list_remove(&toplevel->commit.link); + wl_list_remove(&toplevel->request_move.link); + wl_list_remove(&toplevel->request_resize.link); + } + + wl_list_remove(&toplevel->destroy.link); + wl_list_remove(&toplevel->request_maximize.link); + wl_list_remove(&toplevel->request_fullscreen.link); + + free(toplevel); +} + +void toplevel_request_move(struct wl_listener *listener, void *data) +{ + UNUSED(data); + absn_toplevel *toplevel = wl_container_of(listener, toplevel, request_move); + if (toplevel->xdg->base->initialized) { + wlr_xdg_surface_schedule_configure(toplevel->xdg->base); + } +} + +void toplevel_request_resize(struct wl_listener *listener, void *data) +{ + UNUSED(data); + absn_toplevel *toplevel = wl_container_of(listener, toplevel, request_resize); + if (toplevel->xdg->base->initialized) { + wlr_xdg_surface_schedule_configure(toplevel->xdg->base); + } +} + +void toplevel_request_maximize(struct wl_listener *listener, void *data) +{ + UNUSED(data); + absn_toplevel *toplevel = wl_container_of(listener, toplevel, request_maximize); + if (toplevel->xdg->base->initialized) { + wlr_xdg_surface_schedule_configure(toplevel->xdg->base); + } +} + +void toplevel_request_fullscreen(struct wl_listener *listener, void *data) +{ + UNUSED(data); + absn_toplevel *toplevel = wl_container_of(listener, toplevel, request_fullscreen); + toplevel_set_fullscreen(toplevel, toplevel->xdg->requested.fullscreen); +} +#include + +#include "types.h" + +void deco_request_mode(struct wl_listener *listener, void *data) +{ + UNUSED(data); + absn_toplevel *toplevel = wl_container_of(listener, toplevel, deco_request_mode); + if (toplevel->xdg->base->initialized) { + wlr_xdg_toplevel_decoration_v1_set_mode(toplevel->deco, WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); + } +} + +void deco_destroy(struct wl_listener *listener, void *data) +{ + UNUSED(data); + absn_toplevel *toplevel = wl_container_of(listener, toplevel, deco_destroy); + + wl_list_remove(&toplevel->deco_request_mode.link); + wl_list_remove(&toplevel->deco_destroy.link); +} +#include "types.h" + +void xdg_popup_commit(struct wl_listener *listener, void *data) +{ + UNUSED(data); + absn_popup *popup = wl_container_of(listener, popup, commit); + struct wlr_box box; + + if (popup->parent_type == TOPLEVEL_XDG) { + absn_toplevel *toplevel = popup->parent; + box = toplevel->output->usable_area; + box.x -= toplevel->geom.x; + box.y -= toplevel->geom.y; + } else { + absn_layer_surface *layer_surface = popup->parent; + box = layer_surface->output->geom; + box.x -= layer_surface->popups->node.x; + box.y -= layer_surface->popups->node.y; + } + + wlr_xdg_popup_unconstrain_from_box(popup->wlr, &box); + + wl_list_remove(&popup->commit.link); + free(popup); +} +#include +#include +#include + +#include "types.h" +#include "xdg-decoration.h" + +void toplevel_commit(struct wl_listener *listener, void *data) +{ + UNUSED(data); + absn_toplevel *toplevel = wl_container_of(listener, toplevel, commit); + + if (toplevel->xdg->base->current.configure_serial < toplevel->resizing) { + return; + } + + if (toplevel->xdg->base->initial_commit) { + wlr_xdg_toplevel_set_activated(toplevel->xdg, false); + + /* forse server side decoration mode */ + if (toplevel->deco) { + deco_request_mode(&toplevel->deco_request_mode, toplevel->deco); + } + /* let client set initial size */ + toplevel->resizing = wlr_xdg_toplevel_set_size(toplevel->xdg, 0, 0); + return; + } + + struct wlr_box clip = { + .x = toplevel->xdg->base->geometry.x, + .y = toplevel->xdg->base->geometry.y, + .width = toplevel->geom.width - toplevel->bw, + .height = toplevel->geom.height - toplevel->bw, + }; + wlr_scene_subsurface_tree_set_clip(&toplevel->scene_surface->node, &clip); + + toplevel->resizing = 0; +} +#ifdef XWAYLAND + +#include "xwayland.h" +#include "toplevel-handlers.h" +#include "toplevel.h" +#include "types.h" + +void xwayland_activate(struct wl_listener *listener, void *data) +{ + UNUSED(data); + absn_toplevel *toplevel = wl_container_of(listener, toplevel, xw_activate); + + if (!toplevel_is_unmanaged(toplevel)) { + wlr_xwayland_surface_activate(toplevel->xw, 1); + } +} + +void xwayland_associate(struct wl_listener *listener, void *data) +{ + UNUSED(data); + absn_toplevel *toplevel = wl_container_of(listener, toplevel, xw_associate); + + LISTEN(toplevel->map, toplevel_map, toplevel->xw->surface->events.map); + LISTEN(toplevel->unmap, toplevel_unmap, toplevel->xw->surface->events.unmap); +} + +void xwayland_dissociate(struct wl_listener *listener, void *data) +{ + UNUSED(data); + absn_toplevel *toplevel = wl_container_of(listener, toplevel, xw_dissociate); + + wl_list_remove(&toplevel->map.link); + wl_list_remove(&toplevel->unmap.link); +} + +void xwayland_configure(struct wl_listener *listener, void *data) +{ + UNUSED(data); + absn_toplevel *toplevel = wl_container_of(listener, toplevel, xw_configure); + struct wlr_xwayland_surface_configure_event *event = data; + + if (!toplevel->xw->surface || !toplevel->xw->surface->mapped) { + wlr_xwayland_surface_configure(toplevel->xw, event->x, event->y, event->width, event->height); + return; + } + + if (toplevel_is_unmanaged(toplevel)) { + wlr_scene_node_set_position(&toplevel->scene_tree->node, event->x, event->y); + wlr_xwayland_surface_configure(toplevel->xw, event->x, event->y, event->width, event->height); + return; + } +} + +void xwayland_set_hints(struct wl_listener *listener, void *data) +{ + UNUSED(listener); + UNUSED(data); +} +#endif diff --git a/include/layer-surface.h b/include/layer-surface.h index 7aca707..b8bd2f9 100644 --- a/include/layer-surface.h +++ b/include/layer-surface.h @@ -3,7 +3,6 @@ #include -void layer_surface_map(struct wl_listener *listener, void *data); void layer_surface_unmap(struct wl_listener *listener, void *data); void layer_surface_commit(struct wl_listener *listener, void *data); void layer_surface_new_popup(struct wl_listener *listener, void *data); diff --git a/include/layer.h b/include/layers.h similarity index 71% rename from include/layer.h rename to include/layers.h index 69227d4..8dedabd 100644 --- a/include/layer.h +++ b/include/layers.h @@ -4,6 +4,6 @@ #include "output.h" #include "types.h" -void layer_arrange(absn_output *output); +void layers_arrange(absn_output *output); #endif diff --git a/include/output.h b/include/output.h index a589603..9e92ef9 100644 --- a/include/output.h +++ b/include/output.h @@ -11,5 +11,6 @@ void output_destroy(struct wl_listener *listener, void *data); void output_layout_change(struct wl_listener *listener, void *data); void update_focused_output(absn_server *server); +void output_arrange(absn_output *output); #endif diff --git a/include/toplevel.h b/include/toplevel.h index 55b38fb..f595fa7 100644 --- a/include/toplevel.h +++ b/include/toplevel.h @@ -3,7 +3,8 @@ #include "types.h" -absn_toplevel *toplevel_at(absn_server *server, double lx, double ly, struct wlr_surface **surface, double *sx, +absn_toplevel *toplevel_at(absn_server *server, double lx, double ly, + struct wlr_surface **surface, double *sx, double *sy); bool toplevel_is_unmanaged(absn_toplevel *toplevel); diff --git a/include/types.h b/include/types.h index 36004c3..7ca4985 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) @@ -74,7 +74,7 @@ static const int layermap[] = { LAYER_BACKGROUND, LAYER_BOTTOM, LAYER_TOP, - LAYER_FULLSCREEN, + LAYER_OVERLAY, }; enum { @@ -150,6 +150,8 @@ typedef struct { struct wl_list focus_stack; absn_toplevel *focused_toplevel; + void *exclusive_focus; + absn_output *focused_output; struct wl_list outputs; struct wl_listener new_output; @@ -177,7 +179,7 @@ struct absn_output { struct wl_listener request_state; struct wl_listener destroy; - struct wl_list layer_surfaces; + struct wl_list layers[4]; }; typedef struct { @@ -186,9 +188,10 @@ typedef struct { absn_server *server; absn_output *output; - int type; /* LAYER_SURFACE */ + bool mapped; struct wlr_scene_tree *scene_tree; struct wlr_scene_layer_surface_v1 *scene_layer; + struct wlr_scene_tree *popups; struct wlr_layer_surface_v1 *wlr; struct wl_listener map; @@ -249,8 +252,11 @@ struct absn_toplevel { typedef struct { struct wlr_xdg_popup *wlr; + + int parent_type; + void *parent; + struct wl_listener commit; - struct wl_listener destroy; } absn_popup; typedef struct { diff --git a/include/xdg-popup.h b/include/xdg-popup.h index 89aa862..86b141b 100644 --- a/include/xdg-popup.h +++ b/include/xdg-popup.h @@ -1,9 +1,6 @@ -#ifndef __XDG_POPUP_H_ -#define __XDG_POPUP_H_ - -#include +#ifndef __XDG_POPUP_H +#define __XDG_POPUP_H void xdg_popup_commit(struct wl_listener *listener, void *data); -void xdg_popup_destroy(struct wl_listener *listener, void *data); #endif diff --git a/src/absinthe.c b/src/absinthe.c index 124b093..32c368b 100644 --- a/src/absinthe.c +++ b/src/absinthe.c @@ -33,7 +33,8 @@ static int setup(absn_server *server) return 1; } - server->backend = wlr_backend_autocreate(wl_display_get_event_loop(server->display), NULL); + server->backend = wlr_backend_autocreate( + wl_display_get_event_loop(server->display), NULL); if (!server->backend) { wlr_log(WLR_ERROR, "Failed to create wlr_backend"); return 1; @@ -48,21 +49,25 @@ static int setup(absn_server *server) wlr_renderer_init_wl_shm(server->renderer, server->display); server->scene = wlr_scene_create(); - if (wlr_renderer_get_texture_formats(server->renderer, WLR_BUFFER_CAP_DMABUF)) { + 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); - server->allocator = wlr_allocator_autocreate(server->backend, server->renderer); + server->allocator = + wlr_allocator_autocreate(server->backend, server->renderer); if (!server->allocator) { wlr_log(WLR_ERROR, "Failed to create wlr_allocator"); return 1; } /* wlroots managers */ - server->compositor = wlr_compositor_create(server->display, 6, server->renderer); + server->compositor = + wlr_compositor_create(server->display, 6, server->renderer); wlr_subcompositor_create(server->display); wlr_data_device_manager_create(server->display); wlr_screencopy_manager_v1_create(server->display); @@ -75,10 +80,13 @@ 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); - 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); + 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); /* toplevels lists */ wl_list_init(&server->toplevels); @@ -89,18 +97,22 @@ static int setup(absn_server *server) LISTEN(server->new_output, new_output, server->backend->events.new_output); server->output_layout = wlr_output_layout_create(server->display); - LISTEN(server->layout_change, output_layout_change, server->output_layout->events.change); + LISTEN(server->layout_change, output_layout_change, + server->output_layout->events.change); server->output_mgr = wlr_output_manager_v1_create(server->display); wlr_xdg_output_manager_v1_create(server->display, server->output_layout); - server->scene_layout = wlr_scene_attach_output_layout(server->scene, server->output_layout); + server->scene_layout = + wlr_scene_attach_output_layout(server->scene, server->output_layout); /* xdg_shell */ server->xdg_shell = wlr_xdg_shell_create(server->display, 6); - LISTEN(server->new_xdg_toplevel, new_xdg_toplevel, server->xdg_shell->events.new_toplevel); - LISTEN(server->new_xdg_popup, new_xdg_popup, server->xdg_shell->events.new_popup); + LISTEN(server->new_xdg_toplevel, new_xdg_toplevel, + server->xdg_shell->events.new_toplevel); + LISTEN(server->new_xdg_popup, new_xdg_popup, + server->xdg_shell->events.new_popup); /* cursor */ server->cursor = wlr_cursor_create(); @@ -110,7 +122,8 @@ static int setup(absn_server *server) server->cursor_mode = CURSOR_PASSTHROUGH; LISTEN(server->cursor_motion, cursor_motion, server->cursor->events.motion); - LISTEN(server->cursor_motion_abs, cursor_motion_abs, server->cursor->events.motion_absolute); + LISTEN(server->cursor_motion_abs, cursor_motion_abs, + server->cursor->events.motion_absolute); LISTEN(server->cursor_button, cursor_button, server->cursor->events.button); LISTEN(server->cursor_axis, cursor_axis, server->cursor->events.axis); LISTEN(server->cursor_frame, cursor_frame, server->cursor->events.frame); @@ -119,14 +132,18 @@ static int setup(absn_server *server) wl_list_init(&server->keyboards); server->seat = wlr_seat_create(server->display, "seat0"); LISTEN(server->new_input, new_input, server->backend->events.new_input); - LISTEN(server->request_cursor, request_cursor, server->seat->events.request_set_cursor); - LISTEN(server->pointer_focus_change, pointer_focus_change, server->seat->pointer_state.events.focus_change); - LISTEN(server->request_set_selection, request_cursor, server->seat->events.request_set_selection); + LISTEN(server->request_cursor, request_cursor, + server->seat->events.request_set_cursor); + LISTEN(server->pointer_focus_change, pointer_focus_change, + server->seat->pointer_state.events.focus_change); + LISTEN(server->request_set_selection, request_cursor, + server->seat->events.request_set_selection); /* layer shell */ - server->layer_shell = wlr_layer_shell_v1_create(server->display, 1); - for (int i = 0; i < LAYERS_COUNT; ++i) + server->layer_shell = wlr_layer_shell_v1_create(server->display, 5); + for (int i = 0; i < LAYERS_COUNT; ++i) { server->layers[i] = wlr_scene_tree_create(&server->scene->tree); + } /* workspaces */ int workspaces_count = sizeof(workspaces) / sizeof(workspaces[0]); @@ -142,12 +159,16 @@ static int setup(absn_server *server) unsetenv("DISPLAY"); #ifdef XWAYLAND - if ((server->xwayland = wlr_xwayland_create(server->display, server->compositor, 1))) { - LISTEN(server->xw_ready, xwayland_ready, server->xwayland->events.ready); - LISTEN(server->xw_new_surface, xwayland_new_surface, server->xwayland->events.new_surface); + if ((server->xwayland = + wlr_xwayland_create(server->display, server->compositor, 1))) { + LISTEN(server->xw_ready, xwayland_ready, + server->xwayland->events.ready); + LISTEN(server->xw_new_surface, xwayland_new_surface, + server->xwayland->events.new_surface); setenv("DISPLAY", server->xwayland->display_name, 1); - wlr_log(WLR_INFO, "Running XWayland, DISPLAY=%s", server->xwayland->display_name); + wlr_log(WLR_INFO, "Running XWayland, DISPLAY=%s", + server->xwayland->display_name); } else { wlr_log(WLR_ERROR, "Failed to setup XWayland, continuing without it"); } @@ -209,8 +230,9 @@ int main(void) { absn_server server = {0}; int err = setup(&server); - if (err) + if (err) { return EXIT_FAILURE; + } wl_display_run(server.display); cleanup(&server); return EXIT_SUCCESS; diff --git a/src/cursor.c b/src/cursor.c index 85443af..8605051 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -18,8 +18,9 @@ static void process_cursor_move(absn_server *server) { struct absn_toplevel *toplevel = server->focused_toplevel; - if (!toplevel) + if (!toplevel) { return; + } if (toplevel->fullscreen) { toplevel->prev_geom = toplevel->geom; @@ -31,8 +32,9 @@ static void process_cursor_move(absn_server *server) new_y = server->cursor->y - server->grab_y + server->grab_geom.y; toplevel_set_pos(toplevel, new_x, new_y); - if (!toplevel->floating) + if (!toplevel->floating) { toplevel_set_floating(toplevel, true); + } } static void apply_resize(absn_toplevel *toplevel, struct wlr_box *new_geom) @@ -44,18 +46,21 @@ static void apply_resize(absn_toplevel *toplevel, struct wlr_box *new_geom) int32_t max_width = toplevel->xdg->current.max_width; int32_t max_height = toplevel->xdg->current.max_height; - if (max_width == 0) + if (max_width == 0) { max_width = 10000; + } - if (max_height == 0) + if (max_height == 0) { max_height = 10000; + } if (!(new_geom->width >= min_width && new_geom->width <= max_width)) { new_geom->width = toplevel->geom.width; new_geom->x = toplevel->geom.x; } - if (!(new_geom->height >= min_height && new_geom->height <= max_height)) { + if (!(new_geom->height >= min_height && + new_geom->height <= max_height)) { new_geom->height = toplevel->geom.height; new_geom->y = toplevel->geom.y; } @@ -68,17 +73,21 @@ static void process_cursor_resize(absn_server *server) { struct absn_toplevel *toplevel = server->focused_toplevel; - if (!toplevel) + if (!toplevel) { return; + } - if (toplevel->resizing) + if (toplevel->resizing) { return; + } - if (toplevel->fullscreen) + if (toplevel->fullscreen) { toplevel_set_fullscreen(toplevel, false); + } - if (!toplevel->floating) + if (!toplevel->floating) { toplevel_set_floating(toplevel, true); + } int32_t new_x, new_y, new_width, new_height; new_x = server->grab_geom.x; @@ -89,8 +98,9 @@ static void process_cursor_resize(absn_server *server) int32_t dx = server->cursor->x - server->grab_x; int32_t dy = server->cursor->y - server->grab_y; - if (dx == 0 && dy == 0) + if (dx == 0 && dy == 0) { return; + } switch (server->resize_corner) { case TOP_LEFT: @@ -133,7 +143,8 @@ void process_cursor_motion(absn_server *server, uint32_t time) { double sx, sy; struct wlr_surface *surface = NULL; - toplevel_at(server, server->cursor->x, server->cursor->y, &surface, &sx, &sy); + toplevel_at(server, server->cursor->x, server->cursor->y, &surface, &sx, + &sy); struct wlr_seat *seat = server->seat; if (server->cursor_mode == CURSOR_MOVE) { diff --git a/src/focus.c b/src/focus.c index 54980f4..5dd8e77 100644 --- a/src/focus.c +++ b/src/focus.c @@ -8,35 +8,40 @@ void unfocus_toplevel(absn_toplevel *toplevel) { - if (!toplevel) + if (!toplevel) { return; + } - if (toplevel->type == TOPLEVEL_XDG) + if (toplevel->type == TOPLEVEL_XDG) { wlr_xdg_toplevel_set_activated(toplevel->xdg, false); + } toplevel_set_border_color(toplevel, unfocused_bc); } void focus_toplevel(absn_toplevel *toplevel) { - if (!toplevel) + if (!toplevel) { return; + } absn_server *server = toplevel->server; struct wlr_seat *seat = server->seat; struct wlr_surface *prev_surface = seat->keyboard_state.focused_surface; struct wlr_surface *surface; #ifdef XWAYLAND - if (toplevel->type == TOPLEVEL_X11) + if (toplevel->type == TOPLEVEL_X11) { surface = toplevel->xw->surface; - else + } else #endif surface = toplevel->xdg->base->surface; - if (surface == prev_surface) + if (surface == prev_surface) { return; + } - if (prev_surface) + if (prev_surface) { unfocus_toplevel(prev_surface->data); + } toplevel->server->focused_toplevel = toplevel; @@ -44,12 +49,16 @@ void focus_toplevel(absn_toplevel *toplevel) wlr_scene_node_raise_to_top(&toplevel->scene_tree->node); wl_list_remove(&toplevel->flink); wl_list_insert(&server->focus_stack, &toplevel->flink); - if (toplevel->type != TOPLEVEL_X11) + if (toplevel->type != TOPLEVEL_X11) { wlr_xdg_toplevel_set_activated(toplevel->xdg, true); + } toplevel_set_border_color(toplevel, focused_bc); - if (keyboard) - wlr_seat_keyboard_notify_enter(seat, surface, keyboard->keycodes, keyboard->num_keycodes, &keyboard->modifiers); + if (keyboard) { + wlr_seat_keyboard_notify_enter(seat, surface, keyboard->keycodes, + keyboard->num_keycodes, + &keyboard->modifiers); + } } /* @@ -61,8 +70,10 @@ absn_toplevel *focus_get_topmost(absn_server *server) absn_toplevel *toplevel; wl_list_for_each(toplevel, &server->focus_stack, flink) { - if (toplevel && toplevel->workspace == server->focused_output->workspace) + if (toplevel && + toplevel->workspace == server->focused_output->workspace) { return toplevel; + } } return NULL; } diff --git a/src/keybinds.c b/src/keybinds.c index 80f78d0..09004d5 100644 --- a/src/keybinds.c +++ b/src/keybinds.c @@ -21,8 +21,9 @@ void run(absn_server *server, const absn_arg *arg) void kill_focus(absn_server *server, const absn_arg *arg) { UNUSED(arg); - if (!server->focused_toplevel) + if (!server->focused_toplevel) { return; + } absn_toplevel *focus = server->focused_toplevel; @@ -39,21 +40,24 @@ void kill_focus(absn_server *server, const absn_arg *arg) void cycle_focus(absn_server *server, const absn_arg *arg) { absn_toplevel *toplevel = focus_get_topmost(server); - if (!toplevel || toplevel->fullscreen) + if (!toplevel || toplevel->fullscreen) { return; + } absn_toplevel *new_focus; if (arg->i > 0) { wl_list_for_each(new_focus, &toplevel->link, link) { - if (toplevel->workspace == new_focus->workspace) + if (toplevel->workspace == new_focus->workspace) { break; + } } } else { wl_list_for_each_reverse(new_focus, &toplevel->link, link) { - if (toplevel->workspace == new_focus->workspace) + if (toplevel->workspace == new_focus->workspace) { break; + } } } focus_toplevel(new_focus); @@ -63,8 +67,9 @@ void swap_focus(absn_server *server, const absn_arg *arg) { absn_toplevel *toplevel = focus_get_topmost(server); - if (!toplevel || toplevel->fullscreen || toplevel->floating) + if (!toplevel || toplevel->fullscreen || toplevel->floating) { return; + } absn_toplevel *temp = NULL; absn_toplevel *first = NULL; @@ -72,14 +77,17 @@ void swap_focus(absn_server *server, const absn_arg *arg) wl_list_for_each(temp, &server->toplevels, link) { - if (temp->workspace == toplevel->workspace) + if (temp->workspace == toplevel->workspace) { last = temp; - if (!first && temp->workspace == toplevel->workspace) + } + if (!first && temp->workspace == toplevel->workspace) { first = temp; + } } - if (first == last) + if (first == last) { return; + } absn_toplevel *swap = NULL; if (arg->i > 0) { @@ -91,8 +99,9 @@ void swap_focus(absn_server *server, const absn_arg *arg) wl_list_for_each(swap, &toplevel->link, link) { - if (toplevel->workspace == swap->workspace) + if (toplevel->workspace == swap->workspace) { break; + } } wl_list_remove(&toplevel->link); @@ -106,8 +115,9 @@ void swap_focus(absn_server *server, const absn_arg *arg) wl_list_for_each_reverse(swap, &toplevel->link, link) { - if (toplevel->workspace == swap->workspace) + if (toplevel->workspace == swap->workspace) { break; + } } wl_list_remove(&swap->link); @@ -121,8 +131,9 @@ arrange: void toggle_fullscreen(absn_server *server, const absn_arg *arg) { UNUSED(arg); - if (!server->focused_toplevel) + if (!server->focused_toplevel) { return; + } absn_toplevel *focus = server->focused_toplevel; toplevel_set_fullscreen(focus, !focus->fullscreen); @@ -131,19 +142,30 @@ void toggle_fullscreen(absn_server *server, const absn_arg *arg) void toggle_floating(absn_server *server, const absn_arg *arg) { UNUSED(arg); - if (!server->focused_toplevel) + if (!server->focused_toplevel) { return; + } absn_toplevel *focus = server->focused_toplevel; toplevel_set_floating(focus, !focus->floating); + + if (focus->floating) { + int32_t new_x = focus->output->geom.x + + (focus->output->geom.width / 2 - focus->geom.width / 2); + int32_t new_y = + focus->output->geom.y + + (focus->output->geom.height / 2 - focus->geom.height / 2); + toplevel_set_pos(focus, new_x, new_y); + } } void increase_master_width(absn_server *server, const absn_arg *arg) { absn_workspace *workspace = server->focused_output->workspace; - if (workspace->size + arg->f >= 1.0 || workspace->size + arg->f <= 0.0) + if (workspace->size + arg->f >= 1.0 || workspace->size + arg->f <= 0.0) { return; + } workspace->size += arg->f; layout_arrange(workspace->output); @@ -153,8 +175,9 @@ void increase_master_count(absn_server *server, const absn_arg *arg) { absn_workspace *workspace = server->focused_output->workspace; - if (workspace->count + arg->i <= 0) + if (workspace->count + arg->i <= 0) { return; + } workspace->count += arg->i; layout_arrange(workspace->output); @@ -164,23 +187,27 @@ void switch_workspace(absn_server *server, const absn_arg *arg) { int i; for (i = 0; i < server->workspaces_count; ++i) { - if (arg->v == server->workspaces[i].name) + if (arg->v == server->workspaces[i].name) { break; /* found it */ + } } - if (&server->workspaces[i] == server->focused_output->workspace) + if (&server->workspaces[i] == server->focused_output->workspace) { return; + } int toplevels_count = 0; absn_toplevel *toplevel; wl_list_for_each(toplevel, &server->toplevels, link) { - if (toplevel->workspace == server->focused_output->workspace) + if (toplevel->workspace == server->focused_output->workspace) { toplevels_count++; + } } - if (toplevels_count == 0) + if (toplevels_count == 0) { server->focused_output->workspace->output = NULL; + } if (!server->workspaces[i].output) { server->workspaces[i].output = server->focused_output; @@ -201,11 +228,13 @@ void switch_workspace(absn_server *server, const absn_arg *arg) absn_toplevel *focus = NULL; wl_list_for_each(toplevel, &server->toplevels, link) { - if (!focus && toplevel && toplevel->workspace == &server->workspaces[i]) { + if (!focus && toplevel && + toplevel->workspace == &server->workspaces[i]) { focus = toplevel; /* found it */ } - if (toplevel && toplevel->workspace == &server->workspaces[i] && toplevel->fullscreen) { + if (toplevel && toplevel->workspace == &server->workspaces[i] && + toplevel->fullscreen) { /* overwrite if there is a fullscreen window */ focus = toplevel; break; @@ -217,14 +246,15 @@ void switch_workspace(absn_server *server, const absn_arg *arg) /* crazy way to make toplevel focus properly if it was focused before */ struct wlr_surface *surface; #ifdef XWAYLAND - if (focus->type == TOPLEVEL_X11) + if (focus->type == TOPLEVEL_X11) { surface = focus->xw->surface; - else + } else #endif surface = focus->xdg->base->surface; - if (surface == server->seat->keyboard_state.focused_surface) + if (surface == server->seat->keyboard_state.focused_surface) { server->seat->keyboard_state.focused_surface = NULL; + } focus_toplevel(focus); } @@ -234,23 +264,28 @@ void switch_workspace(absn_server *server, const absn_arg *arg) void move_focus_to_workspace(absn_server *server, const absn_arg *arg) { - if (!server->focused_toplevel) + if (!server->focused_toplevel) { return; + } - if (server->focused_toplevel->fullscreen) + if (server->focused_toplevel->fullscreen) { toplevel_set_fullscreen(server->focused_toplevel, false); + } int i; for (i = 0; i < server->workspaces_count; ++i) { - if (arg->v == server->workspaces[i].name) + if (arg->v == server->workspaces[i].name) { break; /* found it */ + } } - if (&server->workspaces[i] == server->focused_toplevel->workspace) + if (&server->workspaces[i] == server->focused_toplevel->workspace) { return; + } - if (!server->workspaces[i].output) + if (!server->workspaces[i].output) { server->workspaces[i].output = server->focused_output; + } server->focused_toplevel->output = server->workspaces[i].output; server->focused_toplevel->workspace = &server->workspaces[i]; diff --git a/src/keyboard.c b/src/keyboard.c index 51a2473..b1dde12 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -14,15 +14,18 @@ void handle_modifiers(struct wl_listener *listener, void *data) absn_keyboard *keyboard = wl_container_of(listener, keyboard, modifiers); wlr_seat_set_keyboard(keyboard->server->seat, keyboard->wlr); - wlr_seat_keyboard_notify_modifiers(keyboard->server->seat, &keyboard->wlr->modifiers); + wlr_seat_keyboard_notify_modifiers(keyboard->server->seat, + &keyboard->wlr->modifiers); } -static bool handle_keybind(absn_server *server, uint32_t mods, xkb_keysym_t keysym) +static bool handle_keybind(absn_server *server, uint32_t mods, + xkb_keysym_t keysym) { 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)) { + xkb_keysym_to_lower(keybinds[i].keysym) == + xkb_keysym_to_lower(keysym)) { keybinds[i].cb(server, &keybinds[i].arg); return true; } @@ -44,15 +47,18 @@ void handle_key(struct wl_listener *listener, void *data) bool handled = false; if (event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { for (int i = 0; i < nsyms; ++i) { - handled = handle_keybind(keyboard->server, mods, syms[i]) || handled; + handled = + handle_keybind(keyboard->server, mods, syms[i]) || handled; } } - if (handled) + if (handled) { return; + } wlr_seat_set_keyboard(keyboard->server->seat, keyboard->wlr); - wlr_seat_keyboard_notify_key(keyboard->server->seat, event->time_msec, event->keycode, event->state); + wlr_seat_keyboard_notify_key(keyboard->server->seat, event->time_msec, + event->keycode, event->state); } void handle_destroy(struct wl_listener *listener, void *data) diff --git a/src/layer-surface.c b/src/layer-surface.c index e29550e..d67ad73 100644 --- a/src/layer-surface.c +++ b/src/layer-surface.c @@ -1,45 +1,92 @@ #include #include "focus.h" -#include "layer.h" +#include "layers.h" #include "types.h" - -void layer_surface_map(struct wl_listener *listener, void *data) -{ - UNUSED(listener); - UNUSED(data); -} +#include "xdg-popup.h" void layer_surface_unmap(struct wl_listener *listener, void *data) { UNUSED(data); - absn_layer_surface *layer_surface = wl_container_of(listener, layer_surface, unmap); + absn_layer_surface *layer_surface = + wl_container_of(listener, layer_surface, unmap); - if (layer_surface->wlr->surface == layer_surface->server->seat->keyboard_state.focused_surface) + if (layer_surface->wlr->surface == + layer_surface->server->seat->keyboard_state.focused_surface) { focus_toplevel(focus_get_topmost(layer_surface->server)); + } + if (layer_surface == layer_surface->server->exclusive_focus) { + layer_surface->server->exclusive_focus = NULL; + } + + layer_surface->mapped = false; } void layer_surface_commit(struct wl_listener *listener, void *data) { UNUSED(data); - absn_layer_surface *layer_surface = wl_container_of(listener, layer_surface, commit); + absn_layer_surface *layer_surface = + wl_container_of(listener, layer_surface, commit); struct wlr_layer_surface_v1 *surface = layer_surface->wlr; + struct wlr_scene_tree *scene_layer = + layer_surface->server->layers[layermap[surface->current.layer]]; - wlr_layer_surface_v1_configure(surface, surface->pending.desired_width, surface->pending.desired_height); + if (surface->initial_commit) { + struct wlr_layer_surface_v1_state old_state = surface->current; + surface->current = surface->pending; + layers_arrange(layer_surface->output); + surface->current = old_state; + return; + } - layer_arrange(layer_surface->output); + if (surface->current.committed == 0 || + layer_surface->mapped == surface->surface->mapped) { + return; + } + layer_surface->mapped = surface->surface->mapped; + + if (scene_layer != layer_surface->scene_tree->node.parent) { + wlr_scene_node_reparent(&layer_surface->scene_tree->node, scene_layer); + wl_list_remove(&layer_surface->link); + wl_list_insert(&layer_surface->output->layers[surface->current.layer], + &layer_surface->link); + bool on_top_layer = + surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP; + if (on_top_layer) { + wlr_scene_node_reparent( + &layer_surface->popups->node, + layer_surface->output->server->layers[LAYER_TOP]); + } else { + wlr_scene_node_reparent(&layer_surface->popups->node, scene_layer); + } + } + + layers_arrange(layer_surface->output); } void layer_surface_new_popup(struct wl_listener *listener, void *data) { - UNUSED(listener); UNUSED(data); + absn_layer_surface *layer_surface = + wl_container_of(listener, layer_surface, new_popup); + struct wlr_xdg_popup *xdg_popup = data; + + wlr_scene_xdg_surface_create(layer_surface->popups, xdg_popup->base); + + absn_popup *popup = calloc(1, sizeof(*popup)); + popup->wlr = xdg_popup; + popup->parent_type = LAYER_SURFACE; + popup->parent = layer_surface; + + LISTEN(popup->commit, xdg_popup_commit, + xdg_popup->base->surface->events.commit); } void layer_surface_destroy(struct wl_listener *listener, void *data) { UNUSED(data); - absn_layer_surface *layer_surface = wl_container_of(listener, layer_surface, destroy); + absn_layer_surface *layer_surface = + wl_container_of(listener, layer_surface, destroy); wl_list_remove(&layer_surface->link); wl_list_remove(&layer_surface->map.link); diff --git a/src/layer.c b/src/layer.c deleted file mode 100644 index d52d82d..0000000 --- a/src/layer.c +++ /dev/null @@ -1,21 +0,0 @@ -#include - -#include "layout.h" -#include "types.h" - -void layer_arrange(absn_output *output) -{ - struct wlr_box usable_area = output->geom; - absn_layer_surface *layer_surface; - - wl_list_for_each(layer_surface, &output->layer_surfaces, link) - { - if (!layer_surface->wlr->initialized) - continue; - - wlr_scene_layer_surface_v1_configure(layer_surface->scene_layer, &output->geom, &usable_area); - } - - output->usable_area = usable_area; - layout_arrange(output); -} diff --git a/src/layers.c b/src/layers.c new file mode 100644 index 0000000..aabcf51 --- /dev/null +++ b/src/layers.c @@ -0,0 +1,87 @@ +#include + +#include "focus.h" +#include "layout.h" +#include "output.h" +#include "types.h" + +/* arrange layers logic from dwl */ + +static void layer_arrange(absn_output *output, struct wl_list *list, + struct wlr_box *usable_area, int exclusive) +{ + absn_layer_surface *layer_surface; + wl_list_for_each(layer_surface, list, link) + { + struct wlr_layer_surface_v1 *surface = layer_surface->wlr; + + if (!surface->initialized) { + continue; + } + + if (exclusive != (surface->current.exclusive_zone > 0)) { + continue; + } + + 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); + } +} + +void layers_arrange(absn_output *output) +{ + if (!output->wlr->enabled) { + return; + } + + struct wlr_box usable_area = output->usable_area; + + /* Arrange non-exclusive surfaces from top->bottom */ + for (int i = 3; i >= 0; --i) { + layer_arrange(output, &output->layers[i], &usable_area, 1); + } + + if (!wlr_box_equal(&output->usable_area, &usable_area)) { + output->usable_area = usable_area; + output_arrange(output); + } + + /* Arrange non-exclusive surfaces from top->bottom */ + for (int i = 3; i >= 0; --i) { + layer_arrange(output, &output->layers[i], &usable_area, 0); + } + + uint32_t layers_above_shell[] = { + ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, + ZWLR_LAYER_SHELL_V1_LAYER_TOP, + }; + + int layers_above_shell_count = + sizeof(layers_above_shell) / sizeof(layers_above_shell[0]); + absn_layer_surface *layer_surface; + for (int i = 0; i < layers_above_shell_count; ++i) { + wl_list_for_each_reverse(layer_surface, + &output->layers[layers_above_shell[i]], link) + { + if (!layer_surface->wlr->current.keyboard_interactive || + !layer_surface->mapped) { + continue; + } + + unfocus_toplevel(output->server->focused_toplevel); + 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); + } + return; + } + } +} diff --git a/src/layout.c b/src/layout.c index a622a14..de26cc4 100644 --- a/src/layout.c +++ b/src/layout.c @@ -14,9 +14,11 @@ static int prepare_output(struct absn_output *output) { if (toplevel->workspace == output->workspace) { wlr_scene_node_set_enabled(&toplevel->scene_tree->node, true); - if (!toplevel->floating && !toplevel->fullscreen) + if (!toplevel->floating && !toplevel->fullscreen) { res++; - } else if (toplevel->output == output && toplevel->workspace != output->workspace) { + } + } else if (toplevel->output == output && + toplevel->workspace != output->workspace) { wlr_scene_node_set_enabled(&toplevel->scene_tree->node, false); } } @@ -28,8 +30,9 @@ static void tile(struct absn_output *output) { int toplevels_count = prepare_output(output); - if (toplevels_count < 1) + if (toplevels_count < 1) { return; + } int32_t og = OUTPUT_GAP; struct wlr_box new_geom; @@ -38,11 +41,15 @@ static void tile(struct absn_output *output) if (toplevels_count == 1) { wl_list_for_each(toplevel, &output->server->toplevels, link) { - if (toplevel->workspace == output->workspace && !toplevel->floating && !toplevel->fullscreen) + if (toplevel->workspace == output->workspace && + !toplevel->floating && !toplevel->fullscreen) { 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; @@ -55,7 +62,9 @@ static void tile(struct absn_output *output) 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); + (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; @@ -74,8 +83,10 @@ static void tile(struct absn_output *output) wl_list_for_each(toplevel, &output->server->toplevels, link) { - if (toplevel->workspace != output->workspace || toplevel->floating || toplevel->fullscreen) + if (toplevel->workspace != output->workspace || + toplevel->floating || toplevel->fullscreen) { continue; + } cur_h = h + (i < r ? 1 : 0); @@ -95,8 +106,10 @@ static void tile(struct absn_output *output) wl_list_for_each(toplevel, &output->server->toplevels, link) { - if (toplevel->workspace != output->workspace || toplevel->floating || toplevel->fullscreen) + if (toplevel->workspace != output->workspace || toplevel->floating || + toplevel->fullscreen) { continue; + } if (i < mcount) { total_lg = (mcount - 1) * lg; @@ -115,8 +128,9 @@ static void tile(struct absn_output *output) dy += cur_h + lg; } else { - if (i == mcount) + if (i == mcount) { dy = og; + } int32_t stack_count = toplevels_count - mcount; total_lg = (stack_count - 1) * lg; @@ -144,8 +158,9 @@ static void tile_left(struct absn_output *output) { int toplevels_count = prepare_output(output); - if (toplevels_count < 1) + if (toplevels_count < 1) { return; + } int32_t og = OUTPUT_GAP; struct wlr_box new_geom; @@ -154,11 +169,15 @@ static void tile_left(struct absn_output *output) if (toplevels_count == 1) { wl_list_for_each(toplevel, &output->server->toplevels, link) { - if (toplevel->workspace == output->workspace && !toplevel->floating && !toplevel->fullscreen) + if (toplevel->workspace == output->workspace && + !toplevel->floating && !toplevel->fullscreen) { 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; @@ -171,7 +190,9 @@ static void tile_left(struct absn_output *output) 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); + (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; @@ -190,8 +211,10 @@ static void tile_left(struct absn_output *output) wl_list_for_each(toplevel, &output->server->toplevels, link) { - if (toplevel->workspace != output->workspace || toplevel->floating || toplevel->fullscreen) + if (toplevel->workspace != output->workspace || + toplevel->floating || toplevel->fullscreen) { continue; + } cur_h = h + (i < r ? 1 : 0); @@ -211,8 +234,10 @@ static void tile_left(struct absn_output *output) wl_list_for_each(toplevel, &output->server->toplevels, link) { - if (toplevel->workspace != output->workspace || toplevel->floating || toplevel->fullscreen) + if (toplevel->workspace != output->workspace || toplevel->floating || + toplevel->fullscreen) { continue; + } if (i < mcount) { total_lg = (mcount - 1) * lg; @@ -222,7 +247,8 @@ static void tile_left(struct absn_output *output) cur_h = h + (i < r ? 1 : 0); - new_geom.x = output->usable_area.x + output->usable_area.width - og - main_stack_width; + new_geom.x = output->usable_area.x + output->usable_area.width - + og - main_stack_width; new_geom.y = output->usable_area.y + dy; new_geom.width = main_stack_width; new_geom.height = cur_h; @@ -231,8 +257,9 @@ static void tile_left(struct absn_output *output) dy += cur_h + lg; } else { - if (i == mcount) + if (i == mcount) { dy = og; + } int32_t stack_count = toplevels_count - mcount; total_lg = (stack_count - 1) * lg; @@ -260,8 +287,9 @@ static void monocle(struct absn_output *output) { int toplevels_count = prepare_output(output); - if (toplevels_count < 1) + if (toplevels_count < 1) { return; + } int32_t og = OUTPUT_GAP; @@ -275,8 +303,10 @@ static void monocle(struct absn_output *output) absn_toplevel *toplevel; wl_list_for_each(toplevel, &output->server->toplevels, link) { - if (toplevel->workspace != output->workspace || toplevel->floating || toplevel->fullscreen) + if (toplevel->workspace != output->workspace || toplevel->floating || + toplevel->fullscreen) { continue; + } toplevel_set_geom(toplevel, &new_geom); } @@ -284,8 +314,9 @@ static void monocle(struct absn_output *output) void layout_arrange(struct absn_output *output) { - if (!output) + if (!output) { return; + } switch (output->workspace->layout) { case LAYOUT_TILE: diff --git a/src/output.c b/src/output.c index f8be1de..d30039b 100644 --- a/src/output.c +++ b/src/output.c @@ -17,8 +17,9 @@ 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->output == output) { goto skip; + } } wlr_scene_output_commit(scene_output, NULL); @@ -29,7 +30,8 @@ skip: void output_request_state(struct wl_listener *listener, void *data) { - struct absn_output *output = wl_container_of(listener, output, request_state); + struct absn_output *output = + wl_container_of(listener, output, request_state); const struct wlr_output_event_request_state *event = data; wlr_output_commit_state(output->wlr, event->state); } @@ -37,7 +39,8 @@ void output_request_state(struct wl_listener *listener, void *data) void output_destroy(struct wl_listener *listener, void *data) { UNUSED(data); - struct absn_output *output = wl_container_of(listener, output, request_state); + struct absn_output *output = + wl_container_of(listener, output, request_state); wl_list_remove(&output->frame.link); wl_list_remove(&output->request_state.link); @@ -50,7 +53,8 @@ void output_layout_change(struct wl_listener *listener, void *data) { UNUSED(data); absn_server *server = wl_container_of(listener, server, layout_change); - struct wlr_output_configuration_v1 *config = wlr_output_configuration_v1_create(); + struct wlr_output_configuration_v1 *config = + wlr_output_configuration_v1_create(); absn_toplevel *toplevel = NULL; absn_output *output; @@ -58,45 +62,57 @@ void output_layout_change(struct wl_listener *listener, void *data) wl_list_for_each(output, &server->outputs, link) { - if (output->wlr->enabled) + if (output->wlr->enabled) { continue; - config_head = wlr_output_configuration_head_v1_create(config, output->wlr); + } + config_head = + wlr_output_configuration_head_v1_create(config, output->wlr); config_head->state.enabled = 0; wlr_output_layout_remove(server->output_layout, output->wlr); // closemon(m); - // m->m = m->w = (struct wlr_box){0}; + output->geom = output->usable_area = (struct wlr_box){0}; } wl_list_for_each(output, &server->outputs, link) { - if (output->wlr->enabled && !wlr_output_layout_get(server->output_layout, output->wlr)) - wlr_output_layout_add_auto(server->output_layout, toplevel->output->wlr); + if (output->wlr->enabled && + !wlr_output_layout_get(server->output_layout, output->wlr)) { + wlr_output_layout_add_auto(server->output_layout, + toplevel->output->wlr); + } } struct wlr_box layout_geom; wlr_output_layout_get_box(server->output_layout, NULL, &layout_geom); - wlr_scene_node_set_position(&server->bg->node, layout_geom.x, layout_geom.y); + wlr_scene_node_set_position(&server->bg->node, layout_geom.x, + layout_geom.y); wlr_scene_rect_set_size(server->bg, layout_geom.width, layout_geom.height); wl_list_for_each(output, &server->outputs, link) { - if (!output->wlr->enabled) + if (!output->wlr->enabled) { continue; - config_head = wlr_output_configuration_head_v1_create(config, output->wlr); + } + config_head = + wlr_output_configuration_head_v1_create(config, output->wlr); - wlr_output_layout_get_box(server->output_layout, output->wlr, &output->geom); + wlr_output_layout_get_box(server->output_layout, output->wlr, + &output->geom); output->usable_area = output->geom; - if ((toplevel = focus_get_topmost(server)) && toplevel->fullscreen) - toplevel_set_size(toplevel, output->geom.width, output->geom.height); + if ((toplevel = focus_get_topmost(server)) && toplevel->fullscreen) { + toplevel_set_size(toplevel, output->geom.width, + output->geom.height); + } config_head->state.x = output->geom.x; config_head->state.y = output->geom.y; - if (!server->focused_output) + if (!server->focused_output) { server->focused_output = output; + } } if (server->focused_output && server->focused_output->wlr->enabled) { @@ -121,11 +137,43 @@ void update_focused_output(absn_server *server) int32_t cursor_y = server->cursor->y; wl_list_for_each(output, &server->outputs, link) { - bool cursor_in_output_x = cursor_x >= output->geom.x && cursor_x <= output->geom.x + output->geom.width; - bool cursor_in_output_y = cursor_y >= output->geom.y && cursor_y <= output->geom.y + output->geom.height; + bool cursor_in_output_x = + cursor_x >= output->geom.x && + cursor_x <= output->geom.x + output->geom.width; + bool cursor_in_output_y = + cursor_y >= output->geom.y && + cursor_y <= output->geom.y + output->geom.height; if (cursor_in_output_x && cursor_in_output_y) { server->focused_output = output; break; } } } + +void output_arrange(absn_output *output) +{ + if (!output->wlr->enabled) { + return; + } + absn_server *server = output->server; + bool enabled; + absn_toplevel *toplevel; + wl_list_for_each(toplevel, &server->toplevels, link) + { + if (toplevel->output == output) { + enabled = output->workspace == toplevel->workspace; + wlr_scene_node_set_enabled(&toplevel->scene_tree->node, enabled); + } + } + + wl_list_for_each(toplevel, &server->toplevels, link) + { + if (toplevel->output != output || + toplevel->scene_tree->node.parent == + server->layers[LAYER_FULLSCREEN]) { + continue; + } + wlr_scene_node_reparent(&toplevel->scene_tree->node, + toplevel->scene_tree->node.parent); + } +} diff --git a/src/seat.c b/src/seat.c index 1d80e1a..ce7116d 100644 --- a/src/seat.c +++ b/src/seat.c @@ -9,22 +9,27 @@ void request_cursor(struct wl_listener *listener, void *data) struct wlr_seat_pointer_request_set_cursor_event *event = data; struct wlr_seat_client *client = server->seat->pointer_state.focused_client; - if (client == event->seat_client) - wlr_cursor_set_surface(server->cursor, event->surface, event->hotspot_x, event->hotspot_y); + if (client == event->seat_client) { + wlr_cursor_set_surface(server->cursor, event->surface, event->hotspot_x, + event->hotspot_y); + } } void pointer_focus_change(struct wl_listener *listener, void *data) { - absn_server *server = wl_container_of(listener, server, pointer_focus_change); + absn_server *server = + wl_container_of(listener, server, pointer_focus_change); struct wlr_seat_pointer_focus_change_event *event = data; - if (!event->new_surface) + if (!event->new_surface) { wlr_cursor_set_xcursor(server->cursor, server->cursor_mgr, "default"); + } } void request_set_selection(struct wl_listener *listener, void *data) { - absn_server *server = wl_container_of(listener, server, request_set_selection); + absn_server *server = + wl_container_of(listener, server, request_set_selection); struct wlr_seat_request_set_selection_event *event = data; wlr_seat_set_selection(server->seat, event->source, event->serial); diff --git a/src/server.c b/src/server.c index 910d915..3709326 100644 --- a/src/server.c +++ b/src/server.c @@ -9,6 +9,7 @@ #include "focus.h" #include "keyboard.h" #include "layer-surface.h" +#include "layers.h" #include "output.h" #include "toplevel-handlers.h" #include "toplevel.h" @@ -35,8 +36,9 @@ void new_output(struct wl_listener *listener, void *data) wlr_output_state_set_enabled(&state, true); struct wlr_output_mode *mode = wlr_output_preferred_mode(wlr_output); - if (mode) + if (mode) { wlr_output_state_set_mode(&state, mode); + } wlr_output_commit_state(wlr_output, &state); wlr_output_state_finish(&state); @@ -54,17 +56,24 @@ void new_output(struct wl_listener *listener, void *data) } LISTEN(output->frame, output_frame, wlr_output->events.frame); - LISTEN(output->request_state, output_request_state, wlr_output->events.request_state); + LISTEN(output->request_state, output_request_state, + wlr_output->events.request_state); LISTEN(output->destroy, output_destroy, wlr_output->events.destroy); wl_list_insert(&server->outputs, &output->link); - wl_list_init(&output->layer_surfaces); + for (int i = 0; i < 4; ++i) { + wl_list_init(&output->layers[i]); + } - struct wlr_output_layout_output *l_layout = wlr_output_layout_add_auto(server->output_layout, output->wlr); - struct wlr_scene_output *scene_output = wlr_scene_output_create(server->scene, wlr_output); - wlr_scene_output_layout_add_output(server->scene_layout, l_layout, scene_output); - wlr_output_layout_get_box(server->output_layout, output->wlr, &output->geom); + struct wlr_output_layout_output *l_layout = + wlr_output_layout_add_auto(server->output_layout, output->wlr); + struct wlr_scene_output *scene_output = + wlr_scene_output_create(server->scene, wlr_output); + wlr_scene_output_layout_add_output(server->scene_layout, l_layout, + scene_output); + wlr_output_layout_get_box(server->output_layout, output->wlr, + &output->geom); output->usable_area = output->geom; } @@ -82,14 +91,21 @@ void new_xdg_toplevel(struct wl_listener *listener, void *data) wlr_surface_set_preferred_buffer_scale(toplevel->xdg->base->surface, 1); - LISTEN(toplevel->commit, toplevel_commit, xdg_toplevel->base->surface->events.commit); - LISTEN(toplevel->map, toplevel_map, xdg_toplevel->base->surface->events.map); - LISTEN(toplevel->unmap, toplevel_unmap, xdg_toplevel->base->surface->events.unmap); + LISTEN(toplevel->commit, toplevel_commit, + xdg_toplevel->base->surface->events.commit); + LISTEN(toplevel->map, toplevel_map, + xdg_toplevel->base->surface->events.map); + LISTEN(toplevel->unmap, toplevel_unmap, + xdg_toplevel->base->surface->events.unmap); LISTEN(toplevel->destroy, toplevel_destroy, xdg_toplevel->events.destroy); - LISTEN(toplevel->request_move, toplevel_request_move, xdg_toplevel->events.request_move); - LISTEN(toplevel->request_resize, toplevel_request_resize, xdg_toplevel->events.request_resize); - LISTEN(toplevel->request_maximize, toplevel_request_maximize, xdg_toplevel->events.request_maximize); - LISTEN(toplevel->request_fullscreen, toplevel_request_fullscreen, xdg_toplevel->events.request_fullscreen); + LISTEN(toplevel->request_move, toplevel_request_move, + xdg_toplevel->events.request_move); + LISTEN(toplevel->request_resize, toplevel_request_resize, + xdg_toplevel->events.request_resize); + LISTEN(toplevel->request_maximize, toplevel_request_maximize, + xdg_toplevel->events.request_maximize); + LISTEN(toplevel->request_fullscreen, toplevel_request_fullscreen, + xdg_toplevel->events.request_fullscreen); } void new_xdg_popup(struct wl_listener *listener, void *data) @@ -97,16 +113,22 @@ void new_xdg_popup(struct wl_listener *listener, void *data) absn_server *server = wl_container_of(listener, server, new_xdg_popup); struct wlr_xdg_popup *xdg_popup = data; + struct wlr_xdg_surface *parent = + wlr_xdg_surface_try_from_wlr_surface(xdg_popup->parent); + if (!parent) { + return; + } + absn_toplevel *toplevel = parent->data; + + wlr_scene_xdg_surface_create(toplevel->scene_tree, xdg_popup->base); + absn_popup *popup = calloc(1, sizeof(*popup)); popup->wlr = xdg_popup; + popup->parent_type = TOPLEVEL_XDG; + popup->parent = toplevel; - struct wlr_xdg_surface *parent = wlr_xdg_surface_try_from_wlr_surface(xdg_popup->parent); - absn_toplevel *parent_toplevel = parent->data; - struct wlr_scene_tree *parent_tree = parent_toplevel->scene_tree; - xdg_popup->base->data = wlr_scene_xdg_surface_create(parent_tree, xdg_popup->base); - - LISTEN(popup->commit, xdg_popup_commit, xdg_popup->base->surface->events.commit); - LISTEN(popup->destroy, xdg_popup_destroy, xdg_popup->base->surface->events.destroy); + LISTEN(popup->commit, xdg_popup_commit, + xdg_popup->base->surface->events.commit); } void new_xdg_decoration(struct wl_listener *listener, void *data) @@ -116,7 +138,8 @@ void new_xdg_decoration(struct wl_listener *listener, void *data) absn_toplevel *toplevel = deco->toplevel->base->data; toplevel->deco = deco; - LISTEN(toplevel->deco_request_mode, deco_request_mode, deco->events.request_mode); + LISTEN(toplevel->deco_request_mode, deco_request_mode, + deco->events.request_mode); LISTEN(toplevel->deco_destroy, deco_destroy, deco->events.destroy); /* Forse server side decoration mode */ @@ -135,20 +158,31 @@ void new_layer_surface(struct wl_listener *listener, void *data) absn_layer_surface *layer_surface = calloc(1, sizeof(*layer_surface)); - LISTEN(layer_surface->map, layer_surface_map, surface->surface->events.map); - LISTEN(layer_surface->unmap, layer_surface_unmap, surface->surface->events.unmap); - LISTEN(layer_surface->commit, layer_surface_commit, surface->surface->events.commit); - LISTEN(layer_surface->new_popup, layer_surface_new_popup, surface->events.new_popup); - LISTEN(layer_surface->destroy, layer_surface_destroy, surface->surface->events.destroy); + LISTEN(layer_surface->unmap, layer_surface_unmap, + surface->surface->events.unmap); + LISTEN(layer_surface->commit, layer_surface_commit, + surface->surface->events.commit); + LISTEN(layer_surface->new_popup, layer_surface_new_popup, + surface->events.new_popup); + LISTEN(layer_surface->destroy, layer_surface_destroy, + surface->surface->events.destroy); layer_surface->wlr = surface; layer_surface->output = surface->output->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); + 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; - wl_list_insert(&layer_surface->output->layer_surfaces, &layer_surface->link); + 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); } @@ -161,9 +195,13 @@ void xwayland_ready(struct wl_listener *listener, void *data) wlr_xwayland_set_seat(server->xwayland, server->seat); struct wlr_xcursor *xcursor; - if ((xcursor = wlr_xcursor_manager_get_xcursor(server->cursor_mgr, "default", 1))) { - struct wlr_buffer *buffer = wlr_xcursor_image_get_buffer(xcursor->images[0]); - wlr_xwayland_set_cursor(server->xwayland, buffer, xcursor->images[0]->hotspot_x, xcursor->images[0]->hotspot_y); + if ((xcursor = wlr_xcursor_manager_get_xcursor(server->cursor_mgr, + "default", 1))) { + struct wlr_buffer *buffer = + wlr_xcursor_image_get_buffer(xcursor->images[0]); + wlr_xwayland_set_cursor(server->xwayland, buffer, + xcursor->images[0]->hotspot_x, + xcursor->images[0]->hotspot_y); } } @@ -180,14 +218,21 @@ void xwayland_new_surface(struct wl_listener *listener, void *data) surface->data = toplevel; LISTEN(toplevel->destroy, toplevel_destroy, surface->events.destroy); - LISTEN(toplevel->request_maximize, toplevel_request_maximize, surface->events.request_maximize); - LISTEN(toplevel->request_fullscreen, toplevel_request_fullscreen, surface->events.request_fullscreen); + LISTEN(toplevel->request_maximize, toplevel_request_maximize, + surface->events.request_maximize); + LISTEN(toplevel->request_fullscreen, toplevel_request_fullscreen, + surface->events.request_fullscreen); - LISTEN(toplevel->xw_activate, xwayland_activate, surface->events.request_activate); - LISTEN(toplevel->xw_associate, xwayland_associate, surface->events.associate); - LISTEN(toplevel->xw_dissociate, xwayland_dissociate, surface->events.dissociate); - LISTEN(toplevel->xw_configure, xwayland_configure, surface->events.request_configure); - LISTEN(toplevel->xw_set_hints, xwayland_set_hints, surface->events.set_hints); + LISTEN(toplevel->xw_activate, xwayland_activate, + surface->events.request_activate); + LISTEN(toplevel->xw_associate, xwayland_associate, + surface->events.associate); + LISTEN(toplevel->xw_dissociate, xwayland_dissociate, + surface->events.dissociate); + LISTEN(toplevel->xw_configure, xwayland_configure, + surface->events.request_configure); + LISTEN(toplevel->xw_set_hints, xwayland_set_hints, + surface->events.set_hints); } #endif @@ -196,7 +241,8 @@ void cursor_motion(struct wl_listener *listener, void *data) absn_server *server = wl_container_of(listener, server, cursor_motion); struct wlr_pointer_motion_event *event = data; update_focused_output(server); - wlr_cursor_move(server->cursor, &event->pointer->base, event->delta_x, event->delta_y); + wlr_cursor_move(server->cursor, &event->pointer->base, event->delta_x, + event->delta_y); process_cursor_motion(server, event->time_msec); } @@ -205,7 +251,8 @@ void cursor_motion_abs(struct wl_listener *listener, void *data) absn_server *server = wl_container_of(listener, server, cursor_motion_abs); struct wlr_pointer_motion_absolute_event *event = data; update_focused_output(server); - wlr_cursor_warp_absolute(server->cursor, &event->pointer->base, event->x, event->y); + wlr_cursor_warp_absolute(server->cursor, &event->pointer->base, event->x, + event->y); process_cursor_motion(server, event->time_msec); } @@ -220,17 +267,20 @@ void cursor_button(struct wl_listener *listener, void *data) } else { double sx, sy; struct wlr_surface *surface = NULL; - absn_toplevel *toplevel = toplevel_at(server, server->cursor->x, server->cursor->y, &surface, &sx, &sy); + absn_toplevel *toplevel = toplevel_at( + server, server->cursor->x, server->cursor->y, &surface, &sx, &sy); - if (!toplevel) + if (!toplevel) { goto handle; + } struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(server->seat); uint32_t mods = wlr_keyboard_get_modifiers(keyboard); if (mods & CURSOR_MOD) { if (event->button == CURSOR_MOVE_BUTTON) { server->cursor_mode = CURSOR_MOVE; - wlr_cursor_set_xcursor(server->cursor, server->cursor_mgr, "all-scroll"); + wlr_cursor_set_xcursor(server->cursor, server->cursor_mgr, + "all-scroll"); handled = true; } else if (event->button == CURSOR_RESIZE_BUTTON) { server->cursor_mode = CURSOR_RESIZE; @@ -249,24 +299,32 @@ void cursor_button(struct wl_listener *listener, void *data) server->grab_geom.width = toplevel->geom.width; server->grab_geom.height = toplevel->geom.height; - if (server->cursor_mode != CURSOR_RESIZE) + if (server->cursor_mode != CURSOR_RESIZE) { goto handle; + } int32_t width = toplevel->xdg->base->geometry.width; int32_t height = toplevel->xdg->base->geometry.height; - if (server->grab_x > (lx + width / 2) && server->grab_y > (ly + height / 2)) { + if (server->grab_x > (lx + width / 2) && + server->grab_y > (ly + height / 2)) { server->resize_corner = BOTTOM_RIGHT; - wlr_cursor_set_xcursor(server->cursor, server->cursor_mgr, "se-resize"); - } else if (server->grab_x < (lx + width / 2) && server->grab_y > (ly + height / 2)) { + wlr_cursor_set_xcursor(server->cursor, server->cursor_mgr, + "se-resize"); + } else if (server->grab_x < (lx + width / 2) && + server->grab_y > (ly + height / 2)) { server->resize_corner = BOTTOM_LEFT; - wlr_cursor_set_xcursor(server->cursor, server->cursor_mgr, "sw-resize"); - } else if (server->grab_x > (lx + width / 2) && server->grab_y < (ly + height / 2)) { + wlr_cursor_set_xcursor(server->cursor, server->cursor_mgr, + "sw-resize"); + } else if (server->grab_x > (lx + width / 2) && + server->grab_y < (ly + height / 2)) { server->resize_corner = TOP_RIGHT; - wlr_cursor_set_xcursor(server->cursor, server->cursor_mgr, "ne-resize"); + wlr_cursor_set_xcursor(server->cursor, server->cursor_mgr, + "ne-resize"); } else { server->resize_corner = TOP_LEFT; - wlr_cursor_set_xcursor(server->cursor, server->cursor_mgr, "nw-resize"); + wlr_cursor_set_xcursor(server->cursor, server->cursor_mgr, + "nw-resize"); } wlr_xdg_toplevel_set_resizing(toplevel->xdg, true); @@ -274,7 +332,8 @@ void cursor_button(struct wl_listener *listener, void *data) handle: if (!handled) { - wlr_seat_pointer_notify_button(server->seat, event->time_msec, event->button, event->state); + wlr_seat_pointer_notify_button(server->seat, event->time_msec, + event->button, event->state); } } @@ -282,8 +341,9 @@ 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) @@ -301,16 +361,19 @@ static void new_keyboard(absn_server *server, struct wlr_input_device *device) keyboard->wlr = wlr_keyboard; struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); - struct xkb_keymap *keymap = xkb_keymap_new_from_names(context, NULL, XKB_KEYMAP_COMPILE_NO_FLAGS); + struct xkb_keymap *keymap = + xkb_keymap_new_from_names(context, NULL, XKB_KEYMAP_COMPILE_NO_FLAGS); wlr_keyboard_set_keymap(wlr_keyboard, keymap); xkb_keymap_unref(keymap); xkb_context_unref(context); wlr_keyboard_set_repeat_info(wlr_keyboard, 25, 600); - LISTEN(keyboard->modifiers, handle_modifiers, wlr_keyboard->events.modifiers); + LISTEN(keyboard->modifiers, handle_modifiers, + wlr_keyboard->events.modifiers); LISTEN(keyboard->key, handle_key, wlr_keyboard->events.key); - LISTEN(keyboard->destroy, handle_destroy, wlr_keyboard->base.events.destroy); + LISTEN(keyboard->destroy, handle_destroy, + wlr_keyboard->base.events.destroy); wlr_seat_set_keyboard(server->seat, wlr_keyboard); diff --git a/src/toplevel-handlers.c b/src/toplevel-handlers.c index 72db3a3..b669e81 100644 --- a/src/toplevel-handlers.c +++ b/src/toplevel-handlers.c @@ -15,11 +15,15 @@ void toplevel_map(struct wl_listener *listener, void *data) toplevel->scene_tree = wlr_scene_tree_create(server->layers[LAYER_TILE]); toplevel->scene_tree->node.data = toplevel; - wlr_scene_node_set_enabled(&toplevel->scene_tree->node, toplevel_is_unmanaged(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) { - wlr_xdg_toplevel_set_tiled(toplevel->xdg, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | WLR_EDGE_RIGHT); + 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); } @@ -28,11 +32,13 @@ void toplevel_map(struct wl_listener *listener, void *data) #ifdef XWAYLAND if (toplevel->type == TOPLEVEL_X11) { - toplevel->scene_surface = wlr_scene_subsurface_tree_create(toplevel->scene_tree, toplevel->xw->surface); + toplevel->scene_surface = wlr_scene_subsurface_tree_create( + toplevel->scene_tree, toplevel->xw->surface); } else #endif { - toplevel->scene_surface = wlr_scene_xdg_surface_create(toplevel->scene_tree, toplevel->xdg->base); + toplevel->scene_surface = wlr_scene_xdg_surface_create( + toplevel->scene_tree, toplevel->xdg->base); } toplevel->scene_surface->node.data = toplevel; @@ -40,7 +46,8 @@ void toplevel_map(struct wl_listener *listener, void *data) toplevel->bw = toplevel_is_unmanaged(toplevel) ? 0 : TOPLEVEL_BW; for (int i = 0; i < 4; ++i) { - toplevel->border[i] = wlr_scene_rect_create(toplevel->scene_tree, 0, 0, unfocused_bc); + toplevel->border[i] = + wlr_scene_rect_create(toplevel->scene_tree, 0, 0, unfocused_bc); toplevel->border[i]->node.data = toplevel; } @@ -66,6 +73,10 @@ void toplevel_unmap(struct wl_listener *listener, void *data) toplevel->server->seat->keyboard_state.focused_surface = NULL; } + if (toplevel == toplevel->server->exclusive_focus) { + toplevel->server->exclusive_focus = NULL; + } + wl_list_remove(&toplevel->link); wl_list_remove(&toplevel->flink); @@ -108,29 +119,35 @@ void toplevel_request_move(struct wl_listener *listener, void *data) { UNUSED(data); absn_toplevel *toplevel = wl_container_of(listener, toplevel, request_move); - if (toplevel->xdg->base->initialized) + if (toplevel->xdg->base->initialized) { wlr_xdg_surface_schedule_configure(toplevel->xdg->base); + } } void toplevel_request_resize(struct wl_listener *listener, void *data) { UNUSED(data); - absn_toplevel *toplevel = wl_container_of(listener, toplevel, request_resize); - if (toplevel->xdg->base->initialized) + absn_toplevel *toplevel = + wl_container_of(listener, toplevel, request_resize); + if (toplevel->xdg->base->initialized) { wlr_xdg_surface_schedule_configure(toplevel->xdg->base); + } } void toplevel_request_maximize(struct wl_listener *listener, void *data) { UNUSED(data); - absn_toplevel *toplevel = wl_container_of(listener, toplevel, request_maximize); - if (toplevel->xdg->base->initialized) + absn_toplevel *toplevel = + wl_container_of(listener, toplevel, request_maximize); + if (toplevel->xdg->base->initialized) { wlr_xdg_surface_schedule_configure(toplevel->xdg->base); + } } void toplevel_request_fullscreen(struct wl_listener *listener, void *data) { UNUSED(data); - absn_toplevel *toplevel = wl_container_of(listener, toplevel, request_fullscreen); + absn_toplevel *toplevel = + wl_container_of(listener, toplevel, request_fullscreen); toplevel_set_fullscreen(toplevel, toplevel->xdg->requested.fullscreen); } diff --git a/src/toplevel.c b/src/toplevel.c index 7d5bdaa..8cf8cb0 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -12,10 +12,11 @@ * its surface and coordinates inside of it * to process input event */ -absn_toplevel *toplevel_at(absn_server *server, double lx, double ly, struct wlr_surface **surface, double *sx, - double *sy) +absn_toplevel *toplevel_at(absn_server *server, double lx, double ly, + struct wlr_surface **surface, double *sx, double *sy) { - struct wlr_scene_node *node = wlr_scene_node_at(&server->scene->tree.node, lx, ly, sx, sy); + struct wlr_scene_node *node = + wlr_scene_node_at(&server->scene->tree.node, lx, ly, sx, sy); if (!node) { return NULL; } @@ -54,8 +55,9 @@ absn_toplevel *toplevel_at(absn_server *server, double lx, double ly, struct wlr bool toplevel_is_unmanaged(absn_toplevel *toplevel) { #ifdef XWAYLAND - if (toplevel->type == TOPLEVEL_X11) + if (toplevel->type == TOPLEVEL_X11) { return toplevel->xw->override_redirect; + } #endif return false; } @@ -80,21 +82,28 @@ static void toplevel_update_borders_geom(absn_toplevel *toplevel) { int32_t bw = toplevel->bw; - if (toplevel->geom.width - 2 * bw < 0 || toplevel->geom.height - 2 * bw < 0) + if (toplevel->geom.width - 2 * bw < 0 || + toplevel->geom.height - 2 * bw < 0) { return; + } - wlr_scene_node_set_position(&toplevel->scene_tree->node, toplevel->geom.x, toplevel->geom.y); + wlr_scene_node_set_position(&toplevel->scene_tree->node, toplevel->geom.x, + toplevel->geom.y); wlr_scene_node_set_position(&toplevel->scene_surface->node, bw, bw); - wlr_scene_rect_set_size(toplevel->border[0], toplevel->geom.width - 2 * bw, bw); - wlr_scene_rect_set_size(toplevel->border[1], toplevel->geom.width - 2 * bw, bw); + wlr_scene_rect_set_size(toplevel->border[0], toplevel->geom.width - 2 * bw, + bw); + wlr_scene_rect_set_size(toplevel->border[1], toplevel->geom.width - 2 * bw, + bw); wlr_scene_rect_set_size(toplevel->border[2], bw, toplevel->geom.height); wlr_scene_rect_set_size(toplevel->border[3], bw, toplevel->geom.height); wlr_scene_node_set_position(&toplevel->border[0]->node, bw, 0); - wlr_scene_node_set_position(&toplevel->border[1]->node, bw, toplevel->geom.height - bw); + wlr_scene_node_set_position(&toplevel->border[1]->node, bw, + toplevel->geom.height - bw); wlr_scene_node_set_position(&toplevel->border[2]->node, 0, 0); - wlr_scene_node_set_position(&toplevel->border[3]->node, toplevel->geom.width - bw, 0); + wlr_scene_node_set_position(&toplevel->border[3]->node, + toplevel->geom.width - bw, 0); } void toplevel_set_pos(absn_toplevel *toplevel, int32_t x, int32_t y) @@ -107,8 +116,9 @@ 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)) + (width == toplevel->geom.width && height == toplevel->geom.height)) { return; + } toplevel->geom.width = width; toplevel->geom.height = height; @@ -124,13 +134,17 @@ void toplevel_set_size(absn_toplevel *toplevel, int32_t width, int32_t height) }; if (toplevel->type == TOPLEVEL_XDG) { - if (wl_resource_get_version(toplevel->xdg->resource) >= XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION) + if (wl_resource_get_version(toplevel->xdg->resource) >= + XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION) { wlr_xdg_toplevel_set_bounds(toplevel->xdg, width, height); - toplevel->resizing = wlr_xdg_toplevel_set_size(toplevel->xdg, width - 2 * bw, height - 2 * bw); + } + toplevel->resizing = wlr_xdg_toplevel_set_size( + toplevel->xdg, width - 2 * bw, height - 2 * bw); } #ifdef XWAYLAND else if (toplevel->type == TOPLEVEL_X11) { - wlr_xwayland_surface_configure(toplevel->xw, toplevel->geom.x, toplevel->geom.y, width - 2 * 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); @@ -148,23 +162,28 @@ void toplevel_set_geom(absn_toplevel *toplevel, struct wlr_box *geom) void toplevel_set_floating(absn_toplevel *toplevel, bool floating) { - if (!toplevel || toplevel->floating == floating) + if (!toplevel || toplevel->floating == floating) { return; + } toplevel->floating = floating; - if (floating) - wlr_scene_node_reparent(&toplevel->scene_tree->node, toplevel->server->layers[LAYER_FLOAT]); - else - wlr_scene_node_reparent(&toplevel->scene_tree->node, toplevel->server->layers[LAYER_TILE]); + if (floating) { + wlr_scene_node_reparent(&toplevel->scene_tree->node, + toplevel->server->layers[LAYER_FLOAT]); + } else { + wlr_scene_node_reparent(&toplevel->scene_tree->node, + toplevel->server->layers[LAYER_TILE]); + } layout_arrange(toplevel->output); } void toplevel_set_fullscreen(absn_toplevel *toplevel, bool fullscreen) { - if (!toplevel || toplevel->fullscreen == fullscreen) + if (!toplevel || toplevel->fullscreen == fullscreen) { return; + } absn_output *output = toplevel->server->focused_output; toplevel->fullscreen = fullscreen; @@ -175,14 +194,18 @@ void toplevel_set_fullscreen(absn_toplevel *toplevel, bool fullscreen) toplevel->bw = 0; toplevel_set_geom(toplevel, &output->geom); - wlr_scene_node_reparent(&toplevel->scene_tree->node, toplevel->server->layers[LAYER_FULLSCREEN]); + wlr_scene_node_reparent(&toplevel->scene_tree->node, + toplevel->server->layers[LAYER_FULLSCREEN]); } else { toplevel->bw = toplevel_is_unmanaged(toplevel) ? 0 : TOPLEVEL_BW; toplevel_set_geom(toplevel, &toplevel->prev_geom); - if (toplevel->floating) - wlr_scene_node_reparent(&toplevel->scene_tree->node, toplevel->server->layers[LAYER_FLOAT]); - else - wlr_scene_node_reparent(&toplevel->scene_tree->node, toplevel->server->layers[LAYER_TILE]); + if (toplevel->floating) { + wlr_scene_node_reparent(&toplevel->scene_tree->node, + toplevel->server->layers[LAYER_FLOAT]); + } else { + wlr_scene_node_reparent(&toplevel->scene_tree->node, + toplevel->server->layers[LAYER_TILE]); + } } toplevel_update_borders_geom(toplevel); @@ -192,8 +215,9 @@ void toplevel_set_fullscreen(absn_toplevel *toplevel, bool fullscreen) void toplevel_set_border_color(absn_toplevel *toplevel, const float color[4]) { - if (!toplevel) + if (!toplevel) { return; + } for (int i = 0; i < 4; ++i) { wlr_scene_rect_set_color(toplevel->border[i], color); } diff --git a/src/xdg-decoration.c b/src/xdg-decoration.c index 71e3763..023b42f 100644 --- a/src/xdg-decoration.c +++ b/src/xdg-decoration.c @@ -5,9 +5,12 @@ void deco_request_mode(struct wl_listener *listener, void *data) { UNUSED(data); - absn_toplevel *toplevel = wl_container_of(listener, toplevel, deco_request_mode); - if (toplevel->xdg->base->initialized) - wlr_xdg_toplevel_decoration_v1_set_mode(toplevel->deco, WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); + absn_toplevel *toplevel = + wl_container_of(listener, toplevel, deco_request_mode); + if (toplevel->xdg->base->initialized) { + wlr_xdg_toplevel_decoration_v1_set_mode( + toplevel->deco, WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); + } } void deco_destroy(struct wl_listener *listener, void *data) diff --git a/src/xdg-popup.c b/src/xdg-popup.c index b8b619a..bb01392 100644 --- a/src/xdg-popup.c +++ b/src/xdg-popup.c @@ -1,24 +1,25 @@ -#include -#include - #include "types.h" void xdg_popup_commit(struct wl_listener *listener, void *data) { UNUSED(data); absn_popup *popup = wl_container_of(listener, popup, commit); + struct wlr_box box; - if (popup->wlr->base->initial_commit) - wlr_xdg_surface_schedule_configure(popup->wlr->base); -} + if (popup->parent_type == TOPLEVEL_XDG) { + absn_toplevel *toplevel = popup->parent; + box = toplevel->output->usable_area; + box.x -= toplevel->geom.x; + box.y -= toplevel->geom.y; + } else { + absn_layer_surface *layer_surface = popup->parent; + box = layer_surface->output->geom; + box.x -= layer_surface->popups->node.x; + box.y -= layer_surface->popups->node.y; + } -void xdg_popup_destroy(struct wl_listener *listener, void *data) -{ - UNUSED(data); - absn_popup *popup = wl_container_of(listener, popup, destroy); + wlr_xdg_popup_unconstrain_from_box(popup->wlr, &box); wl_list_remove(&popup->commit.link); - wl_list_remove(&popup->destroy.link); - free(popup); } diff --git a/src/xdg-toplevel.c b/src/xdg-toplevel.c index 6849286..dcac164 100644 --- a/src/xdg-toplevel.c +++ b/src/xdg-toplevel.c @@ -10,15 +10,17 @@ void toplevel_commit(struct wl_listener *listener, void *data) UNUSED(data); absn_toplevel *toplevel = wl_container_of(listener, toplevel, commit); - if (toplevel->xdg->base->current.configure_serial < toplevel->resizing) + if (toplevel->xdg->base->current.configure_serial < toplevel->resizing) { return; + } if (toplevel->xdg->base->initial_commit) { wlr_xdg_toplevel_set_activated(toplevel->xdg, false); /* forse server side decoration mode */ - if (toplevel->deco) + if (toplevel->deco) { deco_request_mode(&toplevel->deco_request_mode, toplevel->deco); + } /* let client set initial size */ toplevel->resizing = wlr_xdg_toplevel_set_size(toplevel->xdg, 0, 0); return; diff --git a/src/xwayland.c b/src/xwayland.c index bd95d19..a2173de 100644 --- a/src/xwayland.c +++ b/src/xwayland.c @@ -10,8 +10,9 @@ void xwayland_activate(struct wl_listener *listener, void *data) UNUSED(data); absn_toplevel *toplevel = wl_container_of(listener, toplevel, xw_activate); - if (!toplevel_is_unmanaged(toplevel)) + if (!toplevel_is_unmanaged(toplevel)) { wlr_xwayland_surface_activate(toplevel->xw, 1); + } } void xwayland_associate(struct wl_listener *listener, void *data) @@ -20,13 +21,15 @@ void xwayland_associate(struct wl_listener *listener, void *data) absn_toplevel *toplevel = wl_container_of(listener, toplevel, xw_associate); LISTEN(toplevel->map, toplevel_map, toplevel->xw->surface->events.map); - LISTEN(toplevel->unmap, toplevel_unmap, toplevel->xw->surface->events.unmap); + LISTEN(toplevel->unmap, toplevel_unmap, + toplevel->xw->surface->events.unmap); } void xwayland_dissociate(struct wl_listener *listener, void *data) { UNUSED(data); - absn_toplevel *toplevel = wl_container_of(listener, toplevel, xw_dissociate); + absn_toplevel *toplevel = + wl_container_of(listener, toplevel, xw_dissociate); wl_list_remove(&toplevel->map.link); wl_list_remove(&toplevel->unmap.link); @@ -39,13 +42,16 @@ void xwayland_configure(struct wl_listener *listener, void *data) struct wlr_xwayland_surface_configure_event *event = data; if (!toplevel->xw->surface || !toplevel->xw->surface->mapped) { - wlr_xwayland_surface_configure(toplevel->xw, event->x, event->y, event->width, event->height); + wlr_xwayland_surface_configure(toplevel->xw, event->x, event->y, + event->width, event->height); return; } if (toplevel_is_unmanaged(toplevel)) { - wlr_scene_node_set_position(&toplevel->scene_tree->node, event->x, event->y); - wlr_xwayland_surface_configure(toplevel->xw, event->x, event->y, event->width, event->height); + wlr_scene_node_set_position(&toplevel->scene_tree->node, event->x, + event->y); + wlr_xwayland_surface_configure(toplevel->xw, event->x, event->y, + event->width, event->height); return; } }