diff options
Diffstat (limited to 'dwl.c')
-rw-r--r-- | dwl.c | 509 |
1 files changed, 204 insertions, 305 deletions
@@ -24,6 +24,7 @@ #include <wlr/types/wlr_gamma_control_v1.h> #include <wlr/types/wlr_idle.h> #include <wlr/types/wlr_idle_inhibit_v1.h> +#include <wlr/types/wlr_idle_notify_v1.h> #include <wlr/types/wlr_input_device.h> #include <wlr/types/wlr_input_inhibitor.h> #include <wlr/types/wlr_keyboard.h> @@ -39,6 +40,8 @@ #include <wlr/types/wlr_screencopy_v1.h> #include <wlr/types/wlr_seat.h> #include <wlr/types/wlr_server_decoration.h> +#include <wlr/types/wlr_single_pixel_buffer_v1.h> +#include <wlr/types/wlr_subcompositor.h> #include <wlr/types/wlr_viewporter.h> #include <wlr/types/wlr_virtual_keyboard_v1.h> #include <wlr/types/wlr_xcursor_manager.h> @@ -49,8 +52,9 @@ #include <wlr/util/log.h> #include <xkbcommon/xkbcommon.h> #ifdef XWAYLAND -#include <X11/Xlib.h> #include <wlr/xwayland.h> +#include <X11/Xlib.h> +#include <xcb/xcb_icccm.h> #endif #include "util.h" @@ -64,11 +68,12 @@ #define END(A) ((A) + LENGTH(A)) #define TAGMASK ((1 << LENGTH(tags)) - 1) #define LISTEN(E, L, H) wl_signal_add((E), ((L)->notify = (H), (L))) +#define IDLE_NOTIFY_ACTIVITY wlr_idle_notify_activity(idle, seat), wlr_idle_notifier_v1_notify_activity(idle_notifier, seat) /* enums */ enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */ enum { XDGShell, LayerShell, X11Managed, X11Unmanaged }; /* client types */ -enum { LyrBg, LyrBottom, LyrTop, LyrOverlay, LyrTile, LyrFloat, LyrDragIcon, NUM_LAYERS }; /* scene layers */ +enum { LyrBg, LyrBottom, LyrTop, LyrOverlay, LyrTile, LyrFloat, LyrFS, LyrDragIcon, NUM_LAYERS }; /* scene layers */ #ifdef XWAYLAND enum { NetWMWindowTypeDialog, NetWMWindowTypeSplash, NetWMWindowTypeToolbar, NetWMWindowTypeUtility, NetLast }; /* EWMH atoms */ @@ -94,10 +99,9 @@ typedef struct { unsigned int type; /* XDGShell or X11* */ struct wlr_box geom; /* layout-relative, includes border */ Monitor *mon; - struct wlr_scene_node *scene; + struct wlr_scene_tree *scene; struct wlr_scene_rect *border[4]; /* top, bottom, left, right */ - struct wlr_scene_node *scene_surface; - struct wlr_scene_rect *fullscreen_bg; /* See setfullscreen() for info */ + struct wlr_scene_tree *scene_surface; struct wl_list link; struct wl_list flink; union { @@ -106,6 +110,7 @@ typedef struct { } surface; struct wl_listener commit; struct wl_listener map; + struct wl_listener maximize; struct wl_listener unmap; struct wl_listener destroy; struct wl_listener set_title; @@ -123,14 +128,6 @@ typedef struct { } Client; typedef struct { - uint32_t singular_anchor; - uint32_t anchor_triplet; - int *positive_axis; - int *negative_axis; - int margin; -} Edge; - -typedef struct { uint32_t mod; xkb_keysym_t keysym; void (*func)(const Arg *); @@ -139,7 +136,7 @@ typedef struct { typedef struct { struct wl_list link; - struct wlr_input_device *device; + struct wlr_keyboard *wlr_keyboard; struct wl_listener modifiers; struct wl_listener key; @@ -151,8 +148,9 @@ typedef struct { unsigned int type; /* LayerShell */ struct wlr_box geom; Monitor *mon; - struct wlr_scene_node *scene; - struct wlr_scene_node *popups; + struct wlr_scene_tree *scene; + struct wlr_scene_tree *popups; + struct wlr_scene_layer_surface_v1 *scene_layer; struct wl_list link; int mapped; struct wlr_layer_surface_v1 *layer_surface; @@ -172,6 +170,7 @@ struct Monitor { struct wl_list link; struct wlr_output *wlr_output; struct wlr_scene_output *scene_output; + struct wlr_scene_rect *fullscreen_bg; /* See createmon() for info */ struct wl_listener frame; struct wl_listener destroy; struct wlr_box m; /* monitor area, layout-relative */ @@ -205,9 +204,6 @@ typedef struct { /* function declarations */ static void applybounds(Client *c, struct wlr_box *bbox); -static void applyexclusive(struct wlr_box *usable_area, uint32_t anchor, - int32_t exclusive, int32_t margin_top, int32_t margin_right, - int32_t margin_bottom, int32_t margin_left); static void applyrules(Client *c); static void arrange(Monitor *m); static void arrangelayer(Monitor *m, struct wl_list *list, @@ -224,11 +220,11 @@ static void closemon(Monitor *m); static void commitlayersurfacenotify(struct wl_listener *listener, void *data); static void commitnotify(struct wl_listener *listener, void *data); static void createidleinhibitor(struct wl_listener *listener, void *data); -static void createkeyboard(struct wlr_input_device *device); +static void createkeyboard(struct wlr_keyboard *keyboard); static void createlayersurface(struct wl_listener *listener, void *data); static void createmon(struct wl_listener *listener, void *data); static void createnotify(struct wl_listener *listener, void *data); -static void createpointer(struct wlr_input_device *device); +static void createpointer(struct wlr_pointer *pointer); static void cursorframe(struct wl_listener *listener, void *data); static void destroydragicon(struct wl_listener *listener, void *data); static void destroyidleinhibitor(struct wl_listener *listener, void *data); @@ -248,6 +244,7 @@ static void keypressmod(struct wl_listener *listener, void *data); static void killclient(const Arg *arg); static void maplayersurfacenotify(struct wl_listener *listener, void *data); static void mapnotify(struct wl_listener *listener, void *data); +static void maximizenotify(struct wl_listener *listener, void *data); static void monocle(Monitor *m); static void motionabsolute(struct wl_listener *listener, void *data); static void motionnotify(uint32_t time); @@ -275,7 +272,6 @@ static void setmon(Client *c, Monitor *m, unsigned int newtags); static void setpsel(struct wl_listener *listener, void *data); static void setsel(struct wl_listener *listener, void *data); static void setup(void); -static void sigchld(int unused); static void spawn(const Arg *arg); static void startdrag(struct wl_listener *listener, void *data); static void tag(const Arg *arg); @@ -305,7 +301,7 @@ static void *exclusive_focus; static struct wl_display *dpy; static struct wlr_backend *backend; static struct wlr_scene *scene; -static struct wlr_scene_node *layers[NUM_LAYERS]; +static struct wlr_scene_tree *layers[NUM_LAYERS]; static struct wlr_renderer *drw; static struct wlr_allocator *alloc; static struct wlr_compositor *compositor; @@ -315,6 +311,7 @@ static struct wlr_xdg_activation_v1 *activation; static struct wl_list clients; /* tiling order */ static struct wl_list fstack; /* focus order */ static struct wlr_idle *idle; +static struct wlr_idle_notifier_v1 *idle_notifier; static struct wlr_idle_inhibit_manager_v1 *idle_inhibit_mgr; static struct wlr_input_inhibit_manager *input_inhibit_mgr; static struct wlr_layer_shell_v1 *layer_shell; @@ -365,6 +362,7 @@ static void configurex11(struct wl_listener *listener, void *data); static void createnotifyx11(struct wl_listener *listener, void *data); static Atom getatom(xcb_connection_t *xc, const char *name); static void sethints(struct wl_listener *listener, void *data); +static void sigchld(int unused); static void xwaylandready(struct wl_listener *listener, void *data); static struct wl_listener new_xwayland_surface = {.notify = createnotifyx11}; static struct wl_listener xwayland_ready = {.notify = xwaylandready}; @@ -410,62 +408,6 @@ applybounds(Client *c, struct wlr_box *bbox) } void -applyexclusive(struct wlr_box *usable_area, - uint32_t anchor, int32_t exclusive, - int32_t margin_top, int32_t margin_right, - int32_t margin_bottom, int32_t margin_left) { - size_t i; - Edge edges[] = { - { /* Top */ - .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP, - .anchor_triplet = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | - ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | - ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP, - .positive_axis = &usable_area->y, - .negative_axis = &usable_area->height, - .margin = margin_top, - }, - { /* Bottom */ - .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM, - .anchor_triplet = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | - ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | - ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM, - .positive_axis = NULL, - .negative_axis = &usable_area->height, - .margin = margin_bottom, - }, - { /* Left */ - .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT, - .anchor_triplet = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | - ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | - ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM, - .positive_axis = &usable_area->x, - .negative_axis = &usable_area->width, - .margin = margin_left, - }, - { /* Right */ - .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT, - .anchor_triplet = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | - ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | - ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM, - .positive_axis = NULL, - .negative_axis = &usable_area->width, - .margin = margin_right, - } - }; - for (i = 0; i < LENGTH(edges); i++) { - if ((anchor == edges[i].singular_anchor || anchor == edges[i].anchor_triplet) - && exclusive + edges[i].margin > 0) { - if (edges[i].positive_axis) - *edges[i].positive_axis += exclusive + edges[i].margin; - if (edges[i].negative_axis) - *edges[i].negative_axis -= exclusive + edges[i].margin; - break; - } - } -} - -void applyrules(Client *c) { /* rule matching */ @@ -491,7 +433,7 @@ applyrules(Client *c) mon = m; } } - wlr_scene_node_reparent(c->scene, layers[c->isfloating ? LyrFloat : LyrTile]); + wlr_scene_node_reparent(&c->scene->node, layers[c->isfloating ? LyrFloat : LyrTile]); setmon(c, mon, newtags); } @@ -501,7 +443,10 @@ arrange(Monitor *m) Client *c; wl_list_for_each(c, &clients, link) if (c->mon == m) - wlr_scene_node_set_enabled(c->scene, VISIBLEON(c, m)); + wlr_scene_node_set_enabled(&c->scene->node, VISIBLEON(c, m)); + + wlr_scene_node_set_enabled(&m->fullscreen_bg->node, + (c = focustop(m)) && c->isfullscreen); if (m && m->lt[m->sellt]->arrange) m->lt[m->sellt]->arrange(m); @@ -517,75 +462,15 @@ arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int wl_list_for_each(layersurface, list, link) { struct wlr_layer_surface_v1 *wlr_layer_surface = layersurface->layer_surface; struct wlr_layer_surface_v1_state *state = &wlr_layer_surface->current; - struct wlr_box bounds; - struct wlr_box box = { - .width = state->desired_width, - .height = state->desired_height - }; - const uint32_t both_horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT - | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; - const uint32_t both_vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP - | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; - - /* Unmapped surfaces shouldn't have exclusive zone */ - if (!((LayerSurface *)wlr_layer_surface->data)->mapped - || exclusive != (state->exclusive_zone > 0)) - continue; - - bounds = state->exclusive_zone == -1 ? full_area : *usable_area; - /* Horizontal axis */ - if ((state->anchor & both_horiz) && box.width == 0) { - box.x = bounds.x; - box.width = bounds.width; - } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) { - box.x = bounds.x; - } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) { - box.x = bounds.x + (bounds.width - box.width); - } else { - box.x = bounds.x + ((bounds.width / 2) - (box.width / 2)); - } - /* Vertical axis */ - if ((state->anchor & both_vert) && box.height == 0) { - box.y = bounds.y; - box.height = bounds.height; - } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) { - box.y = bounds.y; - } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) { - box.y = bounds.y + (bounds.height - box.height); - } else { - box.y = bounds.y + ((bounds.height / 2) - (box.height / 2)); - } - /* Margin */ - if ((state->anchor & both_horiz) == both_horiz) { - box.x += state->margin.left; - box.width -= state->margin.left + state->margin.right; - } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) { - box.x += state->margin.left; - } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) { - box.x -= state->margin.right; - } - if ((state->anchor & both_vert) == both_vert) { - box.y += state->margin.top; - box.height -= state->margin.top + state->margin.bottom; - } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) { - box.y += state->margin.top; - } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) { - box.y -= state->margin.bottom; - } - if (box.width < 0 || box.height < 0) { - wlr_layer_surface_v1_destroy(wlr_layer_surface); + if (exclusive != (state->exclusive_zone > 0)) continue; - } - layersurface->geom = box; - - if (state->exclusive_zone > 0) - applyexclusive(usable_area, state->anchor, state->exclusive_zone, - state->margin.top, state->margin.right, - state->margin.bottom, state->margin.left); - wlr_scene_node_set_position(layersurface->scene, box.x, box.y); - wlr_scene_node_set_position(layersurface->popups, box.x, box.y); - wlr_layer_surface_v1_configure(wlr_layer_surface, box.width, box.height); + + wlr_scene_layer_surface_v1_configure(layersurface->scene_layer, &full_area, usable_area); + wlr_scene_node_set_position(&layersurface->popups->node, + layersurface->scene->node.x, layersurface->scene->node.y); + layersurface->geom.x = layersurface->scene->node.x; + layersurface->geom.y = layersurface->scene->node.y; } } @@ -636,8 +521,8 @@ axisnotify(struct wl_listener *listener, void *data) { /* This event is forwarded by the cursor when a pointer emits an axis event, * for example when you move the scroll wheel. */ - struct wlr_event_pointer_axis *event = data; - wlr_idle_notify_activity(idle, seat); + struct wlr_pointer_axis_event *event = data; + IDLE_NOTIFY_ACTIVITY; /* TODO: allow usage of scroll whell for mousebindings, it can be implemented * checking the event's orientation and the delta of the event */ /* Notify the client with pointer focus of the axis event. */ @@ -649,13 +534,13 @@ axisnotify(struct wl_listener *listener, void *data) void buttonpress(struct wl_listener *listener, void *data) { - struct wlr_event_pointer_button *event = data; + struct wlr_pointer_button_event *event = data; struct wlr_keyboard *keyboard; uint32_t mods; Client *c; const Button *b; - wlr_idle_notify_activity(idle, seat); + IDLE_NOTIFY_ACTIVITY; switch (event->state) { case WLR_BUTTON_PRESSED: @@ -711,19 +596,16 @@ checkidleinhibitor(struct wlr_surface *exclude) int inhibited = 0; struct wlr_idle_inhibitor_v1 *inhibitor; wl_list_for_each(inhibitor, &idle_inhibit_mgr->inhibitors, link) { - Client *c; - if (exclude == inhibitor->surface) - continue; - /* In case we can't get a client from the surface assume that it is - * visible, for example a layer surface */ - if (!(c = client_from_wlr_surface(inhibitor->surface)) - || VISIBLEON(c, c->mon)) { + struct wlr_scene_tree *tree = inhibitor->surface->data; + if (bypass_surface_visibility || (exclude != inhibitor->surface + && tree->node.enabled)) { inhibited = 1; break; } } wlr_idle_set_enabled(idle, NULL, !inhibited); + wlr_idle_notifier_v1_set_inhibited(idle_notifier, inhibited); } void @@ -766,12 +648,9 @@ cleanupmon(struct wl_listener *listener, void *data) LayerSurface *l, *tmp; int i; - for (i = 0; i <= ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY; i++) { - wl_list_for_each_safe(l, tmp, &m->layers[i], link) { - wlr_scene_node_set_enabled(l->scene, 0); + for (i = 0; i <= ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY; i++) + wl_list_for_each_safe(l, tmp, &m->layers[i], link) wlr_layer_surface_v1_destroy(l->layer_surface); - } - } wl_list_remove(&m->destroy.link); wl_list_remove(&m->frame.link); @@ -779,6 +658,7 @@ cleanupmon(struct wl_listener *listener, void *data) m->wlr_output->data = NULL; wlr_output_layout_remove(output_layout, m->wlr_output); wlr_scene_output_destroy(m->scene_output); + wlr_scene_node_destroy(&m->fullscreen_bg->node); closemon(m); free(m); @@ -822,17 +702,17 @@ commitlayersurfacenotify(struct wl_listener *listener, void *data) if (!wlr_output || !(layersurface->mon = wlr_output->data)) return; - if (layers[wlr_layer_surface->current.layer] != layersurface->scene->parent) { - wlr_scene_node_reparent(layersurface->scene, + if (layers[wlr_layer_surface->current.layer] != layersurface->scene->node.parent) { + wlr_scene_node_reparent(&layersurface->scene->node, layers[wlr_layer_surface->current.layer]); - wlr_scene_node_reparent(layersurface->popups, + wlr_scene_node_reparent(&layersurface->popups->node, layers[wlr_layer_surface->current.layer]); wl_list_remove(&layersurface->link); wl_list_insert(&layersurface->mon->layers[wlr_layer_surface->current.layer], &layersurface->link); } if (wlr_layer_surface->current.layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP) - wlr_scene_node_reparent(layersurface->popups, layers[LyrTop]); + wlr_scene_node_reparent(&layersurface->popups->node, layers[LyrTop]); if (wlr_layer_surface->current.committed == 0 && layersurface->mapped == wlr_layer_surface->mapped) @@ -870,29 +750,29 @@ createidleinhibitor(struct wl_listener *listener, void *data) } void -createkeyboard(struct wlr_input_device *device) +createkeyboard(struct wlr_keyboard *keyboard) { struct xkb_context *context; struct xkb_keymap *keymap; - Keyboard *kb = device->data = ecalloc(1, sizeof(*kb)); - kb->device = device; + Keyboard *kb = keyboard->data = ecalloc(1, sizeof(*kb)); + kb->wlr_keyboard = keyboard; /* Prepare an XKB keymap and assign it to the keyboard. */ context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); keymap = xkb_keymap_new_from_names(context, &xkb_rules, XKB_KEYMAP_COMPILE_NO_FLAGS); - wlr_keyboard_set_keymap(device->keyboard, keymap); + wlr_keyboard_set_keymap(keyboard, keymap); xkb_keymap_unref(keymap); xkb_context_unref(context); - wlr_keyboard_set_repeat_info(device->keyboard, repeat_rate, repeat_delay); + wlr_keyboard_set_repeat_info(keyboard, repeat_rate, repeat_delay); /* Here we set up listeners for keyboard events. */ - LISTEN(&device->keyboard->events.modifiers, &kb->modifiers, keypressmod); - LISTEN(&device->keyboard->events.key, &kb->key, keypress); - LISTEN(&device->events.destroy, &kb->destroy, cleanupkeyboard); + LISTEN(&keyboard->events.modifiers, &kb->modifiers, keypressmod); + LISTEN(&keyboard->events.key, &kb->key, keypress); + LISTEN(&keyboard->base.events.destroy, &kb->destroy, cleanupkeyboard); - wlr_seat_set_keyboard(seat, device); + wlr_seat_set_keyboard(seat, keyboard); /* And add the keyboard to our list of keyboards */ wl_list_insert(&keyboards, &kb->link); @@ -926,11 +806,13 @@ createlayersurface(struct wl_listener *listener, void *data) layersurface->mon = wlr_layer_surface->output->data; wlr_layer_surface->data = layersurface; - layersurface->scene = wlr_scene_subsurface_tree_create( - layers[wlr_layer_surface->pending.layer], wlr_layer_surface->surface); - layersurface->scene->data = layersurface; + layersurface->scene_layer = wlr_scene_layer_surface_v1_create( + layers[wlr_layer_surface->pending.layer], wlr_layer_surface); + layersurface->scene = layersurface->scene_layer->tree; layersurface->popups = wlr_layer_surface->surface->data = - &wlr_scene_tree_create(layers[wlr_layer_surface->pending.layer])->node; + wlr_scene_tree_create(layers[wlr_layer_surface->pending.layer]); + + layersurface->scene->node.data = layersurface; wl_list_insert(&layersurface->mon->layers[wlr_layer_surface->pending.layer], &layersurface->link); @@ -979,7 +861,6 @@ createmon(struct wl_listener *listener, void *data) * monitor's preferred mode; a more sophisticated compositor would let * the user configure it. */ wlr_output_set_mode(wlr_output, wlr_output_preferred_mode(wlr_output)); - wlr_output_enable_adaptive_sync(wlr_output, 1); /* Set up event listeners */ LISTEN(&wlr_output->events.frame, &m->frame, rendermon); @@ -989,9 +870,26 @@ createmon(struct wl_listener *listener, void *data) if (!wlr_output_commit(wlr_output)) return; + /* Try to enable adaptive sync, note that not all monitors support it. + * wlr_output_commit() will deactivate it in case it cannot be enabled */ + wlr_output_enable_adaptive_sync(wlr_output, 1); + wlr_output_commit(wlr_output); + wl_list_insert(&mons, &m->link); printstatus(); + /* The xdg-protocol specifies: + * + * If the fullscreened surface is not opaque, the compositor must make + * sure that other screen content not part of the same surface tree (made + * up of subsurfaces, popups or similarly coupled surfaces) are not + * visible below the fullscreened surface. + * + */ + /* updatemons() will resize and set correct position */ + m->fullscreen_bg = wlr_scene_rect_create(layers[LyrFS], 0, 0, fullscreen_bg); + wlr_scene_node_set_enabled(&m->fullscreen_bg->node, 0); + /* Adds this to the output layout in the order it was configured in. * * The output layout utility automatically adds a wl_output global to the @@ -1043,14 +941,16 @@ createnotify(struct wl_listener *listener, void *data) LISTEN(&xdg_surface->toplevel->events.set_title, &c->set_title, updatetitle); LISTEN(&xdg_surface->toplevel->events.request_fullscreen, &c->fullscreen, fullscreennotify); + LISTEN(&xdg_surface->toplevel->events.request_maximize, &c->maximize, + maximizenotify); } void -createpointer(struct wlr_input_device *device) +createpointer(struct wlr_pointer *pointer) { - if (wlr_input_device_is_libinput(device)) { + if (wlr_input_device_is_libinput(&pointer->base)) { struct libinput_device *libinput_device = (struct libinput_device*) - wlr_libinput_get_device_handle(device); + wlr_libinput_get_device_handle(&pointer->base); if (libinput_device_config_tap_get_finger_count(libinput_device)) { libinput_device_config_tap_set_enabled(libinput_device, tap_to_click); @@ -1085,7 +985,7 @@ createpointer(struct wlr_input_device *device) } } - wlr_cursor_attach_input_device(cursor, device); + wlr_cursor_attach_input_device(cursor, &pointer->base); } void @@ -1127,7 +1027,7 @@ destroylayersurfacenotify(struct wl_listener *listener, void *data) wl_list_remove(&layersurface->map.link); wl_list_remove(&layersurface->unmap.link); wl_list_remove(&layersurface->surface_commit.link); - wlr_scene_node_destroy(layersurface->scene); + wlr_scene_node_destroy(&layersurface->scene->node); free(layersurface); } @@ -1175,7 +1075,7 @@ focusclient(Client *c, int lift) /* Raise client in stacking order if requested */ if (c && lift) - wlr_scene_node_raise_to_top(c->scene); + wlr_scene_node_raise_to_top(&c->scene->node); if (c && client_surface(c) == old) return; @@ -1256,7 +1156,7 @@ focusstack(const Arg *arg) { /* Focus the next or previous client (in tiling order) on selmon */ Client *c, *sel = selclient(); - if (!sel || (sel->isfullscreen && lockfullscreen)) + if (!sel || sel->isfullscreen) return; if (arg->i > 0) { wl_list_for_each(c, &sel->link, link) { @@ -1316,10 +1216,10 @@ inputdevice(struct wl_listener *listener, void *data) switch (device->type) { case WLR_INPUT_DEVICE_KEYBOARD: - createkeyboard(device); + createkeyboard(wlr_keyboard_from_input_device(device)); break; case WLR_INPUT_DEVICE_POINTER: - createpointer(device); + createpointer(wlr_pointer_from_input_device(device)); break; default: /* TODO handle other input device types */ @@ -1362,19 +1262,19 @@ keypress(struct wl_listener *listener, void *data) int i; /* This event is raised when a key is pressed or released. */ Keyboard *kb = wl_container_of(listener, kb, key); - struct wlr_event_keyboard_key *event = data; + struct wlr_keyboard_key_event *event = data; /* Translate libinput keycode -> xkbcommon */ uint32_t keycode = event->keycode + 8; /* Get a list of keysyms based on the keymap for this keyboard */ const xkb_keysym_t *syms; int nsyms = xkb_state_key_get_syms( - kb->device->keyboard->xkb_state, keycode, &syms); + kb->wlr_keyboard->xkb_state, keycode, &syms); int handled = 0; - uint32_t mods = wlr_keyboard_get_modifiers(kb->device->keyboard); + uint32_t mods = wlr_keyboard_get_modifiers(kb->wlr_keyboard); - wlr_idle_notify_activity(idle, seat); + IDLE_NOTIFY_ACTIVITY; /* On _press_ if there is no active screen locker, * attempt to process a compositor keybinding. */ @@ -1385,7 +1285,7 @@ keypress(struct wl_listener *listener, void *data) if (!handled) { /* Pass unhandled keycodes along to the client. */ - wlr_seat_set_keyboard(seat, kb->device); + wlr_seat_set_keyboard(seat, kb->wlr_keyboard); wlr_seat_keyboard_notify_key(seat, event->time_msec, event->keycode, event->state); } @@ -1403,10 +1303,10 @@ keypressmod(struct wl_listener *listener, void *data) * same seat. You can swap out the underlying wlr_keyboard like this and * wlr_seat handles this transparently. */ - wlr_seat_set_keyboard(seat, kb->device); + wlr_seat_set_keyboard(seat, kb->wlr_keyboard); /* Send modifiers to the client. */ wlr_seat_keyboard_notify_modifiers(seat, - &kb->device->keyboard->modifiers); + &kb->wlr_keyboard->modifiers); } void @@ -1433,27 +1333,25 @@ mapnotify(struct wl_listener *listener, void *data) int i; /* Create scene tree for this client and its border */ - c->scene = &wlr_scene_tree_create(layers[LyrTile])->node; + c->scene = wlr_scene_tree_create(layers[LyrTile]); c->scene_surface = c->type == XDGShell ? wlr_scene_xdg_surface_create(c->scene, c->surface.xdg) : wlr_scene_subsurface_tree_create(c->scene, client_surface(c)); if (client_surface(c)) { client_surface(c)->data = c->scene; /* Ideally we should do this in createnotify{,x11} but at that moment - * wlr_xwayland_surface doesn't have wlr_surface yet - */ + * wlr_xwayland_surface doesn't have wlr_surface yet. */ LISTEN(&client_surface(c)->events.commit, &c->commit, commitnotify); - } - c->scene->data = c->scene_surface->data = c; + c->scene->node.data = c->scene_surface->node.data = c; #ifdef XWAYLAND /* Handle unmanaged clients first so we can return prior create borders */ if (client_is_unmanaged(c)) { client_get_geometry(c, &c->geom); /* Unmanaged clients always are floating */ - wlr_scene_node_reparent(c->scene, layers[LyrFloat]); - wlr_scene_node_set_position(c->scene, c->geom.x + borderpx, + wlr_scene_node_reparent(&c->scene->node, layers[LyrFloat]); + wlr_scene_node_set_position(&c->scene->node, c->geom.x + borderpx, c->geom.y + borderpx); if (client_wants_focus(c)) { focusclient(c, 1); @@ -1483,9 +1381,10 @@ mapnotify(struct wl_listener *listener, void *data) * we always consider floating, clients that have parent and thus * we set the same tags and monitor than its parent, if not * try to apply rules for them */ - if ((p = client_get_parent(c)) && client_is_mapped(p)) { + /* TODO: https://github.com/djpohly/dwl/pull/334#issuecomment-1330166324 */ + if (c->type == XDGShell && (p = client_get_parent(c))) { c->isfloating = 1; - wlr_scene_node_reparent(c->scene, layers[LyrFloat]); + wlr_scene_node_reparent(&c->scene->node, layers[LyrFloat]); setmon(c, p->mon, p->tags); } else { applyrules(c); @@ -1496,6 +1395,18 @@ mapnotify(struct wl_listener *listener, void *data) } void +maximizenotify(struct wl_listener *listener, void *data) +{ + /* This event is raised when a client would like to maximize itself, + * typically because the user clicked on the maximize button on + * client-side decorations. dwl doesn't support maximization, but + * to conform to xdg-shell protocol we still must send a configure. + * wlr_xdg_surface_schedule_configure() is used to send an empty reply. */ + Client *c = wl_container_of(listener, c, maximize); + wlr_xdg_surface_schedule_configure(c->surface.xdg); +} + +void monocle(Monitor *m) { Client *c; @@ -1506,7 +1417,7 @@ monocle(Monitor *m) resize(c, m->w, 0); } if ((c = focustop(m))) - wlr_scene_node_raise_to_top(c->scene); + wlr_scene_node_raise_to_top(&c->scene->node); } void @@ -1518,8 +1429,8 @@ motionabsolute(struct wl_listener *listener, void *data) * move the mouse over the window. You could enter the window from any edge, * so we have to warp the mouse there. There is also some hardware which * emits these events. */ - struct wlr_event_pointer_motion_absolute *event = data; - wlr_cursor_warp_absolute(cursor, event->device, event->x, event->y); + struct wlr_pointer_motion_absolute_event *event = data; + wlr_cursor_warp_absolute(cursor, &event->pointer->base, event->x, event->y); motionnotify(event->time_msec); } @@ -1534,7 +1445,7 @@ motionnotify(uint32_t time) /* time is 0 in internal calls meant to restore pointer focus. */ if (time) { - wlr_idle_notify_activity(idle, seat); + IDLE_NOTIFY_ACTIVITY; /* Update selmon (even while dragging a window) */ if (sloppyfocus) @@ -1583,13 +1494,13 @@ motionrelative(struct wl_listener *listener, void *data) { /* This event is forwarded by the cursor when a pointer emits a _relative_ * pointer motion event (i.e. a delta) */ - struct wlr_event_pointer_motion *event = data; + struct wlr_pointer_motion_event *event = data; /* The cursor doesn't move unless we tell it to. The cursor automatically * handles constraining the motion to the output layout, as well as any * special configuration applied for the specific input device which * generated the event. You can pass NULL for the device if you want to move * the cursor around without any input. */ - wlr_cursor_move(cursor, event->device, event->delta_x, event->delta_y); + wlr_cursor_move(cursor, &event->pointer->base, event->delta_x, event->delta_y); motionnotify(event->time_msec); } @@ -1599,7 +1510,7 @@ moveresize(const Arg *arg) if (cursor_mode != CurNormal && cursor_mode != CurPressed) return; xytonode(cursor->x, cursor->y, NULL, &grabc, NULL, NULL, NULL); - if (!grabc || client_is_unmanaged(grabc)) + if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen) return; /* Float the window and tell motionnotify to grab it */ @@ -1663,29 +1574,15 @@ outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test) config_head->state.x, config_head->state.y); wlr_output_set_transform(wlr_output, config_head->state.transform); wlr_output_set_scale(wlr_output, config_head->state.scale); + wlr_output_enable_adaptive_sync(wlr_output, + config_head->state.adaptive_sync_enabled); apply_or_test: if (test) { ok &= wlr_output_test(wlr_output); wlr_output_rollback(wlr_output); } else { - int output_ok = 1; - /* If it's a custom mode to avoid an assertion failed in wlr_output_commit() - * we test if that mode does not fail rather than just call wlr_output_commit(). - * We do not test normal modes because (at least in my hardware (@sevz17)) - * wlr_output_test() fails even if that mode can actually be set */ - if (!config_head->state.mode && config_head->state.enabled) - ok &= (output_ok = wlr_output_test(wlr_output) - && wlr_output_commit(wlr_output)); - else - ok &= wlr_output_commit(wlr_output); - - /* In custom modes we call wlr_output_test(), it it fails - * we need to rollback, and normal modes seems to does not cause - * assertions failed in wlr_output_commit() which rollback - * the output on failure */ - if (!output_ok) - wlr_output_rollback(wlr_output); + ok &= wlr_output_commit(wlr_output); } } @@ -1830,12 +1727,13 @@ void resize(Client *c, struct wlr_box geo, int interact) { struct wlr_box *bbox = interact ? &sgeom : &c->mon->w; + client_set_bounds(c, geo.width, geo.height); c->geom = geo; applybounds(c, bbox); /* Update scene-graph, including borders */ - wlr_scene_node_set_position(c->scene, c->geom.x, c->geom.y); - wlr_scene_node_set_position(c->scene_surface, c->bw, c->bw); + wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y); + wlr_scene_node_set_position(&c->scene_surface->node, c->bw, c->bw); wlr_scene_rect_set_size(c->border[0], c->geom.width, c->bw); wlr_scene_rect_set_size(c->border[1], c->geom.width, c->bw); wlr_scene_rect_set_size(c->border[2], c->bw, c->geom.height - 2 * c->bw); @@ -1843,8 +1741,6 @@ resize(Client *c, struct wlr_box geo, int interact) wlr_scene_node_set_position(&c->border[1]->node, 0, c->geom.height - c->bw); wlr_scene_node_set_position(&c->border[2]->node, 0, c->bw); wlr_scene_node_set_position(&c->border[3]->node, c->geom.width - c->bw, c->bw); - if (c->fullscreen_bg) - wlr_scene_rect_set_size(c->fullscreen_bg, c->geom.width, c->geom.height); /* wlroots makes this a no-op if size hasn't changed */ c->resize = client_set_size(c, c->geom.width - 2 * c->bw, @@ -1939,7 +1835,7 @@ void setfloating(Client *c, int floating) { c->isfloating = floating; - wlr_scene_node_reparent(c->scene, layers[c->isfloating ? LyrFloat : LyrTile]); + wlr_scene_node_reparent(&c->scene->node, layers[c->isfloating ? LyrFloat : LyrTile]); arrange(c->mon); printstatus(); } @@ -1952,32 +1848,16 @@ setfullscreen(Client *c, int fullscreen) return; c->bw = fullscreen ? 0 : borderpx; client_set_fullscreen(c, fullscreen); + wlr_scene_node_reparent(&c->scene->node, layers[fullscreen + ? LyrFS : c->isfloating ? LyrFloat : LyrTile]); if (fullscreen) { c->prev = c->geom; resize(c, c->mon->m, 0); - /* The xdg-protocol specifies: - * - * If the fullscreened surface is not opaque, the compositor must make - * sure that other screen content not part of the same surface tree (made - * up of subsurfaces, popups or similarly coupled surfaces) are not - * visible below the fullscreened surface. - * - * For brevity we set a black background for all clients - */ - if (!c->fullscreen_bg) { - c->fullscreen_bg = wlr_scene_rect_create(c->scene, - c->geom.width, c->geom.height, fullscreen_bg); - wlr_scene_node_lower_to_bottom(&c->fullscreen_bg->node); - } } else { /* restore previous size instead of arrange for floating windows since * client positions are set by the user and cannot be recalculated */ resize(c, c->prev, 0); - if (c->fullscreen_bg) { - wlr_scene_node_destroy(&c->fullscreen_bg->node); - c->fullscreen_bg = NULL; - } } arrange(c->mon); printstatus(); @@ -2070,7 +1950,11 @@ setup(void) dpy = wl_display_create(); /* Set up signal handlers */ +#ifdef XWAYLAND sigchld(0); +#else + signal(SIGCHLD, SIG_IGN); +#endif signal(SIGINT, quitsignal); signal(SIGTERM, quitsignal); @@ -2087,13 +1971,14 @@ setup(void) /* Initialize the scene graph used to lay out windows */ scene = wlr_scene_create(); - layers[LyrBg] = &wlr_scene_tree_create(&scene->node)->node; - layers[LyrBottom] = &wlr_scene_tree_create(&scene->node)->node; - layers[LyrTile] = &wlr_scene_tree_create(&scene->node)->node; - layers[LyrFloat] = &wlr_scene_tree_create(&scene->node)->node; - layers[LyrTop] = &wlr_scene_tree_create(&scene->node)->node; - layers[LyrOverlay] = &wlr_scene_tree_create(&scene->node)->node; - layers[LyrDragIcon] = &wlr_scene_tree_create(&scene->node)->node; + layers[LyrBg] = wlr_scene_tree_create(&scene->tree); + layers[LyrBottom] = wlr_scene_tree_create(&scene->tree); + layers[LyrTile] = wlr_scene_tree_create(&scene->tree); + layers[LyrFloat] = wlr_scene_tree_create(&scene->tree); + layers[LyrFS] = wlr_scene_tree_create(&scene->tree); + layers[LyrTop] = wlr_scene_tree_create(&scene->tree); + layers[LyrOverlay] = wlr_scene_tree_create(&scene->tree); + layers[LyrDragIcon] = wlr_scene_tree_create(&scene->tree); /* Create a renderer with the default implementation */ if (!(drw = wlr_renderer_autocreate(backend))) @@ -2118,6 +2003,8 @@ setup(void) wlr_gamma_control_manager_v1_create(dpy); wlr_primary_selection_v1_device_manager_create(dpy); wlr_viewporter_create(dpy); + wlr_single_pixel_buffer_manager_v1_create(dpy); + wlr_subcompositor_create(dpy); /* Initializes the interface used to implement urgency hints */ activation = wlr_xdg_activation_v1_create(dpy); @@ -2144,6 +2031,7 @@ setup(void) wl_list_init(&fstack); idle = wlr_idle_create(dpy); + idle_notifier = wlr_idle_notifier_v1_create(dpy); idle_inhibit_mgr = wlr_idle_inhibit_v1_create(dpy); wl_signal_add(&idle_inhibit_mgr->events.new_inhibitor, &idle_inhibitor_create); @@ -2151,7 +2039,7 @@ setup(void) layer_shell = wlr_layer_shell_v1_create(dpy); wl_signal_add(&layer_shell->events.new_surface, &new_layer_shell_surface); - xdg_shell = wlr_xdg_shell_create(dpy); + xdg_shell = wlr_xdg_shell_create(dpy, 4); wl_signal_add(&xdg_shell->events.new_surface, &new_xdg_surface); input_inhibit_mgr = wlr_input_inhibit_manager_create(dpy); @@ -2235,22 +2123,6 @@ setup(void) } void -sigchld(int unused) -{ - /* We should be able to remove this function in favor of a simple - * signal(SIGCHLD, SIG_IGN); - * but the Xwayland implementation in wlroots currently prevents us from - * setting our own disposition for SIGCHLD. - */ - pid_t pid; - if (signal(SIGCHLD, sigchld) == SIG_ERR) - die("can't install SIGCHLD handler:"); - while (0 < (pid = waitpid(-1, NULL, WNOHANG))) - if (pid == child_pid) - child_pid = -1; -} - -void spawn(const Arg *arg) { if (fork() == 0) { @@ -2379,7 +2251,7 @@ unmaplayersurfacenotify(struct wl_listener *listener, void *data) LayerSurface *layersurface = wl_container_of(listener, layersurface, unmap); layersurface->mapped = 0; - wlr_scene_node_set_enabled(layersurface->scene, 0); + wlr_scene_node_set_enabled(&layersurface->scene->node, 0); if (layersurface == exclusive_focus) exclusive_focus = NULL; if (layersurface->layer_surface->output @@ -2416,7 +2288,7 @@ unmapnotify(struct wl_listener *listener, void *data) } wl_list_remove(&c->commit.link); - wlr_scene_node_destroy(c->scene); + wlr_scene_node_destroy(&c->scene->node); printstatus(); motionnotify(0); } @@ -2455,20 +2327,24 @@ updatemons(struct wl_listener *listener, void *data) && !wlr_output_layout_get(output_layout, m->wlr_output)) wlr_output_layout_add_auto(output_layout, m->wlr_output); /* Now that we update the output layout we can get its box */ - sgeom = *wlr_output_layout_get_box(output_layout, NULL); + wlr_output_layout_get_box(output_layout, NULL, &sgeom); wl_list_for_each(m, &mons, link) { if (!m->wlr_output->enabled) continue; config_head = wlr_output_configuration_head_v1_create(config, m->wlr_output); /* Get the effective monitor geometry to use for surfaces */ - m->m = m->w = *wlr_output_layout_get_box(output_layout, m->wlr_output); + wlr_output_layout_get_box(output_layout, m->wlr_output, &(m->m)); + wlr_output_layout_get_box(output_layout, m->wlr_output, &(m->w)); wlr_scene_output_set_position(m->scene_output, m->m.x, m->m.y); /* Calculate the effective monitor geometry to use for clients */ arrangelayers(m); /* Don't move clients to the left output when plugging monitors */ arrange(m); + wlr_scene_node_set_position(&m->fullscreen_bg->node, m->m.x, m->m.y); + wlr_scene_rect_set_size(m->fullscreen_bg, m->m.width, m->m.height); + config_head->state.enabled = 1; config_head->state.mode = m->wlr_output->current_mode; config_head->state.x = m->m.x; @@ -2519,7 +2395,7 @@ void virtualkeyboard(struct wl_listener *listener, void *data) { struct wlr_virtual_keyboard_v1 *keyboard = data; - createkeyboard(&keyboard->input_device); + createkeyboard(&keyboard->keyboard); } Monitor * @@ -2538,14 +2414,15 @@ xytonode(double x, double y, struct wlr_surface **psurface, Client *c = NULL; LayerSurface *l = NULL; const int *layer; - int focus_order[] = { LyrOverlay, LyrTop, LyrFloat, LyrTile, LyrBottom, LyrBg }; + int focus_order[] = { LyrOverlay, LyrTop, LyrFS, LyrFloat, LyrTile, LyrBottom, LyrBg }; for (layer = focus_order; layer < END(focus_order); layer++) { - if ((node = wlr_scene_node_at(layers[*layer], x, y, nx, ny))) { - if (node->type == WLR_SCENE_NODE_SURFACE) - surface = wlr_scene_surface_from_node(node)->surface; + if ((node = wlr_scene_node_at(&layers[*layer]->node, x, y, nx, ny))) { + if (node->type == WLR_SCENE_NODE_BUFFER) + surface = wlr_scene_surface_from_buffer( + wlr_scene_buffer_from_node(node))->surface; /* Walk the tree to find a node that knows the client */ - for (pnode = node; pnode && !c; pnode = pnode->parent) + for (pnode = node; pnode && !c; pnode = &pnode->parent->node) c = pnode->data; if (c && c->type == LayerShell) { c = NULL; @@ -2610,14 +2487,19 @@ configurex11(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, configure); struct wlr_xwayland_surface_configure_event *event = data; - wlr_xwayland_surface_configure(c->surface.xwayland, - event->x, event->y, event->width, event->height); + if (!c->mon) + return; + if (c->isfloating || c->type == X11Unmanaged) + resize(c, (struct wlr_box){.x = event->x, .y = event->y, + .width = event->width, .height = event->height}, 0); + else + arrange(c->mon); } void createnotifyx11(struct wl_listener *listener, void *data) { - struct wlr_xwayland_surface *xwayland_surface = data; + struct wlr_xwayland_surface *xsurface = data; Client *c; /* TODO: why we unset fullscreen when a xwayland client is created? */ wl_list_for_each(c, &clients, link) @@ -2625,22 +2507,20 @@ createnotifyx11(struct wl_listener *listener, void *data) setfullscreen(c, 0); /* Allocate a Client for this surface */ - c = xwayland_surface->data = ecalloc(1, sizeof(*c)); - c->surface.xwayland = xwayland_surface; - c->type = xwayland_surface->override_redirect ? X11Unmanaged : X11Managed; + c = xsurface->data = ecalloc(1, sizeof(*c)); + c->surface.xwayland = xsurface; + c->type = xsurface->override_redirect ? X11Unmanaged : X11Managed; c->bw = borderpx; /* Listen to the various events it can emit */ - LISTEN(&xwayland_surface->events.map, &c->map, mapnotify); - LISTEN(&xwayland_surface->events.unmap, &c->unmap, unmapnotify); - LISTEN(&xwayland_surface->events.request_activate, &c->activate, activatex11); - LISTEN(&xwayland_surface->events.request_configure, &c->configure, - configurex11); - LISTEN(&xwayland_surface->events.set_hints, &c->set_hints, sethints); - LISTEN(&xwayland_surface->events.set_title, &c->set_title, updatetitle); - LISTEN(&xwayland_surface->events.destroy, &c->destroy, destroynotify); - LISTEN(&xwayland_surface->events.request_fullscreen, &c->fullscreen, - fullscreennotify); + LISTEN(&xsurface->events.map, &c->map, mapnotify); + LISTEN(&xsurface->events.unmap, &c->unmap, unmapnotify); + LISTEN(&xsurface->events.request_activate, &c->activate, activatex11); + LISTEN(&xsurface->events.request_configure, &c->configure, configurex11); + LISTEN(&xsurface->events.set_hints, &c->set_hints, sethints); + LISTEN(&xsurface->events.set_title, &c->set_title, updatetitle); + LISTEN(&xsurface->events.destroy, &c->destroy, destroynotify); + LISTEN(&xsurface->events.request_fullscreen, &c->fullscreen, fullscreennotify); } Atom @@ -2661,12 +2541,31 @@ sethints(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, set_hints); if (c != selclient()) { - c->isurgent = c->surface.xwayland->hints_urgency; + c->isurgent = xcb_icccm_wm_hints_get_urgency(c->surface.xwayland->hints); printstatus(); } } void +sigchld(int unused) +{ + siginfo_t in; + /* We should be able to remove this function in favor of a simple + * signal(SIGCHLD, SIG_IGN); + * but the Xwayland implementation in wlroots currently prevents us from + * setting our own disposition for SIGCHLD. + */ + if (signal(SIGCHLD, sigchld) == SIG_ERR) + die("can't install SIGCHLD handler:"); + /* WNOWAIT leaves the child in a waitable state, in case this is the + * XWayland process + */ + while (!waitid(P_ALL, 0, &in, WEXITED|WNOHANG|WNOWAIT) && in.si_pid + && in.si_pid != xwayland->server->pid) + waitpid(in.si_pid, NULL, 0); +} + +void xwaylandready(struct wl_listener *listener, void *data) { struct wlr_xcursor *xcursor; |