diff options
-rw-r--r-- | Makefile | 5 | ||||
-rw-r--r-- | client.h | 75 | ||||
-rw-r--r-- | dwl.c | 310 |
3 files changed, 224 insertions, 166 deletions
@@ -16,7 +16,7 @@ LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` $(LIBS) all: dwl dwl: dwl.o util.o $(CC) dwl.o util.o $(LDLIBS) $(LDFLAGS) $(DWLCFLAGS) -o $@ -dwl.o: dwl.c config.mk config.h client.h xdg-shell-protocol.h wlr-layer-shell-unstable-v1-protocol.h +dwl.o: dwl.c config.mk config.h client.h cursor-shape-v1-protocol.h xdg-shell-protocol.h wlr-layer-shell-unstable-v1-protocol.h util.o: util.c util.h # wayland-scanner is a tool which generates C headers and rigging for Wayland @@ -31,6 +31,9 @@ xdg-shell-protocol.h: wlr-layer-shell-unstable-v1-protocol.h: $(WAYLAND_SCANNER) server-header \ protocols/wlr-layer-shell-unstable-v1.xml $@ +cursor-shape-v1-protocol.h: + $(WAYLAND_SCANNER) server-header \ + $(WAYLAND_PROTOCOLS)/staging/cursor-shape/cursor-shape-v1.xml $@ config.h: cp config.def.h $@ @@ -54,7 +54,7 @@ client_surface(Client *c) static inline int toplevel_from_wlr_surface(struct wlr_surface *s, Client **pc, LayerSurface **pl) { - struct wlr_xdg_surface *xdg_surface; + struct wlr_xdg_surface *xdg_surface, *tmp_xdg_surface; struct wlr_surface *root_surface; struct wlr_layer_surface_v1 *layer_surface; Client *c = NULL; @@ -69,40 +69,40 @@ toplevel_from_wlr_surface(struct wlr_surface *s, Client **pc, LayerSurface **pl) root_surface = wlr_surface_get_root_surface(s); #ifdef XWAYLAND - if (wlr_surface_is_xwayland_surface(root_surface) - && (xsurface = wlr_xwayland_surface_from_wlr_surface(root_surface))) { + if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(root_surface))) { c = xsurface->data; type = c->type; goto end; } #endif - if (wlr_surface_is_layer_surface(root_surface) - && (layer_surface = wlr_layer_surface_v1_from_wlr_surface(root_surface))) { + if ((layer_surface = wlr_layer_surface_v1_try_from_wlr_surface(root_surface))) { l = layer_surface->data; type = LayerShell; goto end; } - if (wlr_surface_is_xdg_surface(root_surface) - && (xdg_surface = wlr_xdg_surface_from_wlr_surface(root_surface))) { - while (1) { - switch (xdg_surface->role) { - case WLR_XDG_SURFACE_ROLE_POPUP: - if (!xdg_surface->popup->parent) - return -1; - else if (!wlr_surface_is_xdg_surface(xdg_surface->popup->parent)) - return toplevel_from_wlr_surface(xdg_surface->popup->parent, pc, pl); - - xdg_surface = wlr_xdg_surface_from_wlr_surface(xdg_surface->popup->parent); - break; - case WLR_XDG_SURFACE_ROLE_TOPLEVEL: - c = xdg_surface->data; - type = c->type; - goto end; - case WLR_XDG_SURFACE_ROLE_NONE: + xdg_surface = wlr_xdg_surface_try_from_wlr_surface(root_surface); + while (xdg_surface) { + tmp_xdg_surface = NULL; + switch (xdg_surface->role) { + case WLR_XDG_SURFACE_ROLE_POPUP: + if (!xdg_surface->popup || !xdg_surface->popup->parent) return -1; - } + + tmp_xdg_surface = wlr_xdg_surface_try_from_wlr_surface(xdg_surface->popup->parent); + + if (!tmp_xdg_surface) + return toplevel_from_wlr_surface(xdg_surface->popup->parent, pc, pl); + + xdg_surface = tmp_xdg_surface; + break; + case WLR_XDG_SURFACE_ROLE_TOPLEVEL: + c = xdg_surface->data; + type = c->type; + goto end; + case WLR_XDG_SURFACE_ROLE_NONE: + return -1; } } @@ -121,14 +121,12 @@ client_activate_surface(struct wlr_surface *s, int activated) struct wlr_xdg_surface *surface; #ifdef XWAYLAND struct wlr_xwayland_surface *xsurface; - if (wlr_surface_is_xwayland_surface(s) - && (xsurface = wlr_xwayland_surface_from_wlr_surface(s))) { + if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(s))) { wlr_xwayland_surface_activate(xsurface, activated); return; } #endif - if (wlr_surface_is_xdg_surface(s) - && (surface = wlr_xdg_surface_from_wlr_surface(s)) + if ((surface = wlr_xdg_surface_try_from_wlr_surface(s)) && surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) wlr_xdg_toplevel_set_activated(surface->toplevel, activated); } @@ -231,16 +229,6 @@ client_is_float_type(Client *c) } static inline int -client_is_mapped(Client *c) -{ -#ifdef XWAYLAND - if (client_is_x11(c)) - return c->surface.xwayland->mapped; -#endif - return c->surface.xdg->mapped; -} - -static inline int client_is_rendered_on_mon(Client *c, Monitor *m) { /* This is needed for when you don't want to check formal assignment, @@ -361,6 +349,19 @@ client_set_tiled(Client *c, uint32_t edges) wlr_xdg_toplevel_set_tiled(c->surface.xdg->toplevel, edges); } +static inline void +client_set_suspended(Client *c, int suspended) +{ +#ifdef XWAYLAND + if (client_is_x11(c)) { + wlr_xwayland_surface_set_withdrawn(c->surface.xwayland, suspended); + return; + } +#endif + + wlr_xdg_toplevel_set_suspended(c->surface.xdg->toplevel, suspended); +} + static inline struct wlr_surface * client_surface_at(Client *c, double cx, double cy, double *sx, double *sy) { @@ -18,15 +18,17 @@ #include <wlr/render/wlr_renderer.h> #include <wlr/types/wlr_compositor.h> #include <wlr/types/wlr_cursor.h> +#include <wlr/types/wlr_cursor_shape_v1.h> #include <wlr/types/wlr_data_control_v1.h> #include <wlr/types/wlr_data_device.h> +#include <wlr/types/wlr_drm.h> +#include <wlr/types/wlr_linux_dmabuf_v1.h> #include <wlr/types/wlr_export_dmabuf_v1.h> +#include <wlr/types/wlr_fractional_scale_v1.h> #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> #include <wlr/types/wlr_layer_shell_v1.h> #include <wlr/types/wlr_output.h> @@ -69,7 +71,7 @@ #define END(A) ((A) + LENGTH(A)) #define TAGMASK ((1u << tagcount) - 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) +#define LISTEN_STATIC(E, H) do { static struct wl_listener _l = {.notify = (H)}; wl_signal_add((E), &_l); } while (0) /* enums */ enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */ @@ -119,6 +121,8 @@ typedef struct { struct wlr_box prev; /* layout-relative, includes border */ #ifdef XWAYLAND struct wl_listener activate; + struct wl_listener associate; + struct wl_listener dissociate; struct wl_listener configure; struct wl_listener set_hints; #endif @@ -179,6 +183,7 @@ struct Monitor { struct wlr_scene_rect *fullscreen_bg; /* See createmon() for info */ struct wl_listener frame; struct wl_listener destroy; + struct wl_listener request_state; struct wl_listener destroy_lock_surface; struct wlr_session_lock_surface_v1 *lock_surface; struct wlr_box m; /* monitor area, layout-relative */ @@ -286,11 +291,14 @@ static void printstatus(void); static void quit(const Arg *arg); static void rendermon(struct wl_listener *listener, void *data); static void requeststartdrag(struct wl_listener *listener, void *data); +static void requestmonstate(struct wl_listener *listener, void *data); static void resize(Client *c, struct wlr_box geo, int interact); static void run(char *startup_cmd); static void setcursor(struct wl_listener *listener, void *data); +static void setcursorshape(struct wl_listener *listener, void *data); static void setfloating(Client *c, int floating); static void setfullscreen(Client *c, int fullscreen); +static void setgamma(struct wl_listener *listener, void *data); static void setlayout(const Arg *arg); static void setmfact(const Arg *arg); static void setmon(Client *c, Monitor *m, uint32_t newtags); @@ -321,7 +329,6 @@ static void zoom(const Arg *arg); /* variables */ static const char broken[] = "broken"; -static const char *cursor_image = "left_ptr"; static pid_t child_pid = -1; static int locked; static void *exclusive_focus; @@ -335,19 +342,20 @@ static const int layermap[] = { LyrBg, LyrBottom, LyrTop, LyrOverlay }; static struct wlr_renderer *drw; static struct wlr_allocator *alloc; static struct wlr_compositor *compositor; +static struct wlr_session *session; static struct wlr_xdg_shell *xdg_shell; static struct wlr_xdg_activation_v1 *activation; static struct wlr_xdg_decoration_manager_v1 *xdg_decoration_mgr; 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; static struct wlr_output_manager_v1 *output_mgr; +static struct wlr_gamma_control_manager_v1 *gamma_control_mgr; static struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard_mgr; +static struct wlr_cursor_shape_manager_v1 *cursor_shape_mgr; static struct wlr_cursor *cursor; static struct wlr_xcursor_manager *cursor_mgr; @@ -355,6 +363,7 @@ static struct wlr_xcursor_manager *cursor_mgr; static struct wlr_session_lock_manager_v1 *session_lock_mgr; static struct wlr_scene_rect *locked_bg; static struct wlr_session_lock_v1 *cur_lock; +static struct wl_listener lock_listener = {.notify = locksession}; static struct wlr_seat *seat; static struct wl_list keyboards; @@ -367,42 +376,15 @@ static struct wlr_box sgeom; static struct wl_list mons; static Monitor *selmon; -/* global event handlers */ -static struct wl_listener cursor_axis = {.notify = axisnotify}; -static struct wl_listener cursor_button = {.notify = buttonpress}; -static struct wl_listener cursor_frame = {.notify = cursorframe}; -static struct wl_listener cursor_motion = {.notify = motionrelative}; -static struct wl_listener cursor_motion_absolute = {.notify = motionabsolute}; -static struct wl_listener drag_icon_destroy = {.notify = destroydragicon}; -static struct wl_listener idle_inhibitor_create = {.notify = createidleinhibitor}; -static struct wl_listener idle_inhibitor_destroy = {.notify = destroyidleinhibitor}; -static struct wl_listener layout_change = {.notify = updatemons}; -static struct wl_listener new_input = {.notify = inputdevice}; -static struct wl_listener new_virtual_keyboard = {.notify = virtualkeyboard}; -static struct wl_listener new_output = {.notify = createmon}; -static struct wl_listener new_xdg_surface = {.notify = createnotify}; -static struct wl_listener new_xdg_decoration = {.notify = createdecoration}; -static struct wl_listener new_layer_shell_surface = {.notify = createlayersurface}; -static struct wl_listener output_mgr_apply = {.notify = outputmgrapply}; -static struct wl_listener output_mgr_test = {.notify = outputmgrtest}; -static struct wl_listener request_activate = {.notify = urgent}; -static struct wl_listener request_cursor = {.notify = setcursor}; -static struct wl_listener request_set_psel = {.notify = setpsel}; -static struct wl_listener request_set_sel = {.notify = setsel}; -static struct wl_listener request_start_drag = {.notify = requeststartdrag}; -static struct wl_listener start_drag = {.notify = startdrag}; -static struct wl_listener session_lock_create_lock = {.notify = locksession}; -static struct wl_listener session_lock_mgr_destroy = {.notify = destroysessionmgr}; - #ifdef XWAYLAND static void activatex11(struct wl_listener *listener, void *data); +static void associatex11(struct wl_listener *listener, void *data); static void configurex11(struct wl_listener *listener, void *data); static void createnotifyx11(struct wl_listener *listener, void *data); +static void dissociatex11(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 xwaylandready(struct wl_listener *listener, void *data); -static struct wl_listener new_xwayland_surface = {.notify = createnotifyx11}; -static struct wl_listener xwayland_ready = {.notify = xwaylandready}; static struct wlr_xwayland *xwayland; static Atom netatom[NetLast]; #endif @@ -475,9 +457,12 @@ void arrange(Monitor *m) { Client *c; - wl_list_for_each(c, &clients, link) - if (c->mon == m) + wl_list_for_each(c, &clients, link) { + if (c->mon == m) { wlr_scene_node_set_enabled(&c->scene->node, VISIBLEON(c, m)); + client_set_suspended(c, !VISIBLEON(c, m)); + } + } wlr_scene_node_set_enabled(&m->fullscreen_bg->node, (c = focustop(m)) && c->isfullscreen); @@ -559,7 +544,7 @@ 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_pointer_axis_event *event = data; - IDLE_NOTIFY_ACTIVITY; + wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); /* 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. */ @@ -577,7 +562,7 @@ buttonpress(struct wl_listener *listener, void *data) Client *c; const Button *b; - IDLE_NOTIFY_ACTIVITY; + wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); switch (event->state) { case WLR_BUTTON_PRESSED: @@ -602,13 +587,10 @@ buttonpress(struct wl_listener *listener, void *data) break; case WLR_BUTTON_RELEASED: /* If you released any buttons, we exit interactive move/resize mode. */ + /* TODO should reset to the pointer focus's current setcursor */ if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) { + wlr_cursor_set_xcursor(cursor, cursor_mgr, "left_ptr"); cursor_mode = CurNormal; - /* Clear the pointer focus, this way if the cursor is over a surface - * we will send an enter event after which the client will provide us - * a cursor surface */ - wlr_seat_pointer_clear_focus(seat); - motionnotify(0); /* Drop the window off on its new monitor */ selmon = xytomon(cursor->x, cursor->y); setmon(grabc, selmon, 0); @@ -627,7 +609,8 @@ buttonpress(struct wl_listener *listener, void *data) void chvt(const Arg *arg) { - wlr_session_change_vt(wlr_backend_get_session(backend), arg->ui); + if (session) + wlr_session_change_vt(session, arg->ui); } void @@ -645,7 +628,6 @@ checkidleinhibitor(struct wlr_surface *exclude) } } - wlr_idle_set_enabled(idle, NULL, !inhibited); wlr_idle_notifier_v1_set_inhibited(idle_notifier, inhibited); } @@ -757,9 +739,9 @@ commitlayersurfacenotify(struct wl_listener *listener, void *data) wlr_scene_node_reparent(&layersurface->popups->node, layers[LyrTop]); if (wlr_layer_surface->current.committed == 0 - && layersurface->mapped == wlr_layer_surface->mapped) + && layersurface->mapped == wlr_layer_surface->surface->mapped) return; - layersurface->mapped = wlr_layer_surface->mapped; + layersurface->mapped = wlr_layer_surface->surface->mapped; arrangelayers(layersurface->mon); } @@ -785,7 +767,7 @@ void createidleinhibitor(struct wl_listener *listener, void *data) { struct wlr_idle_inhibitor_v1 *idle_inhibitor = data; - wl_signal_add(&idle_inhibitor->events.destroy, &idle_inhibitor_destroy); + LISTEN_STATIC(&idle_inhibitor->events.destroy, destroyidleinhibitor); checkidleinhibitor(NULL); } @@ -838,21 +820,19 @@ createlayersurface(struct wl_listener *listener, void *data) return; } - layersurface = ecalloc(1, sizeof(LayerSurface)); + layersurface = wlr_layer_surface->data = ecalloc(1, sizeof(LayerSurface)); layersurface->type = LayerShell; LISTEN(&wlr_layer_surface->surface->events.commit, &layersurface->surface_commit, commitlayersurfacenotify); LISTEN(&wlr_layer_surface->events.destroy, &layersurface->destroy, destroylayersurfacenotify); - LISTEN(&wlr_layer_surface->events.map, &layersurface->map, + LISTEN(&wlr_layer_surface->surface->events.map, &layersurface->map, maplayersurfacenotify); - LISTEN(&wlr_layer_surface->events.unmap, &layersurface->unmap, + LISTEN(&wlr_layer_surface->surface->events.unmap, &layersurface->unmap, unmaplayersurfacenotify); layersurface->layer_surface = wlr_layer_surface; layersurface->mon = wlr_layer_surface->output->data; - wlr_layer_surface->data = layersurface; - layersurface->scene_layer = wlr_scene_layer_surface_v1_create(l, wlr_layer_surface); layersurface->scene = layersurface->scene_layer->tree; layersurface->popups = wlr_layer_surface->surface->data = wlr_scene_tree_create(l); @@ -913,7 +893,6 @@ createmon(struct wl_listener *listener, void *data) m->mfact = r->mfact; m->nmaster = r->nmaster; wlr_output_set_scale(wlr_output, r->scale); - wlr_xcursor_manager_load(cursor_mgr, r->scale); m->lt[0] = m->lt[1] = r->lt; wlr_output_set_transform(wlr_output, r->rr); m->m.x = r->x; @@ -931,6 +910,7 @@ createmon(struct wl_listener *listener, void *data) /* Set up event listeners */ LISTEN(&wlr_output->events.frame, &m->frame, rendermon); LISTEN(&wlr_output->events.destroy, &m->destroy, cleanupmon); + LISTEN(&wlr_output->events.request_state, &m->request_state, requestmonstate); wlr_output_enable(wlr_output, 1); if (!wlr_output_commit(wlr_output)) @@ -1004,8 +984,12 @@ createnotify(struct wl_listener *listener, void *data) c->surface.xdg = xdg_surface; c->bw = borderpx; - LISTEN(&xdg_surface->events.map, &c->map, mapnotify); - LISTEN(&xdg_surface->events.unmap, &c->unmap, unmapnotify); + wlr_xdg_toplevel_set_wm_capabilities(xdg_surface->toplevel, + WLR_XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN); + + 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->events.destroy, &c->destroy, destroynotify); LISTEN(&xdg_surface->toplevel->events.set_title, &c->set_title, updatetitle); LISTEN(&xdg_surface->toplevel->events.request_fullscreen, &c->fullscreen, @@ -1072,8 +1056,6 @@ cursorframe(struct wl_listener *listener, void *data) void destroydragicon(struct wl_listener *listener, void *data) { - struct wlr_drag_icon *icon = data; - wlr_scene_node_destroy(icon->data); /* Focus enter isn't sent during drag, so refocus the focused node. */ focusclient(focustop(selmon), 1); motionnotify(0); @@ -1150,18 +1132,23 @@ destroynotify(struct wl_listener *listener, void *data) { /* Called when the surface is destroyed and should never be shown again. */ Client *c = wl_container_of(listener, c, destroy); - wl_list_remove(&c->map.link); - wl_list_remove(&c->unmap.link); wl_list_remove(&c->destroy.link); wl_list_remove(&c->set_title.link); wl_list_remove(&c->fullscreen.link); #ifdef XWAYLAND if (c->type != XDGShell) { + wl_list_remove(&c->activate.link); + wl_list_remove(&c->associate.link); wl_list_remove(&c->configure.link); + wl_list_remove(&c->dissociate.link); wl_list_remove(&c->set_hints.link); - wl_list_remove(&c->activate.link); - } + } else #endif + { + wl_list_remove(&c->commit.link); + wl_list_remove(&c->map.link); + wl_list_remove(&c->unmap.link); + } free(c); } @@ -1175,8 +1162,8 @@ destroysessionlock(struct wl_listener *listener, void *data) void destroysessionmgr(struct wl_listener *listener, void *data) { - wl_list_remove(&session_lock_create_lock.link); - wl_list_remove(&session_lock_mgr_destroy.link); + wl_list_remove(&lock_listener.link); + wl_list_remove(&listener->link); } Monitor * @@ -1427,12 +1414,11 @@ keypress(struct wl_listener *listener, void *data) int handled = 0; uint32_t mods = wlr_keyboard_get_modifiers(kb->wlr_keyboard); - IDLE_NOTIFY_ACTIVITY; + wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); /* On _press_ if there is no active screen locker, * attempt to process a compositor keybinding. */ - if (!locked && !input_inhibit_mgr->active_inhibitor - && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) + if (!locked && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) for (i = 0; i < nsyms; i++) handled = keybinding(mods, syms[i]) || handled; @@ -1509,13 +1495,12 @@ locksession(struct wl_listener *listener, void *data) wlr_session_lock_v1_destroy(session_lock); return; } - lock = ecalloc(1, sizeof(*lock)); + lock = session_lock->data = ecalloc(1, sizeof(*lock)); focusclient(NULL, 0); lock->scene = wlr_scene_tree_create(layers[LyrBlock]); cur_lock = lock->lock = session_lock; locked = 1; - session_lock->data = lock; LISTEN(&session_lock->events.new_surface, &lock->new_surface, createlocksurface); LISTEN(&session_lock->events.destroy, &lock->destroy, destroysessionlock); @@ -1540,17 +1525,11 @@ 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]); + c->scene = client_surface(c)->data = wlr_scene_tree_create(layers[LyrTile]); wlr_scene_node_set_enabled(&c->scene->node, c->type != XDGShell); 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. */ - LISTEN(&client_surface(c)->events.commit, &c->commit, commitnotify); - } c->scene->node.data = c->scene_surface->node.data = c; /* Handle unmanaged clients first so we can return prior create borders */ @@ -1658,7 +1637,7 @@ motionnotify(uint32_t time) /* time is 0 in internal calls meant to restore pointer focus. */ if (time) { - IDLE_NOTIFY_ACTIVITY; + wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); /* Update selmon (even while dragging a window) */ if (sloppyfocus) @@ -1696,8 +1675,8 @@ motionnotify(uint32_t time) /* If there's no client surface under the cursor, set the cursor image to a * default. This is what makes the cursor image appear when you move it * off of a client or over its border. */ - if (!surface && !seat->drag && (!cursor_image || strcmp(cursor_image, "left_ptr"))) - wlr_xcursor_manager_set_cursor_image(cursor_mgr, (cursor_image = "left_ptr"), cursor); + if (!surface && !seat->drag) + wlr_cursor_set_xcursor(cursor, cursor_mgr, "left_ptr"); pointerfocus(c, surface, sx, sy, time); } @@ -1732,7 +1711,7 @@ moveresize(const Arg *arg) case CurMove: grabcx = cursor->x - grabc->geom.x; grabcy = cursor->y - grabc->geom.y; - wlr_xcursor_manager_set_cursor_image(cursor_mgr, (cursor_image = "fleur"), cursor); + wlr_cursor_set_xcursor(cursor, cursor_mgr, "fleur"); break; case CurResize: /* Doesn't work for X11 output - the next absolute motion event @@ -1740,8 +1719,7 @@ moveresize(const Arg *arg) wlr_cursor_warp_closest(cursor, NULL, grabc->geom.x + grabc->geom.width, grabc->geom.y + grabc->geom.height); - wlr_xcursor_manager_set_cursor_image(cursor_mgr, - (cursor_image = "bottom_right_corner"), cursor); + wlr_cursor_set_xcursor(cursor, cursor_mgr, "bottom_right_corner"); break; } } @@ -1783,7 +1761,7 @@ outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test) /* Don't move monitors if position wouldn't change, this to avoid * wlroots marking the output as manually configured */ if (m->m.x != config_head->state.x || m->m.y != config_head->state.y) - wlr_output_layout_move(output_layout, wlr_output, + wlr_output_layout_add(output_layout, wlr_output, 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); @@ -1842,6 +1820,7 @@ pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, * wlroots makes this a no-op if surface is already focused */ wlr_seat_pointer_notify_enter(seat, surface, sx, sy); wlr_seat_pointer_notify_motion(seat, time, sx, sy); + } void @@ -1905,7 +1884,7 @@ rendermon(struct wl_listener *listener, void *data) wl_list_for_each(c, &clients, link) if (c->resize && !c->isfloating && client_is_rendered_on_mon(c, m) && !client_is_stopped(c)) goto skip; - wlr_scene_output_commit(m->scene_output); + wlr_scene_output_commit(m->scene_output, NULL); skip: /* Let clients know a frame has been rendered */ @@ -1926,6 +1905,14 @@ requeststartdrag(struct wl_listener *listener, void *data) } void +requestmonstate(struct wl_listener *listener, void *data) +{ + struct wlr_output_event_request_state *event = data; + wlr_output_commit_state(event->output, event->state); + updatemons(NULL, NULL); +} + +void resize(Client *c, struct wlr_box geo, int interact) { struct wlr_box *bbox = interact ? &sgeom : &c->mon->w; @@ -1992,7 +1979,7 @@ run(char *startup_cmd) * initialized, as the image/coordinates are not transformed for the * monitor when displayed here */ wlr_cursor_warp_closest(cursor, NULL, cursor->x, cursor->y); - wlr_xcursor_manager_set_cursor_image(cursor_mgr, cursor_image, cursor); + wlr_cursor_set_xcursor(cursor, cursor_mgr, "left_ptr"); /* Run the Wayland event loop. This does not return until you exit the * compositor. Starting the backend rigged up all of the necessary event @@ -2011,7 +1998,6 @@ setcursor(struct wl_listener *listener, void *data) * event, which will result in the client requesting set the cursor surface */ if (cursor_mode != CurNormal && cursor_mode != CurPressed) return; - cursor_image = NULL; /* This can be sent by any client, so we check to make sure this one is * actually has pointer focus first. If so, we can tell the cursor to * use the provided surface as the cursor image. It will set the @@ -2023,6 +2009,20 @@ setcursor(struct wl_listener *listener, void *data) } void +setcursorshape(struct wl_listener *listener, void *data) +{ + struct wlr_cursor_shape_manager_v1_request_set_shape_event *event = data; + if (cursor_mode != CurNormal && cursor_mode != CurPressed) + return; + /* This can be sent by any client, so we check to make sure this one is + * actually has pointer focus first. If so, we can tell the cursor to + * use the provided cursor shape. */ + if (event->seat_client == seat->pointer_state.focused_client) + wlr_cursor_set_xcursor(cursor, cursor_mgr, + wlr_cursor_shape_v1_name(event->shape)); +} + +void setfloating(Client *c, int floating) { c->isfloating = floating; @@ -2057,6 +2057,27 @@ setfullscreen(Client *c, int fullscreen) } void +setgamma(struct wl_listener *listener, void *data) +{ + struct wlr_gamma_control_manager_v1_set_gamma_event *event = data; + struct wlr_output_state state; + wlr_output_state_init(&state); + if (!wlr_gamma_control_v1_apply(event->control, &state)) { + wlr_output_state_finish(&state); + return; + } + + if (!wlr_output_test_state(event->output, &state)) { + wlr_gamma_control_v1_send_failed_and_destroy(event->control); + wlr_output_state_finish(&state); + return; + } + + wlr_output_commit_state(event->output, &state); + wlr_output_schedule_frame(event->output); +} + +void setlayout(const Arg *arg) { if (!selmon) @@ -2152,7 +2173,7 @@ setup(void) * backend uses the renderer, for example, to fall back to software cursors * if the backend does not support hardware cursors (some older GPUs * don't). */ - if (!(backend = wlr_backend_autocreate(dpy))) + if (!(backend = wlr_backend_autocreate(dpy, &session))) die("couldn't create backend"); /* Initialize the scene graph used to lay out windows */ @@ -2165,7 +2186,19 @@ setup(void) /* Create a renderer with the default implementation */ if (!(drw = wlr_renderer_autocreate(backend))) die("couldn't create renderer"); - wlr_renderer_init_wl_display(drw, dpy); + + /* Create shm, drm and linux_dmabuf interfaces by ourselves. + * The simplest way is call: + * wlr_renderer_init_wl_display(drw); + * but we need to create manually the linux_dmabuf interface to integrate it + * with wlr_scene. */ + wlr_renderer_init_wl_shm(drw, dpy); + + if (wlr_renderer_get_dmabuf_texture_formats(drw)) { + wlr_drm_create(dpy, drw); + wlr_scene_set_linux_dmabuf_v1(scene, + wlr_linux_dmabuf_v1_create_with_renderer(dpy, 4, drw)); + } /* Create a default allocator */ if (!(alloc = wlr_allocator_autocreate(backend, drw))) @@ -2177,31 +2210,34 @@ setup(void) * to dig your fingers in and play with their behavior if you want. Note that * the clients cannot set the selection directly without compositor approval, * see the setsel() function. */ - compositor = wlr_compositor_create(dpy, drw); + compositor = wlr_compositor_create(dpy, 6, drw); wlr_export_dmabuf_manager_v1_create(dpy); wlr_screencopy_manager_v1_create(dpy); wlr_data_control_manager_v1_create(dpy); wlr_data_device_manager_create(dpy); - 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_fractional_scale_manager_v1_create(dpy, 1); wlr_subcompositor_create(dpy); /* Initializes the interface used to implement urgency hints */ activation = wlr_xdg_activation_v1_create(dpy); - wl_signal_add(&activation->events.request_activate, &request_activate); + LISTEN_STATIC(&activation->events.request_activate, urgent); + + gamma_control_mgr = wlr_gamma_control_manager_v1_create(dpy); + LISTEN_STATIC(&gamma_control_mgr->events.set_gamma, setgamma); /* 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(); - wl_signal_add(&output_layout->events.change, &layout_change); + LISTEN_STATIC(&output_layout->events.change, updatemons); wlr_xdg_output_manager_v1_create(dpy, output_layout); /* Configure a listener to be notified when new outputs are available on the * backend. */ wl_list_init(&mons); - wl_signal_add(&backend->events.new_output, &new_output); + LISTEN_STATIC(&backend->events.new_output, createmon); /* Set up our client lists and the xdg-shell. The xdg-shell is a * Wayland protocol which is used for application windows. For more @@ -2212,22 +2248,20 @@ setup(void) wl_list_init(&clients); 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); + LISTEN_STATIC(&idle_inhibit_mgr->events.new_inhibitor, createidleinhibitor); - layer_shell = wlr_layer_shell_v1_create(dpy); - wl_signal_add(&layer_shell->events.new_surface, &new_layer_shell_surface); + layer_shell = wlr_layer_shell_v1_create(dpy, 3); + LISTEN_STATIC(&layer_shell->events.new_surface, createlayersurface); - xdg_shell = wlr_xdg_shell_create(dpy, 4); - wl_signal_add(&xdg_shell->events.new_surface, &new_xdg_surface); + xdg_shell = wlr_xdg_shell_create(dpy, 6); + LISTEN_STATIC(&xdg_shell->events.new_surface, createnotify); - input_inhibit_mgr = wlr_input_inhibit_manager_create(dpy); session_lock_mgr = wlr_session_lock_manager_v1_create(dpy); - wl_signal_add(&session_lock_mgr->events.new_lock, &session_lock_create_lock); - wl_signal_add(&session_lock_mgr->events.destroy, &session_lock_mgr_destroy); + wl_signal_add(&session_lock_mgr->events.new_lock, &lock_listener); + LISTEN_STATIC(&session_lock_mgr->events.destroy, destroysessionmgr); locked_bg = wlr_scene_rect_create(layers[LyrBlock], sgeom.width, sgeom.height, (float [4]){0.1, 0.1, 0.1, 1.0}); wlr_scene_node_set_enabled(&locked_bg->node, 0); @@ -2237,7 +2271,7 @@ setup(void) wlr_server_decoration_manager_create(dpy), WLR_SERVER_DECORATION_MANAGER_MODE_SERVER); xdg_decoration_mgr = wlr_xdg_decoration_manager_v1_create(dpy); - wl_signal_add(&xdg_decoration_mgr->events.new_toplevel_decoration, &new_xdg_decoration); + LISTEN_STATIC(&xdg_decoration_mgr->events.new_toplevel_decoration, createdecoration); /* * Creates a cursor, which is a wlroots utility for tracking the cursor @@ -2265,11 +2299,14 @@ setup(void) * * And more comments are sprinkled throughout the notify functions above. */ - wl_signal_add(&cursor->events.motion, &cursor_motion); - wl_signal_add(&cursor->events.motion_absolute, &cursor_motion_absolute); - wl_signal_add(&cursor->events.button, &cursor_button); - wl_signal_add(&cursor->events.axis, &cursor_axis); - wl_signal_add(&cursor->events.frame, &cursor_frame); + LISTEN_STATIC(&cursor->events.motion, motionrelative); + LISTEN_STATIC(&cursor->events.motion_absolute, motionabsolute); + LISTEN_STATIC(&cursor->events.button, buttonpress); + LISTEN_STATIC(&cursor->events.axis, axisnotify); + LISTEN_STATIC(&cursor->events.frame, cursorframe); + + cursor_shape_mgr = wlr_cursor_shape_manager_v1_create(dpy, 1); + LISTEN_STATIC(&cursor_shape_mgr->events.request_set_shape, setcursorshape); /* * Configures a seat, which is a single "seat" at which a user sits and @@ -2278,20 +2315,19 @@ setup(void) * let us know when new input devices are available on the backend. */ wl_list_init(&keyboards); - wl_signal_add(&backend->events.new_input, &new_input); + LISTEN_STATIC(&backend->events.new_input, inputdevice); virtual_keyboard_mgr = wlr_virtual_keyboard_manager_v1_create(dpy); - wl_signal_add(&virtual_keyboard_mgr->events.new_virtual_keyboard, - &new_virtual_keyboard); + LISTEN_STATIC(&virtual_keyboard_mgr->events.new_virtual_keyboard, virtualkeyboard); seat = wlr_seat_create(dpy, "seat0"); - wl_signal_add(&seat->events.request_set_cursor, &request_cursor); - wl_signal_add(&seat->events.request_set_selection, &request_set_sel); - wl_signal_add(&seat->events.request_set_primary_selection, &request_set_psel); - wl_signal_add(&seat->events.request_start_drag, &request_start_drag); - wl_signal_add(&seat->events.start_drag, &start_drag); + LISTEN_STATIC(&seat->events.request_set_cursor, setcursor); + LISTEN_STATIC(&seat->events.request_set_selection, setsel); + LISTEN_STATIC(&seat->events.request_set_primary_selection, setpsel); + LISTEN_STATIC(&seat->events.request_start_drag, requeststartdrag); + LISTEN_STATIC(&seat->events.start_drag, startdrag); output_mgr = wlr_output_manager_v1_create(dpy); - wl_signal_add(&output_mgr->events.apply, &output_mgr_apply); - wl_signal_add(&output_mgr->events.test, &output_mgr_test); + LISTEN_STATIC(&output_mgr->events.apply, outputmgrapply); + LISTEN_STATIC(&output_mgr->events.test, outputmgrtest); wlr_scene_set_presentation(scene, wlr_presentation_create(dpy, backend)); @@ -2302,8 +2338,8 @@ setup(void) */ xwayland = wlr_xwayland_create(dpy, compositor, 1); if (xwayland) { - wl_signal_add(&xwayland->events.ready, &xwayland_ready); - wl_signal_add(&xwayland->events.new_surface, &new_xwayland_surface); + LISTEN_STATIC(&xwayland->events.ready, xwaylandready); + LISTEN_STATIC(&xwayland->events.new_surface, createnotifyx11); setenv("DISPLAY", xwayland->display_name, 1); } else { @@ -2330,8 +2366,8 @@ startdrag(struct wl_listener *listener, void *data) if (!drag->icon) return; - drag->icon->data = &wlr_scene_subsurface_tree_create(drag_icon, drag->icon->surface)->node; - wl_signal_add(&drag->icon->events.destroy, &drag_icon_destroy); + drag->icon->data = &wlr_scene_drag_icon_create(drag_icon, drag->icon)->node; + LISTEN_STATIC(&drag->icon->events.destroy, destroydragicon); } void @@ -2482,7 +2518,6 @@ unmapnotify(struct wl_listener *listener, void *data) wl_list_remove(&c->flink); } - wl_list_remove(&c->commit.link); wlr_scene_node_destroy(&c->scene->node); printstatus(); motionnotify(0); @@ -2562,7 +2597,7 @@ updatemons(struct wl_listener *listener, void *data) if (selmon && selmon->wlr_output->enabled) { wl_list_for_each(c, &clients, link) - if (!c->mon && client_is_mapped(c)) + if (!c->mon && client_surface(c)->mapped) setmon(c, selmon, c->tags); focusclient(focustop(selmon), 1); if (selmon->lock_surface) { @@ -2638,7 +2673,7 @@ xytonode(double x, double y, struct wlr_surface **psurface, continue; if (node->type == WLR_SCENE_NODE_BUFFER) - surface = wlr_scene_surface_from_buffer( + surface = wlr_scene_surface_try_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->node) @@ -2698,6 +2733,16 @@ activatex11(struct wl_listener *listener, void *data) } void +associatex11(struct wl_listener *listener, void *data) +{ + Client *c = wl_container_of(listener, c, associate); + + LISTEN(&client_surface(c)->events.commit, &c->commit, commitnotify); + LISTEN(&client_surface(c)->events.map, &c->map, mapnotify); + LISTEN(&client_surface(c)->events.unmap, &c->unmap, unmapnotify); +} + +void configurex11(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, configure); @@ -2724,8 +2769,8 @@ createnotifyx11(struct wl_listener *listener, void *data) c->bw = borderpx; /* Listen to the various events it can emit */ - LISTEN(&xsurface->events.map, &c->map, mapnotify); - LISTEN(&xsurface->events.unmap, &c->unmap, unmapnotify); + LISTEN(&xsurface->events.associate, &c->associate, associatex11); + LISTEN(&xsurface->events.dissociate, &c->dissociate, dissociatex11); 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); @@ -2734,6 +2779,15 @@ createnotifyx11(struct wl_listener *listener, void *data) LISTEN(&xsurface->events.request_fullscreen, &c->fullscreen, fullscreennotify); } +void +dissociatex11(struct wl_listener *listener, void *data) +{ + Client *c = wl_container_of(listener, c, dissociate); + wl_list_remove(&c->commit.link); + wl_list_remove(&c->map.link); + wl_list_remove(&c->unmap.link); +} + Atom getatom(xcb_connection_t *xc, const char *name) { |