diff options
| author | Leonardo Hernández Hernández <leohdz172@proton.me> | 2023-11-25 00:04:19 -0600 | 
|---|---|---|
| committer | Leonardo Hernández Hernández <leohdz172@proton.me> | 2023-11-25 00:04:19 -0600 | 
| commit | 7ac76219dfe1ca0614ee92faacf310435b00de70 (patch) | |
| tree | 063f570e97bcb995502b747bcc3ab5d55f73b97a | |
| parent | b4da97446aafba04ac10062b16f343ac95a81e90 (diff) | |
| parent | 6838f909bd58e6f9775dcc463566c2c3ad3d4279 (diff) | |
Merge branch 'wlroots-next'
| -rw-r--r-- | Makefile | 7 | ||||
| -rw-r--r-- | client.h | 176 | ||||
| -rw-r--r-- | dwl.c | 425 | 
3 files changed, 338 insertions, 270 deletions
| @@ -5,7 +5,7 @@ include config.mk  # flags for compiling  DWLCPPFLAGS = -I. -DWLR_USE_UNSTABLE -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" $(XWAYLAND) -DWLDEVCFLAGS = -pedantic -Wall -Wextra -Wdeclaration-after-statement -Wno-unused-parameter -Wno-sign-compare -Wshadow -Wunused-macros\ +DWLDEVCFLAGS = -g -pedantic -Wall -Wextra -Wdeclaration-after-statement -Wno-unused-parameter -Wno-sign-compare -Wshadow -Wunused-macros\  	-Werror=strict-prototypes -Werror=implicit -Werror=return-type -Werror=incompatible-pointer-types  # CFLAGS / LDFLAGS @@ -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 $@ @@ -11,34 +11,8 @@ client_is_x11(Client *c)  {  #ifdef XWAYLAND  	return c->type == X11Managed || c->type == X11Unmanaged; -#else -	return 0;  #endif -} - -static inline void -client_get_size_hints(Client *c, struct wlr_box *max, struct wlr_box *min) -{ -	struct wlr_xdg_toplevel *toplevel; -	struct wlr_xdg_toplevel_state *state; -#ifdef XWAYLAND -	if (client_is_x11(c)) { -		xcb_size_hints_t *size_hints = c->surface.xwayland->size_hints; -		if (size_hints) { -			max->width = size_hints->max_width; -			max->height = size_hints->max_height; -			min->width = size_hints->min_width; -			min->height = size_hints->min_height; -		} -		return; -	} -#endif -	toplevel = c->surface.xdg->toplevel; -	state = &toplevel->current; -	max->width = state->max_width; -	max->height = state->max_height; -	min->width = state->min_width; -	min->height = state->min_height; +	return 0;  }  static inline struct wlr_surface * @@ -54,7 +28,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; @@ -65,44 +39,44 @@ toplevel_from_wlr_surface(struct wlr_surface *s, Client **pc, LayerSurface **pl)  #endif  	if (!s) -		return type; +		return -1;  	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;  		}  	} @@ -118,19 +92,16 @@ end:  static inline void  client_activate_surface(struct wlr_surface *s, int activated)  { -	struct wlr_xdg_surface *surface; +	struct wlr_xdg_toplevel *toplevel;  #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)) -			&& surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) -		wlr_xdg_toplevel_set_activated(surface->toplevel, activated); +	if ((toplevel = wlr_xdg_toplevel_try_from_wlr_surface(s))) +		wlr_xdg_toplevel_set_activated(toplevel, activated);  }  static inline uint32_t @@ -140,31 +111,45 @@ client_set_bounds(Client *c, int32_t width, int32_t height)  	if (client_is_x11(c))  		return 0;  #endif -	if (c->surface.xdg->client->shell->version >= -			XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION && width >= 0 && height >= 0) +	if (wl_resource_get_version(c->surface.xdg->toplevel->resource) >= +			XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION && width >= 0 && height >= 0 +			&& (c->bounds.width != width || c->bounds.height != height)) { +		c->bounds.width = width; +		c->bounds.height = height;  		return wlr_xdg_toplevel_set_bounds(c->surface.xdg->toplevel, width, height); +	}  	return 0;  } -static inline void -client_for_each_surface(Client *c, wlr_surface_iterator_func_t fn, void *data) +static inline const char * +client_get_appid(Client *c)  { -	wlr_surface_for_each_surface(client_surface(c), fn, data);  #ifdef XWAYLAND  	if (client_is_x11(c)) -		return; +		return c->surface.xwayland->class;  #endif -	wlr_xdg_surface_for_each_popup_surface(c->surface.xdg, fn, data); +	return c->surface.xdg->toplevel->app_id;  } -static inline const char * -client_get_appid(Client *c) +static inline void +client_get_clip(Client *c, struct wlr_box *clip)  { +	struct wlr_box xdg_geom = {0}; +	*clip = (struct wlr_box){ +		.x = 0, +		.y = 0, +		.width = c->geom.width - c->bw, +		.height = c->geom.height - c->bw, +	}; +  #ifdef XWAYLAND  	if (client_is_x11(c)) -		return c->surface.xwayland->class; +		return;  #endif -	return c->surface.xdg->toplevel->app_id; + +	wlr_xdg_surface_get_geometry(c->surface.xdg, &xdg_geom); +	clip->x = xdg_geom.x; +	clip->y = xdg_geom.y;  }  static inline void @@ -192,7 +177,6 @@ client_get_parent(Client *c)  #endif  	if (c->surface.xdg->toplevel->parent)  		toplevel_from_wlr_surface(c->surface.xdg->toplevel->parent->base->surface, &p, NULL); -  	return p;  } @@ -209,35 +193,35 @@ client_get_title(Client *c)  static inline int  client_is_float_type(Client *c)  { -	struct wlr_box min = {0}, max = {0}; -	client_get_size_hints(c, &max, &min); +	struct wlr_xdg_toplevel *toplevel; +	struct wlr_xdg_toplevel_state state;  #ifdef XWAYLAND  	if (client_is_x11(c)) {  		struct wlr_xwayland_surface *surface = c->surface.xwayland; +		xcb_size_hints_t *size_hints = surface->size_hints; +		size_t i;  		if (surface->modal)  			return 1; -		for (size_t i = 0; i < surface->window_type_len; i++) +		for (i = 0; i < surface->window_type_len; i++)  			if (surface->window_type[i] == netatom[NetWMWindowTypeDialog]  					|| surface->window_type[i] == netatom[NetWMWindowTypeSplash]  					|| surface->window_type[i] == netatom[NetWMWindowTypeToolbar]  					|| surface->window_type[i] == netatom[NetWMWindowTypeUtility])  				return 1; + +		return size_hints && size_hints->min_width > 0 && size_hints->min_height > 0 +			&& (size_hints->max_width == size_hints->min_width +				|| size_hints->max_height == size_hints->min_height);  	}  #endif -	return ((min.width > 0 || min.height > 0 || max.width > 0 || max.height > 0) -		&& (min.width == max.width || min.height == max.height)); -} -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; +	toplevel = c->surface.xdg->toplevel; +	state = toplevel->current; +	return toplevel->parent || (state.min_width != 0 && state.min_height != 0 +		&& (state.min_width == state.max_width +			|| state.min_height == state.max_height));  }  static inline int @@ -247,7 +231,8 @@ client_is_rendered_on_mon(Client *c, Monitor *m)  	 * but rather actual displaying of the pixels.  	 * Usually VISIBLEON suffices and is also faster. */  	struct wlr_surface_output *s; -	if (!c->scene->node.enabled) +	int unused_lx, unused_ly; +	if (!wlr_scene_node_coords(&c->scene->node, &unused_lx, &unused_ly))  		return 0;  	wl_list_for_each(s, &client_surface(c)->current_outputs, link)  		if (s->output == m->wlr_output) @@ -366,18 +351,25 @@ client_set_tiled(Client *c, uint32_t edges)  	if (client_is_x11(c))  		return;  #endif -	wlr_xdg_toplevel_set_tiled(c->surface.xdg->toplevel, edges); +	if (wl_resource_get_version(c->surface.xdg->resource) +			>= XDG_TOPLEVEL_STATE_TILED_RIGHT_SINCE_VERSION) { +		wlr_xdg_toplevel_set_tiled(c->surface.xdg->toplevel, edges); +	} else { +		wlr_xdg_toplevel_set_maximized(c->surface.xdg->toplevel, edges != WLR_EDGE_NONE); +	}  } -static inline struct wlr_surface * -client_surface_at(Client *c, double cx, double cy, double *sx, double *sy) +static inline void +client_set_suspended(Client *c, int suspended)  {  #ifdef XWAYLAND -	if (client_is_x11(c)) -		return wlr_surface_surface_at(c->surface.xwayland->surface, -				cx, cy, sx, sy); +	if (client_is_x11(c)) { +		wlr_xwayland_surface_set_withdrawn(c->surface.xwayland, suspended); +		return; +	}  #endif -	return wlr_xdg_surface_surface_at(c->surface.xdg, cx, cy, sx, sy); + +	wlr_xdg_toplevel_set_suspended(c->surface.xdg->toplevel, suspended);  }  static inline int @@ -3,7 +3,6 @@   */  #include <getopt.h>  #include <libinput.h> -#include <limits.h>  #include <linux/input-event-codes.h>  #include <signal.h>  #include <stdio.h> @@ -18,15 +17,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 +70,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 */ @@ -117,8 +118,11 @@ typedef struct {  	struct wl_listener set_title;  	struct wl_listener fullscreen;  	struct wlr_box prev; /* layout-relative, includes border */ +	struct wlr_box bounds;  #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 */ @@ -189,6 +194,7 @@ struct Monitor {  	unsigned int sellt;  	uint32_t tagset[2];  	double mfact; +	int gamma_lut_changed;  	int nmaster;  	char ltsymbol[16];  }; @@ -286,11 +292,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 +330,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 +343,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 +364,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 +377,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 xcb_atom_t 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 xcb_atom_t netatom[NetLast];  #endif @@ -417,19 +400,9 @@ static xcb_atom_t netatom[NetLast];  void  applybounds(Client *c, struct wlr_box *bbox)  { -	if (!c->isfullscreen) { -		struct wlr_box min = {0}, max = {0}; -		client_get_size_hints(c, &max, &min); -		/* try to set size hints */ -		c->geom.width = MAX(min.width + (2 * (int)c->bw), c->geom.width); -		c->geom.height = MAX(min.height + (2 * (int)c->bw), c->geom.height); -		/* Some clients set their max size to INT_MAX, which does not violate the -		 * protocol but it's unnecesary, as they can set their max size to zero. */ -		if (max.width > 0 && !(2 * c->bw > INT_MAX - max.width)) /* Checks for overflow */ -			c->geom.width = MIN(max.width + (2 * c->bw), c->geom.width); -		if (max.height > 0 && !(2 * c->bw > INT_MAX - max.height)) /* Checks for overflow */ -			c->geom.height = MIN(max.height + (2 * c->bw), c->geom.height); -	} +	/* set minimum possible */ +	c->geom.width = MAX(1, c->geom.width); +	c->geom.height = MAX(1, c->geom.height);  	if (c->geom.x >= bbox->x + bbox->width)  		c->geom.x = bbox->x + bbox->width - c->geom.width; @@ -475,9 +448,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 +535,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 +553,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 +578,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, "default");  			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 +600,7 @@ buttonpress(struct wl_listener *listener, void *data)  void  chvt(const Arg *arg)  { -	wlr_session_change_vt(wlr_backend_get_session(backend), arg->ui); +	wlr_session_change_vt(session, arg->ui);  }  void @@ -645,7 +618,6 @@ checkidleinhibitor(struct wlr_surface *exclude)  		}  	} -	wlr_idle_set_enabled(idle, NULL, !inhibited);  	wlr_idle_notifier_v1_set_inhibited(idle_notifier, inhibited);  } @@ -654,21 +626,19 @@ cleanup(void)  {  #ifdef XWAYLAND  	wlr_xwayland_destroy(xwayland); +	xwayland = NULL;  #endif  	wl_display_destroy_clients(dpy);  	if (child_pid > 0) {  		kill(child_pid, SIGTERM);  		waitpid(child_pid, NULL, 0);  	} -	wlr_backend_destroy(backend); -	wlr_scene_node_destroy(&scene->tree.node); -	wlr_renderer_destroy(drw); -	wlr_allocator_destroy(alloc);  	wlr_xcursor_manager_destroy(cursor_mgr); -	wlr_cursor_destroy(cursor);  	wlr_output_layout_destroy(output_layout); -	wlr_seat_destroy(seat);  	wl_display_destroy(dpy); +	/* Destroy after the wayland display (when the monitors are already destroyed) +	   to avoid destroying them with an invalid scene output. */ +	wlr_scene_node_destroy(&scene->tree.node);  }  void @@ -757,9 +727,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);  } @@ -769,6 +739,9 @@ commitnotify(struct wl_listener *listener, void *data)  {  	Client *c = wl_container_of(listener, c, commit); +	if (client_surface(c)->mapped) +		resize(c, c->geom, (c->isfloating && !c->isfullscreen)); +  	/* mark a pending resize as completed */  	if (c->resize && c->resize <= c->surface.xdg->current.configure_serial)  		c->resize = 0; @@ -785,7 +758,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);  } @@ -840,21 +813,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); @@ -915,7 +886,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; @@ -933,16 +903,12 @@ 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))  		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(); @@ -1006,8 +972,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, @@ -1074,8 +1044,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,20 +1118,25 @@ destroylocksurface(struct wl_listener *listener, void *data)  void  destroynotify(struct wl_listener *listener, void *data)  { -	/* Called when the surface is destroyed and should never be shown again. */ +	/* Called when the xdg_toplevel is destroyed. */  	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);  } @@ -1177,8 +1150,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 +1400,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 +1481,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 +1511,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 */ @@ -1610,9 +1575,14 @@ maximizenotify(struct wl_listener *listener, void *data)  	 * 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. +	 * Since xdg-shell protocol v5 we should ignore request of unsupported +	 * capabilities, just schedule a empty configure when the client uses <5 +	 * protocol version  	 * 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); +	if (wl_resource_get_version(c->surface.xdg->resource) +			< XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION) +		wlr_xdg_surface_schedule_configure(c->surface.xdg);  }  void @@ -1658,7 +1628,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 +1666,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, "default");  	pointerfocus(c, surface, sx, sy, time);  } @@ -1732,7 +1702,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 +1710,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, "se-resize");  		break;  	}  } @@ -1783,7 +1752,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 +1811,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 @@ -1898,6 +1868,8 @@ rendermon(struct wl_listener *listener, void *data)  	 * generally at the output's refresh rate (e.g. 60Hz). */  	Monitor *m = wl_container_of(listener, m, frame);  	Client *c; +	struct wlr_output_state pending = {0}; +	struct wlr_gamma_control_v1 *gamma_control;  	struct timespec now;  	/* Render if no XDG clients have an outstanding resize and are visible on @@ -1905,12 +1877,38 @@ 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); + +	/* +	 * HACK: The "correct" way to set the gamma is to commit it together with +	 * the rest of the state in one go, but to do that we would need to rewrite +	 * wlr_scene_output_commit() in order to add the gamma to the pending +	 * state before committing, instead try to commit the gamma in one frame, +	 * and commit the rest of the state in the next one (or in the same frame if +	 * the gamma can not be committed). +	 */ +	if (m->gamma_lut_changed) { +		gamma_control = wlr_gamma_control_manager_v1_get_control(gamma_control_mgr, m->wlr_output); +		m->gamma_lut_changed = 0; + +		if (!wlr_gamma_control_v1_apply(gamma_control, &pending)) +			goto commit; + +		if (!wlr_output_test_state(m->wlr_output, &pending)) { +			wlr_gamma_control_v1_send_failed_and_destroy(gamma_control); +			goto commit; +		} +		wlr_output_commit_state(m->wlr_output, &pending); +		wlr_output_schedule_frame(m->wlr_output); +	} else { +commit: +		wlr_scene_output_commit(m->scene_output, NULL); +	}  skip:  	/* Let clients know a frame has been rendered */  	clock_gettime(CLOCK_MONOTONIC, &now);  	wlr_scene_output_send_frame_done(m->scene_output, &now); +	wlr_output_state_finish(&pending);  }  void @@ -1926,9 +1924,18 @@ 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; +	struct wlr_box clip;  	client_set_bounds(c, geo.width, geo.height);  	c->geom = geo;  	applybounds(c, bbox); @@ -1947,6 +1954,8 @@ resize(Client *c, struct wlr_box geo, int interact)  	/* this is a no-op if size hasn't changed */  	c->resize = client_set_size(c, c->geom.width - 2 * c->bw,  			c->geom.height - 2 * c->bw); +	client_get_clip(c, &clip); +	wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, &clip);  }  void @@ -1992,7 +2001,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, "default");  	/* 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 +2020,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 +2031,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; @@ -2058,6 +2080,15 @@ setfullscreen(Client *c, int fullscreen)  }  void +setgamma(struct wl_listener *listener, void *data) +{ +	struct wlr_gamma_control_manager_v1_set_gamma_event *event = data; +	Monitor *m = event->output->data; +	m->gamma_lut_changed = 1; +	wlr_output_schedule_frame(m->wlr_output); +} + +void  setlayout(const Arg *arg)  {  	if (!selmon) @@ -2150,12 +2181,8 @@ setup(void)  	/* 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. The NULL argument here optionally allows you -	 * to pass in a custom renderer if wlr_renderer doesn't meet your needs. The -	 * 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 an X11 server is running. */ +	if (!(backend = wlr_backend_autocreate(dpy, &session)))  		die("couldn't create backend");  	/* Initialize the scene graph used to lay out windows */ @@ -2165,12 +2192,30 @@ setup(void)  	drag_icon = wlr_scene_tree_create(&scene->tree);  	wlr_scene_node_place_below(&drag_icon->node, &layers[LyrBlock]->node); -	/* Create a renderer with the default implementation */ +	/* Autocreates a renderer, either Pixman, GLES2 or Vulkan for us. The user +	 * can also specify a renderer using the WLR_RENDERER env var. +	 * The renderer is responsible for defining the various pixel formats it +	 * supports for shared memory, this configures that for clients. */  	if (!(drw = wlr_renderer_autocreate(backend)))  		die("couldn't create renderer"); -	wlr_renderer_init_wl_display(drw, dpy); -	/* Create a default allocator */ +	/* 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)); +	} + +	/* Autocreates an allocator for us. +	 * The allocator is the bridge between the renderer and the backend. It +	 * handles the buffer creation, allowing wlroots to render onto the +	 * screen */  	if (!(alloc = wlr_allocator_autocreate(backend, drw)))  		die("couldn't create allocator"); @@ -2180,33 +2225,36 @@ 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_subcompositor_create(dpy); +	wlr_data_device_manager_create(dpy);  	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_subcompositor_create(dpy); +	wlr_fractional_scale_manager_v1_create(dpy, 1);  	/* 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 +	/* Set up our client lists, the xdg-shell and the layer-shell. The xdg-shell is a  	 * Wayland protocol which is used for application windows. For more  	 * detail on shells, refer to the article:  	 * @@ -2215,22 +2263,20 @@ setup(void)  	wl_list_init(&clients);  	wl_list_init(&fstack); -	idle = wlr_idle_create(dpy); -	idle_notifier = wlr_idle_notifier_v1_create(dpy); +	xdg_shell = wlr_xdg_shell_create(dpy, 6); +	LISTEN_STATIC(&xdg_shell->events.new_surface, createnotify); -	idle_inhibit_mgr = wlr_idle_inhibit_v1_create(dpy); -	wl_signal_add(&idle_inhibit_mgr->events.new_inhibitor, &idle_inhibitor_create); +	layer_shell = wlr_layer_shell_v1_create(dpy, 3); +	LISTEN_STATIC(&layer_shell->events.new_surface, createlayersurface); -	layer_shell = wlr_layer_shell_v1_create(dpy); -	wl_signal_add(&layer_shell->events.new_surface, &new_layer_shell_surface); +	idle_notifier = wlr_idle_notifier_v1_create(dpy); -	xdg_shell = wlr_xdg_shell_create(dpy, 4); -	wl_signal_add(&xdg_shell->events.new_surface, &new_xdg_surface); +	idle_inhibit_mgr = wlr_idle_inhibit_v1_create(dpy); +	LISTEN_STATIC(&idle_inhibit_mgr->events.new_inhibitor, createidleinhibitor); -	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); @@ -2240,7 +2286,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 @@ -2261,18 +2307,19 @@ setup(void)  	 * when the pointer moves. However, we can attach input devices to it, and  	 * it will generate aggregate events for all of them. In these events, we  	 * can choose how we want to process them, forwarding them to clients and -	 * moving the cursor around. More detail on this process is described in my -	 * input handling blog post: -	 * +	 * moving the cursor around. More detail on this process is described in  	 * https://drewdevault.com/2018/07/17/Input-handling-in-wlroots.html  	 *  	 * 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 @@ -2281,20 +2328,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)); @@ -2305,8 +2351,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 { @@ -2333,8 +2379,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 @@ -2485,7 +2531,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); @@ -2524,7 +2569,6 @@ updatemons(struct wl_listener *listener, void *data)  		if (m->wlr_output->enabled  				&& !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 */  	wlr_output_layout_get_box(output_layout, NULL, &sgeom); @@ -2538,8 +2582,8 @@ updatemons(struct wl_listener *listener, void *data)  		config_head = wlr_output_configuration_head_v1_create(config, m->wlr_output);  		/* Get the effective monitor geometry to use for surfaces */ -		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_output_layout_get_box(output_layout, m->wlr_output, &m->m); +		m->w = m->m;  		wlr_scene_output_set_position(m->scene_output, m->m.x, m->m.y);  		wlr_scene_node_set_position(&m->fullscreen_bg->node, m->m.x, m->m.y); @@ -2556,7 +2600,11 @@ updatemons(struct wl_listener *listener, void *data)  		arrangelayers(m);  		/* Don't move clients to the left output when plugging monitors */  		arrange(m); +		/* make sure fullscreen clients have the right size */ +		if ((c = focustop(m)) && c->isfullscreen) +			resize(c, m->m, 0); +		m->gamma_lut_changed = 1;  		config_head->state.enabled = 1;  		config_head->state.mode = m->wlr_output->current_mode;  		config_head->state.x = m->m.x; @@ -2565,7 +2613,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) { @@ -2575,6 +2623,13 @@ updatemons(struct wl_listener *listener, void *data)  		}  	} +	/* FIXME: figure out why the cursor image is at 0,0 after turning all +	 * the monitors on. +	 * Move the cursor image where it used to be. It does not generate a +	 * wl_pointer.motion event for the clients, it's only the image what it's +	 * at the wrong position after all. */ +	wlr_cursor_move(cursor, NULL, 0, 0); +  	wlr_output_manager_v1_set_configuration(output_mgr, config);  } @@ -2595,7 +2650,7 @@ urgent(struct wl_listener *listener, void *data)  	if (!c || c == focustop(selmon))  		return; -	if (client_is_mapped(c)) +	if (client_surface(c)->mapped)  		client_set_border_color(c, urgentcolor);  	c->isurgent = 1;  	printstatus(); @@ -2643,7 +2698,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) @@ -2703,6 +2758,15 @@ 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.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); @@ -2729,8 +2793,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); @@ -2739,6 +2803,14 @@ 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->map.link); +	wl_list_remove(&c->unmap.link); +} +  xcb_atom_t  getatom(xcb_connection_t *xc, const char *name)  { @@ -2756,12 +2828,13 @@ void  sethints(struct wl_listener *listener, void *data)  {  	Client *c = wl_container_of(listener, c, set_hints); +	struct wlr_surface *surface = client_surface(c);  	if (c == focustop(selmon))  		return;  	c->isurgent = xcb_icccm_wm_hints_get_urgency(c->surface.xwayland->hints); -	if (c->isurgent && client_is_mapped(c)) +	if (c->isurgent && surface && surface->mapped)  		client_set_border_color(c, urgentcolor);  	printstatus(); @@ -2789,7 +2862,7 @@ xwaylandready(struct wl_listener *listener, void *data)  	wlr_xwayland_set_seat(xwayland, seat);  	/* Set the default XWayland cursor to match the rest of dwl. */ -	if ((xcursor = wlr_xcursor_manager_get_xcursor(cursor_mgr, "left_ptr", 1))) +	if ((xcursor = wlr_xcursor_manager_get_xcursor(cursor_mgr, "default", 1)))  		wlr_xwayland_set_cursor(xwayland,  				xcursor->images[0]->buffer, xcursor->images[0]->width * 4,  				xcursor->images[0]->width, xcursor->images[0]->height, | 
