diff options
Diffstat (limited to 'dwl.c')
-rw-r--r-- | dwl.c | 160 |
1 files changed, 94 insertions, 66 deletions
@@ -15,6 +15,7 @@ #include <wlr/backend/libinput.h> #include <wlr/render/allocator.h> #include <wlr/render/wlr_renderer.h> +#include <wlr/types/wlr_alpha_modifier_v1.h> #include <wlr/types/wlr_compositor.h> #include <wlr/types/wlr_cursor.h> #include <wlr/types/wlr_cursor_shape_v1.h> @@ -256,6 +257,7 @@ static void cleanupmon(struct wl_listener *listener, void *data); 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 commitpopup(struct wl_listener *listener, void *data); static void createdecoration(struct wl_listener *listener, void *data); static void createidleinhibitor(struct wl_listener *listener, void *data); static void createkeyboard(struct wlr_keyboard *keyboard); @@ -266,6 +268,7 @@ static void createmon(struct wl_listener *listener, void *data); static void createnotify(struct wl_listener *listener, void *data); static void createpointer(struct wlr_pointer *pointer); static void createpointerconstraint(struct wl_listener *listener, void *data); +static void createpopup(struct wl_listener *listener, void *data); static void cursorconstrain(struct wlr_pointer_constraint_v1 *constraint); static void cursorframe(struct wl_listener *listener, void *data); static void cursorwarptohint(void); @@ -357,6 +360,7 @@ static pid_t child_pid = -1; static int locked; static void *exclusive_focus; static struct wl_display *dpy; +static struct wl_event_loop *event_loop; static struct wlr_backend *backend; static struct wlr_scene *scene; static struct wlr_scene_tree *layers[NUM_LAYERS]; @@ -586,7 +590,7 @@ axisnotify(struct wl_listener *listener, void *data) /* Notify the client with pointer focus of the axis event. */ wlr_seat_pointer_notify_axis(seat, event->time_msec, event->orientation, event->delta, - event->delta_discrete, event->source); + event->delta_discrete, event->source, event->relative_direction); } void @@ -601,7 +605,7 @@ buttonpress(struct wl_listener *listener, void *data) wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); switch (event->state) { - case WLR_BUTTON_PRESSED: + case WL_POINTER_BUTTON_STATE_PRESSED: cursor_mode = CurPressed; held_grab = seat->pointer_state.focused_surface; if (locked) @@ -622,7 +626,7 @@ buttonpress(struct wl_listener *listener, void *data) } } break; - case WLR_BUTTON_RELEASED: + case WL_POINTER_BUTTON_STATE_RELEASED: held_grab = NULL; /* If you released any buttons, we exit interactive move/resize mode. */ /* TODO should reset to the pointer focus's current setcursor */ @@ -681,10 +685,13 @@ cleanup(void) waitpid(child_pid, NULL, 0); } wlr_xcursor_manager_destroy(cursor_mgr); - wlr_output_layout_destroy(output_layout); destroykeyboardgroup(&kb_group->destroy, NULL); + /* If it's not destroyed manually it will cause a use-after-free of wlr_seat. + * Destroy it until it's fixed in the wlroots side */ + wlr_backend_destroy(backend); + wl_display_destroy(dpy); /* Destroy after the wayland display (when the monitors are already destroyed) to avoid destroying them with an invalid scene output. */ @@ -749,6 +756,17 @@ commitlayersurfacenotify(struct wl_listener *listener, void *data) LayerSurface *l = wl_container_of(listener, l, surface_commit); struct wlr_layer_surface_v1 *layer_surface = l->layer_surface; struct wlr_scene_tree *scene_layer = layers[layermap[layer_surface->current.layer]]; + struct wlr_layer_surface_v1_state old_state; + + if (l->layer_surface->initial_commit) { + /* Temporarily set the layer's current state to pending + * so that we can easily arrange it */ + old_state = l->layer_surface->current; + l->layer_surface->current = l->layer_surface->pending; + arrangelayers(l->mon); + l->layer_surface->current = old_state; + return; + } if (layer_surface->current.committed == 0 && l->mapped == layer_surface->surface->mapped) return; @@ -770,6 +788,14 @@ commitnotify(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, commit); + if (c->surface.xdg->initial_commit) { + wlr_xdg_toplevel_set_wm_capabilities(c->surface.xdg->toplevel, WLR_XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN); + wlr_xdg_toplevel_set_size(c->surface.xdg->toplevel, 0, 0); + if (c->decoration) + requestdecorationmode(&c->set_decoration_mode, c->decoration); + return; + } + if (client_surface(c)->mapped && c->mon) resize(c, c->geom, (c->isfloating && !c->isfullscreen)); @@ -779,6 +805,33 @@ commitnotify(struct wl_listener *listener, void *data) } void +commitpopup(struct wl_listener *listener, void *data) +{ + struct wlr_surface *surface = data; + struct wlr_xdg_popup *popup = wlr_xdg_popup_try_from_wlr_surface(surface); + LayerSurface *l = NULL; + Client *c = NULL; + struct wlr_box box; + int type = -1; + + if (!popup->base->initial_commit) + return; + + type = toplevel_from_wlr_surface(popup->base->surface, &c, &l); + if (!popup->parent || type < 0) + return; + popup->base->surface->data = wlr_scene_xdg_surface_create( + popup->parent->data, popup->base); + if ((l && !l->mon) || (c && !c->mon)) + return; + box = type == LayerShell ? l->mon->m : c->mon->w; + box.x -= (type == LayerShell ? l->geom.x : c->geom.x); + box.y -= (type == LayerShell ? l->geom.y : c->geom.y); + wlr_xdg_popup_unconstrain_from_box(popup, &box); + wl_list_remove(&listener->link); +} + +void createdecoration(struct wl_listener *listener, void *data) { struct wlr_xdg_toplevel_decoration_v1 *deco = data; @@ -836,8 +889,7 @@ createkeyboardgroup(void) LISTEN(&group->wlr_group->keyboard.events.key, &group->key, keypress); LISTEN(&group->wlr_group->keyboard.events.modifiers, &group->modifiers, keypressmod); - group->key_repeat_source = wl_event_loop_add_timer( - wl_display_get_event_loop(dpy), keyrepeat, group); + group->key_repeat_source = wl_event_loop_add_timer(event_loop, keyrepeat, group); /* A seat can only have one keyboard, but this is a limitation of the * Wayland protocol - not wlroots. We assign all connected keyboards to the @@ -855,7 +907,6 @@ createlayersurface(struct wl_listener *listener, void *data) LayerSurface *l; struct wlr_surface *surface = layer_surface->surface; struct wlr_scene_tree *scene_layer = layers[layermap[layer_surface->pending.layer]]; - struct wlr_layer_surface_v1_state old_state; if (!layer_surface->output && !(layer_surface->output = selmon ? selmon->wlr_output : NULL)) { @@ -880,15 +931,6 @@ createlayersurface(struct wl_listener *listener, void *data) wl_list_insert(&l->mon->layers[layer_surface->pending.layer],&l->link); wlr_surface_send_enter(surface, layer_surface->output); - - /* Temporarily set the layer's current state to pending - * so that we can easily arrange it - */ - old_state = layer_surface->current; - layer_surface->current = layer_surface->pending; - l->mapped = 1; - arrangelayers(l->mon); - layer_surface->current = old_state; } void @@ -994,49 +1036,22 @@ createmon(struct wl_listener *listener, void *data) void createnotify(struct wl_listener *listener, void *data) { - /* This event is raised when wlr_xdg_shell receives a new xdg surface from a - * client, either a toplevel (application window) or popup, - * or when wlr_layer_shell receives a new popup from a layer. - * If you want to do something tricky with popups you should check if - * its parent is wlr_xdg_shell or wlr_layer_shell */ - struct wlr_xdg_surface *xdg_surface = data; + /* This event is raised when a client creates a new toplevel (application window). */ + struct wlr_xdg_toplevel *toplevel = data; Client *c = NULL; - LayerSurface *l = NULL; - - if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { - struct wlr_xdg_popup *popup = xdg_surface->popup; - struct wlr_box box; - if (toplevel_from_wlr_surface(popup->base->surface, &c, &l) < 0) - return; - popup->base->surface->data = wlr_scene_xdg_surface_create( - popup->parent->data, popup->base); - if ((l && !l->mon) || (c && !c->mon)) - return; - box = l ? l->mon->m : c->mon->w; - box.x -= (l ? l->geom.x : c->geom.x); - box.y -= (l ? l->geom.y : c->geom.y); - wlr_xdg_popup_unconstrain_from_box(popup, &box); - return; - } else if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_NONE) - return; /* Allocate a Client for this surface */ - c = xdg_surface->data = ecalloc(1, sizeof(*c)); - c->surface.xdg = xdg_surface; + c = toplevel->base->data = ecalloc(1, sizeof(*c)); + c->surface.xdg = toplevel->base; c->bw = borderpx; - wlr_xdg_toplevel_set_wm_capabilities(xdg_surface->toplevel, - WLR_XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN); - - LISTEN(&xdg_surface->events.destroy, &c->destroy, destroynotify); - LISTEN(&xdg_surface->surface->events.commit, &c->commit, commitnotify); - LISTEN(&xdg_surface->surface->events.map, &c->map, mapnotify); - LISTEN(&xdg_surface->surface->events.unmap, &c->unmap, unmapnotify); - LISTEN(&xdg_surface->toplevel->events.request_fullscreen, &c->fullscreen, - fullscreennotify); - LISTEN(&xdg_surface->toplevel->events.request_maximize, &c->maximize, - maximizenotify); - LISTEN(&xdg_surface->toplevel->events.set_title, &c->set_title, updatetitle); + LISTEN(&toplevel->base->surface->events.commit, &c->commit, commitnotify); + LISTEN(&toplevel->base->surface->events.map, &c->map, mapnotify); + LISTEN(&toplevel->base->surface->events.unmap, &c->unmap, unmapnotify); + LISTEN(&toplevel->events.destroy, &c->destroy, destroynotify); + LISTEN(&toplevel->events.request_fullscreen, &c->fullscreen, fullscreennotify); + LISTEN(&toplevel->events.request_maximize, &c->maximize, maximizenotify); + LISTEN(&toplevel->events.set_title, &c->set_title, updatetitle); } void @@ -1093,6 +1108,15 @@ createpointerconstraint(struct wl_listener *listener, void *data) } void +createpopup(struct wl_listener *listener, void *data) +{ + /* This event is raised when a client (either xdg-shell or layer-shell) + * creates a new popup. */ + struct wlr_xdg_popup *popup = data; + LISTEN_STATIC(&popup->base->surface->events.commit, commitpopup); +} + +void cursorconstrain(struct wlr_pointer_constraint_v1 *constraint) { if (active_constraint == constraint) @@ -1124,8 +1148,7 @@ cursorwarptohint(void) double sy = active_constraint->current.cursor_hint.y; toplevel_from_wlr_surface(active_constraint->surface, &c, NULL); - /* TODO: wlroots 0.18: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4478 */ - if (c && (active_constraint->current.committed & WLR_POINTER_CONSTRAINT_V1_STATE_CURSOR_HINT )) { + if (c && active_constraint->current.cursor_hint.enabled) { wlr_cursor_warp(cursor, NULL, sx + c->geom.x + c->bw, sy + c->geom.y + c->bw); wlr_seat_pointer_warp(active_constraint->seat, sx, sy); } @@ -1135,6 +1158,7 @@ void destroydecoration(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, destroy_decoration); + c->decoration = NULL; wl_list_remove(&c->destroy_decoration.link); wl_list_remove(&c->set_decoration_mode.link); @@ -1703,8 +1727,9 @@ maximizenotify(struct wl_listener *listener, void *data) * protocol version * wlr_xdg_surface_schedule_configure() is used to send an empty reply. */ Client *c = wl_container_of(listener, c, maximize); - if (wl_resource_get_version(c->surface.xdg->toplevel->resource) - < XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION) + if (c->surface.xdg->initialized + && wl_resource_get_version(c->surface.xdg->toplevel->resource) + < XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION) wlr_xdg_surface_schedule_configure(c->surface.xdg); } @@ -2070,8 +2095,9 @@ void requestdecorationmode(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, set_decoration_mode); - wlr_xdg_toplevel_decoration_v1_set_mode(c->decoration, - WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); + if (c->surface.xdg->initialized) + wlr_xdg_toplevel_decoration_v1_set_mode(c->decoration, + WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); } void @@ -2345,12 +2371,13 @@ setup(void) /* The Wayland display is managed by libwayland. It handles accepting * clients from the Unix socket, manging Wayland globals, and so on. */ dpy = wl_display_create(); + event_loop = wl_display_get_event_loop(dpy); /* The backend is a wlroots feature which abstracts the underlying input and * output hardware. The autocreate option will choose the most suitable * backend based on the current environment, such as opening an X11 window * if an X11 server is running. */ - if (!(backend = wlr_backend_autocreate(dpy, &session))) + if (!(backend = wlr_backend_autocreate(event_loop, &session))) die("couldn't create backend"); /* Initialize the scene graph used to lay out windows */ @@ -2375,7 +2402,7 @@ setup(void) * with wlr_scene. */ wlr_renderer_init_wl_shm(drw, dpy); - if (wlr_renderer_get_dmabuf_texture_formats(drw)) { + if (wlr_renderer_get_texture_formats(drw, WLR_BUFFER_CAP_DMABUF)) { wlr_drm_create(dpy, drw); wlr_scene_set_linux_dmabuf_v1(scene, wlr_linux_dmabuf_v1_create_with_renderer(dpy, 4, drw)); @@ -2404,6 +2431,8 @@ setup(void) wlr_viewporter_create(dpy); wlr_single_pixel_buffer_manager_v1_create(dpy); wlr_fractional_scale_manager_v1_create(dpy, 1); + wlr_presentation_create(dpy, backend); + wlr_alpha_modifier_v1_create(dpy); /* Initializes the interface used to implement urgency hints */ activation = wlr_xdg_activation_v1_create(dpy); @@ -2414,7 +2443,7 @@ setup(void) /* Creates an output layout, which a wlroots utility for working with an * arrangement of screens in a physical layout. */ - output_layout = wlr_output_layout_create(); + output_layout = wlr_output_layout_create(dpy); LISTEN_STATIC(&output_layout->events.change, updatemons); wlr_xdg_output_manager_v1_create(dpy, output_layout); @@ -2433,7 +2462,8 @@ setup(void) wl_list_init(&fstack); xdg_shell = wlr_xdg_shell_create(dpy, 6); - LISTEN_STATIC(&xdg_shell->events.new_surface, createnotify); + LISTEN_STATIC(&xdg_shell->events.new_toplevel, createnotify); + LISTEN_STATIC(&xdg_shell->events.new_popup, createpopup); layer_shell = wlr_layer_shell_v1_create(dpy, 3); LISTEN_STATIC(&layer_shell->events.new_surface, createlayersurface); @@ -2521,8 +2551,6 @@ setup(void) LISTEN_STATIC(&output_mgr->events.apply, outputmgrapply); LISTEN_STATIC(&output_mgr->events.test, outputmgrtest); - wlr_scene_set_presentation(scene, wlr_presentation_create(dpy, backend)); - /* Make sure XWayland clients don't connect to the parent X server, * e.g when running in the x11 backend or the wayland backend and the * compositor has Xwayland support */ |