diff options
Diffstat (limited to 'dwl.c')
| -rw-r--r-- | dwl.c | 828 | 
1 files changed, 345 insertions, 483 deletions
| @@ -13,6 +13,7 @@  #include <libinput.h>  #include <wayland-server-core.h>  #include <wlr/backend.h> +#include <wlr/render/allocator.h>  #include <wlr/render/wlr_renderer.h>  #include <wlr/types/wlr_compositor.h>  #include <wlr/types/wlr_cursor.h> @@ -29,9 +30,11 @@  #include <wlr/types/wlr_output_layout.h>  #include <wlr/types/wlr_output_management_v1.h>  #include <wlr/types/wlr_pointer.h> +#include <wlr/types/wlr_presentation_time.h>  #include <wlr/types/wlr_primary_selection.h>  #include <wlr/types/wlr_primary_selection_v1.h>  #include <wlr/types/wlr_screencopy_v1.h> +#include <wlr/types/wlr_scene.h>  #include <wlr/types/wlr_server_decoration.h>  #include <wlr/types/wlr_seat.h>  #include <wlr/types/wlr_viewporter.h> @@ -55,19 +58,19 @@  #define MAX(A, B)               ((A) > (B) ? (A) : (B))  #define MIN(A, B)               ((A) < (B) ? (A) : (B))  #define CLEANMASK(mask)         (mask & ~WLR_MODIFIER_CAPS) -#define VISIBLEON(C, M)         ((C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags])) +#define VISIBLEON(C, M)         ((M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags]))  #define LENGTH(X)               (sizeof X / sizeof X[0])  #define END(A)                  ((A) + LENGTH(A))  #define TAGMASK                 ((1 << LENGTH(tags)) - 1) -#define ROUND(X)                ((int)((X)+0.5))  #define LISTEN(E, L, H)         wl_signal_add((E), ((L)->notify = (H), (L)))  /* enums */  enum { CurNormal, CurMove, CurResize }; /* cursor */ +enum { XDGShell, LayerShell, X11Managed, X11Unmanaged }; /* client types */ +enum { LyrBg, LyrBottom, LyrTop, LyrOverlay, LyrTile, LyrFloat, NUM_LAYERS }; /* scene layers */  #ifdef XWAYLAND  enum { NetWMWindowTypeDialog, NetWMWindowTypeSplash, NetWMWindowTypeToolbar,  	NetWMWindowTypeUtility, NetLast }; /* EWMH atoms */ -enum { XDGShell, X11Managed, X11Unmanaged }; /* client types */  #endif  typedef union { @@ -86,9 +89,13 @@ typedef struct {  typedef struct Monitor Monitor;  typedef struct { +	/* Must be first */ +	unsigned int type; /* XDGShell or X11* */ +	struct wlr_scene_node *scene; +	struct wlr_scene_rect *border[4]; /* top, bottom, left, right */ +	struct wlr_scene_node *scene_surface;  	struct wl_list link;  	struct wl_list flink; -	struct wl_list slink;  	union {  		struct wlr_xdg_surface *xdg;  		struct wlr_xwayland_surface *xwayland; @@ -99,10 +106,9 @@ typedef struct {  	struct wl_listener destroy;  	struct wl_listener set_title;  	struct wl_listener fullscreen; -	struct wlr_box geom;  /* layout-relative, includes border */ +	struct wlr_box geom, prev;  /* layout-relative, includes border */  	Monitor *mon;  #ifdef XWAYLAND -	unsigned int type;  	struct wl_listener activate;  	struct wl_listener configure;  #endif @@ -110,19 +116,10 @@ typedef struct {  	unsigned int tags;  	int isfloating, isurgent;  	uint32_t resize; /* configure serial of a pending resize */ -	int prevx; -	int prevy; -	int prevwidth; -	int prevheight;  	int isfullscreen;  } Client;  typedef struct { -	struct wl_listener request_mode; -	struct wl_listener destroy; -} Decoration; - -typedef struct {  	uint32_t mod;  	xkb_keysym_t keysym;  	void (*func)(const Arg *); @@ -139,8 +136,11 @@ typedef struct {  } Keyboard;  typedef struct { -	struct wlr_layer_surface_v1 *layer_surface; +	/* Must be first */ +	unsigned int type; /* LayerShell */ +	struct wlr_scene_node *scene;  	struct wl_list link; +	struct wlr_layer_surface_v1 *layer_surface;  	struct wl_listener destroy;  	struct wl_listener map; @@ -148,7 +148,6 @@ typedef struct {  	struct wl_listener surface_commit;  	struct wlr_box geo; -	enum zwlr_layer_shell_v1_layer layer;  } LayerSurface;  typedef struct { @@ -167,11 +166,12 @@ typedef struct {  struct Monitor {  	struct wl_list link;  	struct wlr_output *wlr_output; +	struct wlr_scene_output *scene_output;  	struct wl_listener frame;  	struct wl_listener destroy;  	struct wlr_box m;      /* monitor area, layout-relative */  	struct wlr_box w;      /* window area, layout-relative */ -	struct wl_list layers[4]; // LayerSurface::link +	struct wl_list layers[4]; /* LayerSurface::link */  	const Layout *lt[2];  	unsigned int seltags;  	unsigned int sellt; @@ -199,14 +199,6 @@ typedef struct {  	int monitor;  } Rule; -/* Used to move all of the data necessary to render a surface from the top-level - * frame handler to the per-surface render function. */ -struct render_data { -	struct wlr_output *output; -	struct timespec *when; -	int x, y; /* layout-relative */ -}; -  /* function declarations */  static void applybounds(Client *c, struct wlr_box *bbox);  static void applyexclusive(struct wlr_box *usable_area, uint32_t anchor, @@ -235,6 +227,7 @@ static void cursorframe(struct wl_listener *listener, void *data);  static void destroylayersurfacenotify(struct wl_listener *listener, void *data);  static void destroynotify(struct wl_listener *listener, void *data);  static Monitor *dirtomon(enum wlr_direction dir); +static void dragicondestroy(struct wl_listener *listener, void *data);  static void focusclient(Client *c, int lift);  static void focusmon(const Arg *arg);  static void focusstack(const Arg *arg); @@ -261,13 +254,10 @@ static void pointerfocus(Client *c, struct wlr_surface *surface,  static void printstatus(void);  static void quit(const Arg *arg);  static void quitsignal(int signo); -static void render(struct wlr_surface *surface, int sx, int sy, void *data); -static void renderclients(Monitor *m, struct timespec *now); -static void renderlayer(struct wl_list *layer_surfaces, struct timespec *now);  static void rendermon(struct wl_listener *listener, void *data); +static void requeststartdrag(struct wl_listener *listener, void *data);  static void resize(Client *c, int x, int y, int w, int h, int interact);  static void run(char *startup_cmd); -static void scalebox(struct wlr_box *box, float scale);  static Client *selclient(void);  static void setcursor(struct wl_listener *listener, void *data);  static void setpsel(struct wl_listener *listener, void *data); @@ -280,6 +270,7 @@ static void setmon(Client *c, Monitor *m, unsigned int newtags);  static void setup(void);  static void sigchld(int unused);  static void spawn(const Arg *arg); +static void startdrag(struct wl_listener *listener, void *data);  static void tag(const Arg *arg);  static void tagmon(const Arg *arg);  static void tile(Monitor *m); @@ -295,9 +286,8 @@ static void updatetitle(struct wl_listener *listener, void *data);  static void urgent(struct wl_listener *listener, void *data);  static void view(const Arg *arg);  static void virtualkeyboard(struct wl_listener *listener, void *data); -static Client *xytoclient(double x, double y); -static struct wlr_surface *xytolayersurface(struct wl_list *layer_surfaces, -		double x, double y, double *sx, double *sy); +static struct wlr_scene_node *xytonode(double x, double y, struct wlr_surface **psurface, +		Client **pc, LayerSurface **pl, double *nx, double *ny);  static Monitor *xytomon(double x, double y);  static void zoom(const Arg *arg); @@ -305,26 +295,24 @@ static void zoom(const Arg *arg);  static const char broken[] = "broken";  static struct wl_display *dpy;  static struct wlr_backend *backend; +static struct wlr_scene *scene; +static struct wlr_scene_node *layers[NUM_LAYERS];  static struct wlr_renderer *drw; +static struct wlr_allocator *alloc;  static struct wlr_compositor *compositor;  static struct wlr_xdg_shell *xdg_shell;  static struct wlr_xdg_activation_v1 *activation;  static struct wl_list clients; /* tiling order */  static struct wl_list fstack;  /* focus order */ -static struct wl_list stack;   /* stacking z-order */ -static struct wl_list independents;  static struct wlr_idle *idle;  static struct wlr_layer_shell_v1 *layer_shell;  static struct wlr_output_manager_v1 *output_mgr; +static struct wlr_presentation *presentation;  static struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard_mgr;  static struct wlr_cursor *cursor;  static struct wlr_xcursor_manager *cursor_mgr; -#ifdef XWAYLAND -static struct wlr_xcursor *xcursor; -static struct wlr_xcursor_manager *xcursor_mgr; -#endif  static struct wlr_seat *seat;  static struct wl_list keyboards; @@ -355,15 +343,16 @@ 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 drag_icon_destroy = {.notify = dragicondestroy};  #ifdef XWAYLAND  static void activatex11(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 Atom getatom(xcb_connection_t *xc, const char *name); -static void renderindependents(struct wlr_output *output, struct timespec *now);  static void xwaylandready(struct wl_listener *listener, void *data); -static Client *xytoindependent(double x, double y);  static struct wl_listener new_xwayland_surface = {.notify = createnotifyx11};  static struct wl_listener xwayland_ready = {.notify = xwaylandready};  static struct wlr_xwayland *xwayland; @@ -403,7 +392,7 @@ applyexclusive(struct wlr_box *usable_area,  		int32_t margin_top, int32_t margin_right,  		int32_t margin_bottom, int32_t margin_left) {  	Edge edges[] = { -		{ // Top +		{ /* Top */  			.singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP,  			.anchor_triplet = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT |  				ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | @@ -412,7 +401,7 @@ applyexclusive(struct wlr_box *usable_area,  			.negative_axis = &usable_area->height,  			.margin = margin_top,  		}, -		{ // Bottom +		{ /* Bottom */  			.singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM,  			.anchor_triplet = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT |  				ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | @@ -421,7 +410,7 @@ applyexclusive(struct wlr_box *usable_area,  			.negative_axis = &usable_area->height,  			.margin = margin_bottom,  		}, -		{ // Left +		{ /* Left */  			.singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT,  			.anchor_triplet = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT |  				ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | @@ -430,7 +419,7 @@ applyexclusive(struct wlr_box *usable_area,  			.negative_axis = &usable_area->width,  			.margin = margin_left,  		}, -		{ // Right +		{ /* Right */  			.singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT,  			.anchor_triplet = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT |  				ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | @@ -478,12 +467,17 @@ applyrules(Client *c)  					mon = m;  		}  	} +	wlr_scene_node_reparent(c->scene, layers[c->isfloating ? LyrFloat : LyrTile]);  	setmon(c, mon, newtags);  }  void  arrange(Monitor *m)  { +	Client *c; +	wl_list_for_each(c, &clients, link) +		wlr_scene_node_set_enabled(c->scene, VISIBLEON(c, c->mon)); +  	if (m->lt[m->sellt]->arrange)  		m->lt[m->sellt]->arrange(m);  	/* TODO recheck pointer focus here... or in resize()? */ @@ -513,7 +507,7 @@ arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int  		bounds = state->exclusive_zone == -1 ? full_area : *usable_area; -		// Horizontal axis +		/* Horizontal axis */  		if ((state->anchor & both_horiz) && box.width == 0) {  			box.x = bounds.x;  			box.width = bounds.width; @@ -524,7 +518,7 @@ arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int  		} else {  			box.x = bounds.x + ((bounds.width / 2) - (box.width / 2));  		} -		// Vertical axis +		/* Vertical axis */  		if ((state->anchor & both_vert) && box.height == 0) {  			box.y = bounds.y;  			box.height = bounds.height; @@ -535,7 +529,7 @@ arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int  		} else {  			box.y = bounds.y + ((bounds.height / 2) - (box.height / 2));  		} -		// Margin +		/* Margin */  		if ((state->anchor & both_horiz) == both_horiz) {  			box.x += state->margin.left;  			box.width -= state->margin.left + state->margin.right; @@ -553,7 +547,7 @@ arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int  			box.y -= state->margin.bottom;  		}  		if (box.width < 0 || box.height < 0) { -			wlr_layer_surface_v1_close(wlr_layer_surface); +			wlr_layer_surface_v1_destroy(wlr_layer_surface);  			continue;  		}  		layersurface->geo = box; @@ -562,6 +556,7 @@ arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int  			applyexclusive(usable_area, state->anchor, state->exclusive_zone,  					state->margin.top, state->margin.right,  					state->margin.bottom, state->margin.left); +		wlr_scene_node_set_position(layersurface->scene, box.x, box.y);  		wlr_layer_surface_v1_configure(wlr_layer_surface, box.width, box.height);  	}  } @@ -569,6 +564,7 @@ arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int  void  arrangelayers(Monitor *m)  { +	int i;  	struct wlr_box usable_area = m->m;  	uint32_t layers_above_shell[] = {  		ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, @@ -577,38 +573,26 @@ arrangelayers(Monitor *m)  	LayerSurface *layersurface;  	struct wlr_keyboard *kb = wlr_seat_get_keyboard(seat); -	// Arrange exclusive surfaces from top->bottom -	arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], -			&usable_area, 1); -	arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], -			&usable_area, 1); -	arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], -			&usable_area, 1); -	arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], -			&usable_area, 1); +	/* Arrange exclusive surfaces from top->bottom */ +	for (i = 3; i >= 0; i--) +		arrangelayer(m, &m->layers[i], &usable_area, 1);  	if (memcmp(&usable_area, &m->w, sizeof(struct wlr_box))) {  		m->w = usable_area;  		arrange(m);  	} -	// Arrange non-exlusive surfaces from top->bottom -	arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], -			&usable_area, 0); -	arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], -			&usable_area, 0); -	arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], -			&usable_area, 0); -	arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], -			&usable_area, 0); - -	// Find topmost keyboard interactive layer, if such a layer exists +	/* Arrange non-exlusive surfaces from top->bottom */ +	for (i = 3; i >= 0; i--) +		arrangelayer(m, &m->layers[i], &usable_area, 0); + +	/* Find topmost keyboard interactive layer, if such a layer exists */  	for (size_t i = 0; i < LENGTH(layers_above_shell); i++) {  		wl_list_for_each_reverse(layersurface,  				&m->layers[layers_above_shell[i]], link) {  			if (layersurface->layer_surface->current.keyboard_interactive &&  					layersurface->layer_surface->mapped) { -				// Deactivate the focused client. +				/* Deactivate the focused client. */  				focusclient(NULL, 0);  				wlr_seat_keyboard_notify_enter(seat, layersurface->layer_surface->surface,  						kb->keycodes, kb->num_keycodes, &kb->modifiers); @@ -643,9 +627,11 @@ buttonpress(struct wl_listener *listener, void *data)  	wlr_idle_notify_activity(idle, seat);  	switch (event->state) { -	case WLR_BUTTON_PRESSED:; +	case WLR_BUTTON_PRESSED:  		/* Change focus if the button was _pressed_ over a client */ -		if ((c = xytoclient(cursor->x, cursor->y))) +		xytonode(cursor->x, cursor->y, NULL, &c, NULL, NULL, NULL); +		/* Don't focus unmanaged clients */ +		if (c && !client_is_unmanaged(c))  			focusclient(c, 1);  		keyboard = wlr_seat_get_keyboard(seat); @@ -662,8 +648,7 @@ buttonpress(struct wl_listener *listener, void *data)  		/* If you released any buttons, we exit interactive move/resize mode. */  		/* TODO should reset to the pointer focus's current setcursor */  		if (cursor_mode != CurNormal) { -			wlr_xcursor_manager_set_cursor_image(cursor_mgr, -					"left_ptr", cursor); +			wlr_xcursor_manager_set_cursor_image(cursor_mgr, "left_ptr", cursor);  			cursor_mode = CurNormal;  			/* Drop the window off on its new monitor */  			selmon = xytomon(cursor->x, cursor->y); @@ -724,11 +709,13 @@ cleanupmon(struct wl_listener *listener, void *data)  	wl_list_remove(&m->frame.link);  	wl_list_remove(&m->link);  	wlr_output_layout_remove(output_layout, m->wlr_output); +	wlr_scene_output_destroy(m->scene_output); + +	if ((nmons = wl_list_length(&mons))) +		do /* don't switch to disabled mons */ +			selmon = wl_container_of(mons.prev, selmon, link); +		while (!selmon->wlr_output->enabled && i++ < nmons); -	nmons = wl_list_length(&mons); -	do // don't switch to disabled mons -		selmon = wl_container_of(mons.prev, selmon, link); -	while (!selmon->wlr_output->enabled && i++ < nmons);  	focusclient(focustop(selmon), 1);  	closemon(m);  	free(m); @@ -737,7 +724,7 @@ cleanupmon(struct wl_listener *listener, void *data)  void  closemon(Monitor *m)  { -	// move closed monitor's clients to the focused one +	/* move closed monitor's clients to the focused one */  	Client *c;  	wl_list_for_each(c, &clients, link) { @@ -757,18 +744,19 @@ commitlayersurfacenotify(struct wl_listener *listener, void *data)  	struct wlr_output *wlr_output = wlr_layer_surface->output;  	Monitor *m; +	wlr_scene_node_reparent(layersurface->scene, +			layers[wlr_layer_surface->current.layer]); +  	if (!wlr_output)  		return; -  	m = wlr_output->data; -	arrangelayers(m); -	if (layersurface->layer != wlr_layer_surface->current.layer) { +	if (layers[wlr_layer_surface->current.layer] != layersurface->scene) {  		wl_list_remove(&layersurface->link);  		wl_list_insert(&m->layers[wlr_layer_surface->current.layer],  			&layersurface->link); -		layersurface->layer = wlr_layer_surface->current.layer;  	} +	arrangelayers(m);  }  void @@ -777,7 +765,7 @@ commitnotify(struct wl_listener *listener, void *data)  	Client *c = wl_container_of(listener, c, commit);  	/* mark a pending resize as completed */ -	if (c->resize && c->resize <= c->surface.xdg->configure_serial) +	if (c->resize && c->resize <= c->surface.xdg->current.configure_serial)  		c->resize = 0;  } @@ -787,11 +775,13 @@ createkeyboard(struct wlr_input_device *device)  	struct xkb_context *context;  	struct xkb_keymap *keymap;  	Keyboard *kb = device->data = calloc(1, sizeof(*kb)); +	if (!kb) +		EBARF("createkeyboard: calloc");  	kb->device = device;  	/* Prepare an XKB keymap and assign it to the keyboard. */  	context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); -	keymap = xkb_map_new_from_names(context, &xkb_rules, +	keymap = xkb_keymap_new_from_names(context, &xkb_rules,  		XKB_KEYMAP_COMPILE_NO_FLAGS);  	wlr_keyboard_set_keymap(device->keyboard, keymap); @@ -818,8 +808,12 @@ createmon(struct wl_listener *listener, void *data)  	struct wlr_output *wlr_output = data;  	const MonitorRule *r;  	Monitor *m = wlr_output->data = calloc(1, sizeof(*m)); +	if (!m) +		EBARF("createmon: calloc");  	m->wlr_output = wlr_output; +	wlr_output_init_render(wlr_output, alloc, drw); +  	/* Initialize monitor state using configured rules */  	for (size_t i = 0; i < LENGTH(m->layers); i++)  		wl_list_init(&m->layers[i]); @@ -860,19 +854,17 @@ createmon(struct wl_listener *listener, void *data)  	 * display, which Wayland clients can see to find out information about the  	 * output (such as DPI, scale factor, manufacturer, etc).  	 */ -	wlr_output_layout_add(output_layout, wlr_output, r->x, r->y); -	sgeom = *wlr_output_layout_get_box(output_layout, NULL); +	m->scene_output = wlr_scene_output_create(scene, wlr_output); +	wlr_output_layout_add_auto(output_layout, wlr_output); -	/* When adding monitors, the geometries of all monitors must be updated */ -	wl_list_for_each(m, &mons, link) { -		/* The first monitor in the list is the most recently added */ +	/* If length == 1 we need update selmon. +	 * Maybe it will change in run(). */ +	if (wl_list_length(&mons) == 1) {  		Client *c; -		wl_list_for_each(c, &clients, link) { -			if (c->isfloating) -				resize(c, c->geom.x + m->w.width, c->geom.y, -						c->geom.width, c->geom.height, 0); -		} -		return; +		selmon = m; +		/* If there is any client, set c->mon to this monitor */ +		wl_list_for_each(c, &clients, link) +			setmon(c, m, c->tags);  	}  } @@ -880,15 +872,31 @@ void  createnotify(struct wl_listener *listener, void *data)  {  	/* This event is raised when wlr_xdg_shell receives a new xdg surface from a -	 * client, either a toplevel (application window) or popup. */ +	 * client, either a toplevel (application window) or popup, +	 * or when wlr_layer_shell receives a new popup from a layer. +	 * If you want to do something tricky with popups you should check if +	 * its parent is wlr_xdg_shell or wlr_layer_shell */  	struct wlr_xdg_surface *xdg_surface = data;  	Client *c; -	if (xdg_surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) +	if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { +		struct wlr_box box; +		xdg_surface->surface->data = wlr_scene_xdg_surface_create( +				xdg_surface->popup->parent->data, xdg_surface); +		if (!(c = client_from_popup(xdg_surface->popup)) || !c->mon) +			return; +		box = c->mon->m; +		box.x -= c->geom.x; +		box.y -= c->geom.y; +		wlr_xdg_popup_unconstrain_from_box(xdg_surface->popup, &box); +		return; +	} else if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_NONE)  		return;  	/* Allocate a Client for this surface */  	c = xdg_surface->data = calloc(1, sizeof(*c)); +	if (!c) +		EBARF("createnotify: calloc");  	c->surface.xdg = xdg_surface;  	c->bw = borderpx; @@ -915,6 +923,9 @@ createlayersurface(struct wl_listener *listener, void *data)  	}  	layersurface = calloc(1, sizeof(LayerSurface)); +	if (!layersurface) +		EBARF("layersurface: calloc"); +	layersurface->type = LayerShell;  	LISTEN(&wlr_layer_surface->surface->events.commit,  		&layersurface->surface_commit, commitlayersurfacenotify);  	LISTEN(&wlr_layer_surface->events.destroy, &layersurface->destroy, @@ -926,15 +937,21 @@ createlayersurface(struct wl_listener *listener, void *data)  	layersurface->layer_surface = wlr_layer_surface;  	wlr_layer_surface->data = layersurface; -  	m = wlr_layer_surface->output->data; -	wl_list_insert(&m->layers[wlr_layer_surface->client_pending.layer], + +	layersurface->scene = wlr_layer_surface->surface->data = +			wlr_scene_subsurface_tree_create(layers[wlr_layer_surface->pending.layer], +			wlr_layer_surface->surface); +	layersurface->scene->data = layersurface; + +	wl_list_insert(&m->layers[wlr_layer_surface->pending.layer],  			&layersurface->link); -	// Temporarily set the layer's current state to client_pending -	// so that we can easily arrange it +	/* Temporarily set the layer's current state to pending +	 * so that we can easily arrange it +	 */  	old_state = wlr_layer_surface->current; -	wlr_layer_surface->current = wlr_layer_surface->client_pending; +	wlr_layer_surface->current = wlr_layer_surface->pending;  	arrangelayers(m);  	wlr_layer_surface->current = old_state;  } @@ -1003,15 +1020,26 @@ destroynotify(struct wl_listener *listener, void *data)  	wl_list_remove(&c->set_title.link);  	wl_list_remove(&c->fullscreen.link);  #ifdef XWAYLAND -	if (c->type == X11Managed) +	if (c->type != XDGShell) { +		wl_list_remove(&c->configure.link);  		wl_list_remove(&c->activate.link); -	else if (c->type == XDGShell) +	} else  #endif  		wl_list_remove(&c->commit.link);  	free(c);  }  void +dragicondestroy(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(selclient(), 1); +	motionnotify(0); +} + +void  togglefullscreen(const Arg *arg)  {  	Client *sel = selclient(); @@ -1023,28 +1051,33 @@ void  setfullscreen(Client *c, int fullscreen)  {  	c->isfullscreen = fullscreen; -	c->bw = (1 - fullscreen) * borderpx; +	c->bw = fullscreen ? 0 : borderpx;  	client_set_fullscreen(c, fullscreen);  	if (fullscreen) { -		c->prevx = c->geom.x; -		c->prevy = c->geom.y; -		c->prevheight = c->geom.height; -		c->prevwidth = c->geom.width; +		c->prev = c->geom;  		resize(c, c->mon->m.x, c->mon->m.y, c->mon->m.width, c->mon->m.height, 0);  	} else {  		/* restore previous size instead of arrange for floating windows since  		 * client positions are set by the user and cannot be recalculated */ -		resize(c, c->prevx, c->prevy, c->prevwidth, c->prevheight, 0); -		arrange(c->mon); +		resize(c, c->prev.x, c->prev.y, c->prev.width, c->prev.height, 0);  	} +	arrange(c->mon); +	printstatus();  }  void  fullscreennotify(struct wl_listener *listener, void *data)  {  	Client *c = wl_container_of(listener, c, fullscreen); -	setfullscreen(c, !c->isfullscreen); +	int fullscreen = client_wants_fullscreen(c); + +	if (!c->mon) { +		/* if the client is not mapped yet, let mapnotify() call setfullscreen() */ +		c->isfullscreen = fullscreen; +		return; +	} +	setfullscreen(c, fullscreen);  }  Monitor * @@ -1066,12 +1099,11 @@ focusclient(Client *c, int lift)  {  	struct wlr_surface *old = seat->keyboard_state.focused_surface;  	struct wlr_keyboard *kb; +	int i;  	/* Raise client in stacking order if requested */ -	if (c && lift) { -		wl_list_remove(&c->slink); -		wl_list_insert(&stack, &c->slink); -	} +	if (c && lift) +		wlr_scene_node_raise_to_top(c->scene);  	if (c && client_surface(c) == old)  		return; @@ -1082,8 +1114,10 @@ focusclient(Client *c, int lift)  		wl_list_insert(&fstack, &c->flink);  		selmon = c->mon;  		c->isurgent = 0; + +		for (i = 0; i < 4; i++) +			wlr_scene_rect_set_color(c->border[i], focuscolor);  	} -	printstatus();  	/* Deactivate old client if focus is changing */  	if (old && (!c || client_surface(c) != old)) { @@ -1102,10 +1136,18 @@ focusclient(Client *c, int lift)  						))  				return;  		} else { +			Client *w; +			struct wlr_scene_node *node = old->data; +			if ((w = node->data)) +				for (i = 0; i < 4; i++) +					wlr_scene_rect_set_color(w->border[i], bordercolor); +  			client_activate_surface(old, 0);  		}  	} +	printstatus(); +  	if (!c) {  		/* With no client, all we have left is to clear focus */  		wlr_seat_keyboard_notify_clear_focus(seat); @@ -1278,16 +1320,16 @@ void  killclient(const Arg *arg)  {  	Client *sel = selclient(); -	if (!sel) -		return; -	client_send_close(sel); +	if (sel) +		client_send_close(sel);  }  void  maplayersurfacenotify(struct wl_listener *listener, void *data)  {  	LayerSurface *layersurface = wl_container_of(listener, layersurface, map); -	wlr_surface_send_enter(layersurface->layer_surface->surface, layersurface->layer_surface->output); +	wlr_surface_send_enter(layersurface->layer_surface->surface, +		layersurface->layer_surface->output);  	motionnotify(0);  } @@ -1296,27 +1338,47 @@ mapnotify(struct wl_listener *listener, void *data)  {  	/* Called when the surface is mapped, or ready to display on-screen. */  	Client *c = wl_container_of(listener, c, map); +	int i; + +	/* Create scene tree for this client and its border */ +	c->scene = &wlr_scene_tree_create(layers[LyrTile])->node; +	c->scene_surface = client_surface(c)->data = c->type == XDGShell +			? wlr_scene_xdg_surface_create(c->scene, c->surface.xdg) +			: wlr_scene_subsurface_tree_create(c->scene, client_surface(c)); +	c->scene_surface->data = c;  	if (client_is_unmanaged(c)) { -		/* Insert this independent into independents lists. */ -		wl_list_insert(&independents, &c->link); +		client_get_geometry(c, &c->geom); +		/* Floating */ +		wlr_scene_node_reparent(c->scene, layers[LyrFloat]); +		wlr_scene_node_set_position(c->scene, c->geom.x + borderpx, +			c->geom.y + borderpx);  		return;  	} -	/* Insert this client into client lists. */ -	wl_list_insert(&clients, &c->link); -	wl_list_insert(&fstack, &c->flink); -	wl_list_insert(&stack, &c->slink); +	for (i = 0; i < 4; i++) { +		c->border[i] = wlr_scene_rect_create(c->scene, 0, 0, bordercolor); +		c->border[i]->node.data = c; +		wlr_scene_rect_set_color(c->border[i], bordercolor); +		wlr_scene_node_lower_to_bottom(&c->border[i]->node); +	} +	/* Initialize client geometry with room for border */ +	client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | WLR_EDGE_RIGHT);  	client_get_geometry(c, &c->geom);  	c->geom.width += 2 * c->bw;  	c->geom.height += 2 * c->bw; -	/* Tell the client not to try anything fancy */ -	client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | WLR_EDGE_RIGHT); +	/* Insert this client into client lists. */ +	wl_list_insert(&clients, &c->link); +	wl_list_insert(&fstack, &c->flink);  	/* Set initial monitor, tags, floating status, and focus */  	applyrules(c); +	printstatus(); + +	if (c->isfullscreen) +		setfullscreen(c, 1);  }  void @@ -1349,10 +1411,10 @@ void  motionnotify(uint32_t time)  {  	double sx = 0, sy = 0; -	struct wlr_surface *surface = NULL;  	Client *c = NULL; +	struct wlr_surface *surface = NULL; -	// time is 0 in internal calls meant to restore pointer focus. +	/* time is 0 in internal calls meant to restore pointer focus. */  	if (time) {  		wlr_idle_notify_activity(idle, seat); @@ -1374,39 +1436,14 @@ motionnotify(uint32_t time)  		return;  	} -	if ((surface = xytolayersurface(&selmon->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], -					cursor->x, cursor->y, &sx, &sy))) -		; -	else if ((surface = xytolayersurface(&selmon->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], -					cursor->x, cursor->y, &sx, &sy))) -		; -#ifdef XWAYLAND -	/* Find an independent under the pointer and send the event along. */ -	else if ((c = xytoindependent(cursor->x, cursor->y))) { -		surface = wlr_surface_surface_at(c->surface.xwayland->surface, -				cursor->x - c->surface.xwayland->x - c->bw, -				cursor->y - c->surface.xwayland->y - c->bw, &sx, &sy); - -	/* Otherwise, find the client under the pointer and send the event along. */ -	} -#endif -	else if ((c = xytoclient(cursor->x, cursor->y))) { -		surface = client_surface_at(c, cursor->x - c->geom.x - c->bw, -				cursor->y - c->geom.y - c->bw, &sx, &sy); -	} -	else if ((surface = xytolayersurface(&selmon->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], -					cursor->x, cursor->y, &sx, &sy))) -		; -	else -		surface = xytolayersurface(&selmon->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], -					cursor->x, cursor->y, &sx, &sy); +	/* Find the client under the pointer and send the event along. */ +	xytonode(cursor->x, cursor->y, &surface, &c, NULL, &sx, &sy);  	/* 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 && time) -		wlr_xcursor_manager_set_cursor_image(cursor_mgr, -				"left_ptr", cursor); +		wlr_xcursor_manager_set_cursor_image(cursor_mgr, "left_ptr", cursor);  	pointerfocus(c, surface, sx, sy, time);  } @@ -1422,15 +1459,17 @@ motionrelative(struct wl_listener *listener, void *data)  	 * special configuration applied for the specific input device which  	 * generated the event. You can pass NULL for the device if you want to move  	 * the cursor around without any input. */ -	wlr_cursor_move(cursor, event->device, -			event->delta_x, event->delta_y); +	wlr_cursor_move(cursor, event->device, event->delta_x, event->delta_y);  	motionnotify(event->time_msec);  }  void  moveresize(const Arg *arg)  { -	if (cursor_mode != CurNormal || !(grabc = xytoclient(cursor->x, cursor->y))) +	if (cursor_mode != CurNormal) +		return; +	xytonode(cursor->x, cursor->y, NULL, &grabc, NULL, NULL, NULL); +	if (!grabc || client_is_unmanaged(grabc))  		return;  	/* Float the window and tell motionnotify to grab it */ @@ -1520,10 +1559,10 @@ pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy,  {  	struct timespec now;  	int internal_call = !time; +	struct wlr_drag_icon *icon; -	/* Use top level surface if nothing more specific given */ -	if (c && !surface) -		surface = client_surface(c); +	if (sloppyfocus && !internal_call && c && !client_is_unmanaged(c)) +		focusclient(c, 0);  	/* If surface is NULL, clear pointer focus */  	if (!surface) { @@ -1536,21 +1575,19 @@ pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy,  		time = now.tv_sec * 1000 + now.tv_nsec / 1000000;  	} -	/* If surface is already focused, only notify of motion */ -	if (surface == seat->pointer_state.focused_surface) { -		wlr_seat_pointer_notify_motion(seat, time, sx, sy); -		return; -	} - -	/* Otherwise, let the client know that the mouse cursor has entered one -	 * of its surfaces, and make keyboard focus follow if desired. */ +	/* Let the client know that the mouse cursor has entered one +	 * of its surfaces, and make keyboard focus follow if desired. +	 * 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); -	if (!c || client_is_unmanaged(c)) -		return; - -	if (sloppyfocus && !internal_call) -		focusclient(c, 0); +	/* If there are is a drag icon, update its position */ +	/* For anyone who wants to change this function: for some reason +	 * (maybe a wlroots bug?, or is it intended?) if we change the node position +	 * before telling the seat for a motion, the clients don't recognize the drag */ +	if (seat->drag && (icon = seat->drag->icon)) +		wlr_scene_node_set_position(icon->data, cursor->x + icon->surface->sx, +				cursor->y + icon->surface->sy);  }  void @@ -1570,10 +1607,14 @@ printstatus(void)  				urg |= c->tags;  		}  		if ((c = focustop(m))) { -			printf("%s title %s\n", m->wlr_output->name, client_get_title(focustop(m))); +			printf("%s title %s\n", m->wlr_output->name, client_get_title(c)); +			printf("%s fullscreen %u\n", m->wlr_output->name, c->isfullscreen); +			printf("%s floating %u\n", m->wlr_output->name, c->isfloating);  			sel = c->tags;  		} else {  			printf("%s title \n", m->wlr_output->name); +			printf("%s fullscreen \n", m->wlr_output->name); +			printf("%s floating \n", m->wlr_output->name);  			sel = 0;  		} @@ -1598,211 +1639,69 @@ quitsignal(int signo)  }  void -render(struct wlr_surface *surface, int sx, int sy, void *data) -{ -	/* This function is called for every surface that needs to be rendered. */ -	struct render_data *rdata = data; -	struct wlr_output *output = rdata->output; -	double ox = 0, oy = 0; -	struct wlr_box obox; -	float matrix[9]; -	enum wl_output_transform transform; - -	/* We first obtain a wlr_texture, which is a GPU resource. wlroots -	 * automatically handles negotiating these with the client. The underlying -	 * resource could be an opaque handle passed from the client, or the client -	 * could have sent a pixel buffer which we copied to the GPU, or a few other -	 * means. You don't have to worry about this, wlroots takes care of it. */ -	struct wlr_texture *texture = wlr_surface_get_texture(surface); -	if (!texture) -		return; - -	/* The client has a position in layout coordinates. If you have two displays, -	 * one next to the other, both 1080p, a client on the rightmost display might -	 * have layout coordinates of 2000,100. We need to translate that to -	 * output-local coordinates, or (2000 - 1920). */ -	wlr_output_layout_output_coords(output_layout, output, &ox, &oy); - -	/* We also have to apply the scale factor for HiDPI outputs. This is only -	 * part of the puzzle, dwl does not fully support HiDPI. */ -	obox.x = ox + rdata->x + sx; -	obox.y = oy + rdata->y + sy; -	obox.width = surface->current.width; -	obox.height = surface->current.height; -	scalebox(&obox, output->scale); - -	/* -	 * Those familiar with OpenGL are also familiar with the role of matrices -	 * in graphics programming. We need to prepare a matrix to render the -	 * client with. wlr_matrix_project_box is a helper which takes a box with -	 * a desired x, y coordinates, width and height, and an output geometry, -	 * then prepares an orthographic projection and multiplies the necessary -	 * transforms to produce a model-view-projection matrix. -	 * -	 * Naturally you can do this any way you like, for example to make a 3D -	 * compositor. -	 */ -	transform = wlr_output_transform_invert(surface->current.transform); -	wlr_matrix_project_box(matrix, &obox, transform, 0, -		output->transform_matrix); - -	/* This takes our matrix, the texture, and an alpha, and performs the actual -	 * rendering on the GPU. */ -	wlr_render_texture_with_matrix(drw, texture, matrix, 1); - -	/* This lets the client know that we've displayed that frame and it can -	 * prepare another one now if it likes. */ -	wlr_surface_send_frame_done(surface, rdata->when); -} - -void -renderclients(Monitor *m, struct timespec *now) -{ -	Client *c, *sel = selclient(); -	const float *color; -	double ox, oy; -	int i, w, h; -	struct render_data rdata; -	struct wlr_box *borders; -	struct wlr_surface *surface; -	/* Each subsequent window we render is rendered on top of the last. Because -	 * our stacking list is ordered front-to-back, we iterate over it backwards. */ -	wl_list_for_each_reverse(c, &stack, slink) { -		/* Only render visible clients which show on this monitor */ -		if (!VISIBLEON(c, c->mon) || !wlr_output_layout_intersects( -					output_layout, m->wlr_output, &c->geom)) -			continue; - -		surface = client_surface(c); -		ox = c->geom.x, oy = c->geom.y; -		wlr_output_layout_output_coords(output_layout, m->wlr_output, -				&ox, &oy); - -		if (c->bw) { -			w = surface->current.width; -			h = surface->current.height; -			borders = (struct wlr_box[4]) { -				{ox, oy, w + 2 * c->bw, c->bw},             /* top */ -				{ox, oy + c->bw, c->bw, h},                 /* left */ -				{ox + c->bw + w, oy + c->bw, c->bw, h},     /* right */ -				{ox, oy + c->bw + h, w + 2 * c->bw, c->bw}, /* bottom */ -			}; - -			/* Draw window borders */ -			color = (c == sel) ? focuscolor : bordercolor; -			for (i = 0; i < 4; i++) { -				scalebox(&borders[i], m->wlr_output->scale); -				wlr_render_rect(drw, &borders[i], color, -						m->wlr_output->transform_matrix); -			} -		} - -		/* This calls our render function for each surface among the -		 * xdg_surface's toplevel and popups. */ -		rdata.output = m->wlr_output; -		rdata.when = now; -		rdata.x = c->geom.x + c->bw; -		rdata.y = c->geom.y + c->bw; -		client_for_each_surface(c, render, &rdata); -	} -} - -void -renderlayer(struct wl_list *layer_surfaces, struct timespec *now) -{ -	LayerSurface *layersurface; -	wl_list_for_each(layersurface, layer_surfaces, link) { -		struct render_data rdata = { -			.output = layersurface->layer_surface->output, -			.when = now, -			.x = layersurface->geo.x, -			.y = layersurface->geo.y, -		}; - -		wlr_surface_for_each_surface(layersurface->layer_surface->surface, -				render, &rdata); -	} -} - -void  rendermon(struct wl_listener *listener, void *data)  { -	Client *c; -	int render = 1; -  	/* This function is called every time an output is ready to display a frame,  	 * generally at the output's refresh rate (e.g. 60Hz). */  	Monitor *m = wl_container_of(listener, m, frame); - +	Client *c; +	int skip = 0;  	struct timespec now; -	clock_gettime(CLOCK_MONOTONIC, &now); - -	/* Do not render if any XDG clients have an outstanding resize. */ -	wl_list_for_each(c, &stack, slink) { -		if (c->resize) { -			wlr_surface_send_frame_done(client_surface(c), &now); -			render = 0; -		} -	} - -	/* HACK: This loop is the simplest way to handle ephemeral pageflip -	 * failures but probably not the best. Revisit if damage tracking is -	 * added. */ -	do { -		/* wlr_output_attach_render makes the OpenGL context current. */ -		if (!wlr_output_attach_render(m->wlr_output, NULL)) -			return; -		if (render) { -			/* Begin the renderer (calls glViewport and some other GL sanity checks) */ -			wlr_renderer_begin(drw, m->wlr_output->width, m->wlr_output->height); -			wlr_renderer_clear(drw, rootcolor); - -			renderlayer(&m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], &now); -			renderlayer(&m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], &now); -			renderclients(m, &now); -#ifdef XWAYLAND -			renderindependents(m->wlr_output, &now); -#endif -			renderlayer(&m->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], &now); -			renderlayer(&m->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], &now); - -			/* Hardware cursors are rendered by the GPU on a separate plane, and can be -			 * moved around without re-rendering what's beneath them - which is more -			 * efficient. However, not all hardware supports hardware cursors. For this -			 * reason, wlroots provides a software fallback, which we ask it to render -			 * here. wlr_cursor handles configuring hardware vs software cursors for you, -			 * and this function is a no-op when hardware cursors are in use. */ -			wlr_output_render_software_cursors(m->wlr_output, NULL); - -			/* Conclude rendering and swap the buffers, showing the final frame -			 * on-screen. */ -			wlr_renderer_end(drw); -		} +	/* Render if no XDG clients have an outstanding resize and are visible on +	 * this monitor. +	 */ +	wl_list_for_each(c, &clients, link) +		skip = skip || (c->resize && VISIBLEON(c, m)); +	if (!skip && !wlr_scene_output_commit(m->scene_output)) +		return; -	} while (!wlr_output_commit(m->wlr_output)); +	/* Let clients know a frame has been rendered */ +	clock_gettime(CLOCK_MONOTONIC, &now); +	wlr_scene_output_send_frame_done(m->scene_output, &now);  }  void  resize(Client *c, int x, int y, int w, int h, int interact)  { -	/* -	 * Note that I took some shortcuts here. In a more fleshed-out -	 * compositor, you'd wait for the client to prepare a buffer at -	 * the new size, then commit any movement that was prepared. -	 */ +	int min_width = 0, min_height = 0;  	struct wlr_box *bbox = interact ? &sgeom : &c->mon->w; +	client_min_size(c, &min_width, &min_height);  	c->geom.x = x;  	c->geom.y = y; -	c->geom.width = w; -	c->geom.height = h; +	c->geom.width = MAX(min_width + 2 * c->bw, w); +	c->geom.height = MAX(min_height + 2 * c->bw, h);  	applybounds(c, bbox); + +	/* Update scene-graph, including borders */ +	wlr_scene_node_set_position(c->scene, c->geom.x, c->geom.y); +	wlr_scene_node_set_position(c->scene_surface, c->bw, c->bw); +	wlr_scene_rect_set_size(c->border[0], c->geom.width, c->bw); +	wlr_scene_rect_set_size(c->border[1], c->geom.width, c->bw); +	wlr_scene_rect_set_size(c->border[2], c->bw, c->geom.height - 2 * c->bw); +	wlr_scene_rect_set_size(c->border[3], c->bw, c->geom.height - 2 * c->bw); +	wlr_scene_node_set_position(&c->border[1]->node, 0, c->geom.height - c->bw); +	wlr_scene_node_set_position(&c->border[2]->node, 0, c->bw); +	wlr_scene_node_set_position(&c->border[3]->node, c->geom.width - c->bw, c->bw); +  	/* wlroots makes this 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);  }  void +requeststartdrag(struct wl_listener *listener, void *data) +{ +	struct wlr_seat_request_start_drag_event *event = data; + +	if (wlr_seat_validate_pointer_grab_serial(seat, event->origin, +			event->serial)) +		wlr_seat_start_pointer_drag(seat, event->drag, event->serial); +	else +		wlr_data_source_destroy(event->drag->source); +} + +void  run(char *startup_cmd)  {  	pid_t startup_pid = -1; @@ -1822,11 +1721,13 @@ run(char *startup_cmd)  			EBARF("startup: fork");  		if (startup_pid == 0) {  			dup2(piperw[0], STDIN_FILENO); +			close(piperw[0]);  			close(piperw[1]);  			execl("/bin/sh", "/bin/sh", "-c", startup_cmd, NULL);  			EBARF("startup: execl");  		}  		dup2(piperw[1], STDOUT_FILENO); +		close(piperw[1]);  		close(piperw[0]);  	}  	/* If nobody is reading the status output, don't terminate */ @@ -1861,15 +1762,6 @@ run(char *startup_cmd)  	}  } -void -scalebox(struct wlr_box *box, float scale) -{ -	box->width =  ROUND((box->x + box->width) * scale) -  ROUND(box->x * scale); -	box->height = ROUND((box->y + box->height) * scale) - ROUND(box->y * scale); -	box->x = ROUND(box->x * scale); -	box->y = ROUND(box->y * scale); -} -  Client *  selclient(void)  { @@ -1902,7 +1794,9 @@ void  setfloating(Client *c, int floating)  {  	c->isfloating = floating; +	wlr_scene_node_reparent(c->scene, layers[c->isfloating ? LyrFloat : LyrTile]);  	arrange(c->mon); +	printstatus();  }  void @@ -1948,7 +1842,7 @@ setmon(Client *c, Monitor *m, unsigned int newtags)  	}  	if (m) {  		/* Make sure window actually overlaps with the monitor */ -		applybounds(c, &m->m); +		resize(c, c->geom.x, c->geom.y, c->geom.width, c->geom.height, 0);  		wlr_surface_send_enter(client_surface(c), m->wlr_output);  		c->tags = newtags ? newtags : m->tagset[m->seltags]; /* assign tags of target monitor */  		arrange(m); @@ -2001,12 +1895,24 @@ setup(void)  	if (!(backend = wlr_backend_autocreate(dpy)))  		BARF("couldn't create backend"); -	/* If we don't provide a renderer, autocreate makes a GLES2 renderer for us. -	 * The renderer is responsible for defining the various pixel formats it -	 * supports for shared memory, this configures that for clients. */ -	drw = wlr_backend_get_renderer(backend); +	/* Initialize the scene graph used to lay out windows */ +	scene = wlr_scene_create(); +	layers[LyrBg] = &wlr_scene_tree_create(&scene->node)->node; +	layers[LyrBottom] = &wlr_scene_tree_create(&scene->node)->node; +	layers[LyrTile] = &wlr_scene_tree_create(&scene->node)->node; +	layers[LyrFloat] = &wlr_scene_tree_create(&scene->node)->node; +	layers[LyrTop] = &wlr_scene_tree_create(&scene->node)->node; +	layers[LyrOverlay] = &wlr_scene_tree_create(&scene->node)->node; + +	/* Create a renderer with the default implementation */ +	if (!(drw = wlr_renderer_autocreate(backend))) +		BARF("couldn't create renderer");  	wlr_renderer_init_wl_display(drw, dpy); +	/* Create a default allocator */ +	if (!(alloc = wlr_allocator_autocreate(backend, drw))) +		BARF("couldn't create allocator"); +  	/* This creates some hands-off wlroots interfaces. The compositor is  	 * necessary for clients to allocate surfaces and the data device manager  	 * handles the clipboard. Each of these wlroots interfaces has room for you @@ -2045,8 +1951,6 @@ setup(void)  	 */  	wl_list_init(&clients);  	wl_list_init(&fstack); -	wl_list_init(&stack); -	wl_list_init(&independents);  	idle = wlr_idle_create(dpy); @@ -2105,17 +2009,19 @@ setup(void)  	wl_signal_add(&virtual_keyboard_mgr->events.new_virtual_keyboard,  			&new_virtual_keyboard);  	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_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);  	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); +	presentation = wlr_presentation_create(dpy, backend); +	wlr_scene_set_presentation(scene, presentation); +  #ifdef XWAYLAND  	/*  	 * Initialise the XWayland X server. @@ -2126,18 +2032,6 @@ setup(void)  		wl_signal_add(&xwayland->events.ready, &xwayland_ready);  		wl_signal_add(&xwayland->events.new_surface, &new_xwayland_surface); -		/* -		 * Create the XWayland cursor manager at scale 1, setting its default -		 * pointer to match the rest of dwl. -		 */ -		xcursor_mgr = wlr_xcursor_manager_create(NULL, 24); -		wlr_xcursor_manager_load(xcursor_mgr, 1); -		if ((xcursor = wlr_xcursor_manager_get_xcursor(xcursor_mgr, "left_ptr", 1))) -			wlr_xwayland_set_cursor(xwayland, -					xcursor->images[0]->buffer, xcursor->images[0]->width * 4, -					xcursor->images[0]->width, xcursor->images[0]->height, -					xcursor->images[0]->hotspot_x, xcursor->images[0]->hotspot_y); -  		setenv("DISPLAY", xwayland->display_name, 1);  	} else {  		fprintf(stderr, "failed to setup XWayland X server, continuing without it\n"); @@ -2171,6 +2065,19 @@ spawn(const Arg *arg)  }  void +startdrag(struct wl_listener *listener, void *data) +{ +	struct wlr_drag *drag = data; + +	if (!drag->icon) +		return; + +	drag->icon->data = wlr_scene_subsurface_tree_create(layers[LyrTop], drag->icon->surface); +	wlr_scene_node_raise_to_top(drag->icon->data); +	wl_signal_add(&drag->icon->events.destroy, &drag_icon_destroy); +} + +void  tag(const Arg *arg)  {  	Client *sel = selclient(); @@ -2198,7 +2105,7 @@ tile(Monitor *m)  	Client *c;  	wl_list_for_each(c, &clients, link) -		if (VISIBLEON(c, m) && !c->isfloating) +		if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen)  			n++;  	if (n == 0)  		return; @@ -2228,10 +2135,9 @@ void  togglefloating(const Arg *arg)  {  	Client *sel = selclient(); -	if (!sel) -		return;  	/* return if fullscreen */ -	setfloating(sel, !sel->isfloating /* || sel->isfixed */); +	if (sel && !sel->isfullscreen) +		setfloating(sel, !sel->isfloating);  }  void @@ -2285,13 +2191,21 @@ unmapnotify(struct wl_listener *listener, void *data)  {  	/* Called when the surface is unmapped, and should no longer be shown. */  	Client *c = wl_container_of(listener, c, unmap); -	wl_list_remove(&c->link); -	if (client_is_unmanaged(c)) +	if (c == grabc) { +		cursor_mode = CurNormal; +		grabc = NULL; +	} + +	if (client_is_unmanaged(c)) { +		wlr_scene_node_destroy(c->scene);  		return; +	} +	wl_list_remove(&c->link);  	setmon(c, NULL, 0);  	wl_list_remove(&c->flink); -	wl_list_remove(&c->slink); +	wlr_scene_node_destroy(c->scene); +	printstatus();  }  void @@ -2317,6 +2231,7 @@ updatemons(struct wl_listener *listener, void *data)  		/* Get the effective monitor geometry to use for surfaces */  		m->m = m->w = *wlr_output_layout_get_box(output_layout, m->wlr_output); +		wlr_scene_output_set_position(m->scene_output, m->m.x, m->m.y);  		/* Calculate the effective monitor geometry to use for clients */  		arrangelayers(m);  		/* Don't move clients to the left output when plugging monitors */ @@ -2375,37 +2290,31 @@ virtualkeyboard(struct wl_listener *listener, void *data)  	createkeyboard(device);  } -Client * -xytoclient(double x, double y) +struct wlr_scene_node * +xytonode(double x, double y, struct wlr_surface **psurface, +		Client **pc, LayerSurface **pl, double *nx, double *ny)  { -	/* Find the topmost visible client (if any) at point (x, y), including -	 * borders. This relies on stack being ordered from top to bottom. */ -	Client *c; -	wl_list_for_each(c, &stack, slink) -		if (VISIBLEON(c, c->mon) && wlr_box_contains_point(&c->geom, x, y)) -			return c; -	return NULL; -} - -struct wlr_surface * -xytolayersurface(struct wl_list *layer_surfaces, double x, double y, -		double *sx, double *sy) -{ -	LayerSurface *layersurface; -	wl_list_for_each_reverse(layersurface, layer_surfaces, link) { -		struct wlr_surface *sub; -		if (!layersurface->layer_surface->mapped) -			continue; -		sub = wlr_layer_surface_v1_surface_at( -				layersurface->layer_surface, -				x - layersurface->geo.x, -				y - layersurface->geo.y, -				sx, sy); -		if (sub) -			return sub; - +	struct wlr_scene_node *node, *pnode; +	struct wlr_surface *surface = NULL; +	Client *c = NULL; +	LayerSurface *l = NULL; + +	if ((node = wlr_scene_node_at(&scene->node, x, y, nx, ny))) { +		if (node->type == WLR_SCENE_NODE_SURFACE) +			surface = wlr_scene_surface_from_node(node)->surface; +		/* Walk the tree to find a node that knows the client */ +		for (pnode = node; pnode && !c; pnode = pnode->parent) +			c = pnode->data; +		if (c && c->type == LayerShell) { +			c = NULL; +			l = pnode->data; +		}  	} -	return NULL; + +	if (psurface) *psurface = surface; +	if (pc) *pc = c; +	if (pl) *pl = l; +	return node;  }  Monitor * @@ -2478,6 +2387,8 @@ createnotifyx11(struct wl_listener *listener, void *data)  	/* Allocate a Client for this surface */  	c = xwayland_surface->data = calloc(1, sizeof(*c)); +	if (!c) +		EBARF("createnotifyx11: calloc");  	c->surface.xwayland = xwayland_surface;  	c->type = xwayland_surface->override_redirect ? X11Unmanaged : X11Managed;  	c->bw = borderpx; @@ -2486,8 +2397,7 @@ createnotifyx11(struct wl_listener *listener, void *data)  	/* Listen to the various events it can emit */  	LISTEN(&xwayland_surface->events.map, &c->map, mapnotify);  	LISTEN(&xwayland_surface->events.unmap, &c->unmap, unmapnotify); -	LISTEN(&xwayland_surface->events.request_activate, &c->activate, -			activatex11); +	LISTEN(&xwayland_surface->events.request_activate, &c->activate, activatex11);  	LISTEN(&xwayland_surface->events.request_configure, &c->configure,  			configurex11);  	LISTEN(&xwayland_surface->events.set_title, &c->set_title, updatetitle); @@ -2510,31 +2420,6 @@ getatom(xcb_connection_t *xc, const char *name)  }  void -renderindependents(struct wlr_output *output, struct timespec *now) -{ -	Client *c; -	struct render_data rdata; -	struct wlr_box geom; - -	wl_list_for_each_reverse(c, &independents, link) { -		geom.x = c->surface.xwayland->x; -		geom.y = c->surface.xwayland->y; -		geom.width = c->surface.xwayland->width; -		geom.height = c->surface.xwayland->height; - -		/* Only render visible clients which show on this output */ -		if (!wlr_output_layout_intersects(output_layout, output, &geom)) -			continue; - -		rdata.output = output; -		rdata.when = now; -		rdata.x = c->surface.xwayland->x; -		rdata.y = c->surface.xwayland->y; -		wlr_surface_for_each_surface(c->surface.xwayland->surface, render, &rdata); -	} -} - -void  xwaylandready(struct wl_listener *listener, void *data)  {  	struct wlr_xcursor *xcursor; @@ -2564,28 +2449,6 @@ xwaylandready(struct wl_listener *listener, void *data)  	xcb_disconnect(xc);  } - -Client * -xytoindependent(double x, double y) -{ -	/* Find the topmost visible independent at point (x, y). -	 * For independents, the most recently created can be used as the "top". -	 * We rely on the X11 convention of unmapping unmanaged when the "owning" -	 * client loses focus, which ensures that unmanaged are only visible on -	 * the current tag. */ -	Client *c; -	wl_list_for_each_reverse(c, &independents, link) { -		struct wlr_box geom = { -			.x = c->surface.xwayland->x, -			.y = c->surface.xwayland->y, -			.width = c->surface.xwayland->width, -			.height = c->surface.xwayland->height, -		}; -		if (wlr_box_contains_point(&geom, x, y)) -			return c; -	} -	return NULL; -}  #endif  int @@ -2603,8 +2466,7 @@ main(int argc, char *argv[])  	if (optind < argc)  		goto usage; -	// Wayland requires XDG_RUNTIME_DIR for creating its communications -	// socket +	/* Wayland requires XDG_RUNTIME_DIR for creating its communications socket */  	if (!getenv("XDG_RUNTIME_DIR"))  		BARF("XDG_RUNTIME_DIR must be set");  	setup(); | 
