diff options
| -rw-r--r-- | Makefile | 5 | ||||
| -rw-r--r-- | client.h | 75 | ||||
| -rw-r--r-- | dwl.c | 315 | 
3 files changed, 227 insertions, 168 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, @@ -369,6 +357,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 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 @@ -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 * @@ -1425,12 +1412,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; @@ -1507,13 +1493,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); @@ -1538,17 +1523,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 */ @@ -1656,7 +1635,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) @@ -1694,8 +1673,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);  } @@ -1730,7 +1709,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 @@ -1738,8 +1717,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;  	}  } @@ -1781,7 +1759,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); @@ -1840,6 +1818,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 @@ -1903,7 +1882,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 */ @@ -1924,6 +1903,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; @@ -1990,7 +1977,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 @@ -2009,7 +1996,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 @@ -2021,6 +2007,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; @@ -2056,6 +2056,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) @@ -2153,7 +2174,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 */ @@ -2166,7 +2187,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))) @@ -2178,31 +2211,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 @@ -2213,22 +2249,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); @@ -2238,7 +2272,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 @@ -2266,11 +2300,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 @@ -2279,20 +2316,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)); @@ -2303,8 +2339,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 { @@ -2331,8 +2367,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 @@ -2483,7 +2519,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); @@ -2563,7 +2598,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) { @@ -2593,7 +2628,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(); @@ -2641,7 +2676,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) @@ -2701,6 +2736,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); @@ -2727,8 +2772,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); @@ -2737,6 +2782,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); +} +  xcb_atom_t  getatom(xcb_connection_t *xc, const char *name)  { @@ -2754,12 +2808,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(); | 
