diff options
| author | Devin J. Pohly <djpohly@gmail.com> | 2020-12-24 21:56:41 -0500 | 
|---|---|---|
| committer | Devin J. Pohly <djpohly@gmail.com> | 2020-12-24 21:56:41 -0500 | 
| commit | 206427537a2abd075157e62da09000f2b5aaf42c (patch) | |
| tree | f9241b75f64dbc19b8f6f1babf75a059e02ea234 /dwl.c | |
| parent | cfe78159033968d80a83b7f879f8281267cc2751 (diff) | |
| parent | 3695ac643fb621f9339137afbc274c82ab46d088 (diff) | |
Merge updates from guidocella
Thanks so much for helping to keep the project running while life was
crazy!
Diffstat (limited to 'dwl.c')
| -rw-r--r-- | dwl.c | 675 | 
1 files changed, 435 insertions, 240 deletions
| @@ -16,21 +16,25 @@  #include <wlr/render/wlr_renderer.h>  #include <wlr/types/wlr_compositor.h>  #include <wlr/types/wlr_cursor.h> +#include <wlr/types/wlr_data_control_v1.h>  #include <wlr/types/wlr_data_device.h>  #include <wlr/types/wlr_export_dmabuf_v1.h>  #include <wlr/types/wlr_gamma_control_v1.h>  #include <wlr/types/wlr_input_device.h> +#include <wlr/types/wlr_idle.h>  #include <wlr/types/wlr_layer_shell_v1.h>  #include <wlr/types/wlr_keyboard.h>  #include <wlr/types/wlr_matrix.h>  #include <wlr/types/wlr_output.h>  #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_primary_selection.h>  #include <wlr/types/wlr_primary_selection_v1.h>  #include <wlr/types/wlr_screencopy_v1.h>  #include <wlr/types/wlr_seat.h>  #include <wlr/types/wlr_viewporter.h> +#include <wlr/types/wlr_virtual_keyboard_v1.h>  #include <wlr/types/wlr_xcursor_manager.h>  #include <wlr/types/wlr_xdg_decoration_v1.h>  #include <wlr/types/wlr_xdg_output_v1.h> @@ -95,6 +99,7 @@ typedef struct {  	} surface;  #ifdef XWAYLAND  	struct wl_listener activate; +	struct wl_listener configure;  #endif  	struct wl_listener commit;  	struct wl_listener map; @@ -171,6 +176,7 @@ struct Monitor {  	double mfact;  	int nmaster;  	Client *fullscreenclient; +	int position;  };  typedef struct { @@ -206,7 +212,7 @@ static void applyexclusive(struct wlr_box *usable_area, uint32_t anchor,  static void applyrules(Client *c);  static void arrange(Monitor *m);  static void arrangelayer(Monitor *m, struct wl_list *list, -		struct wlr_box *usable_area, bool exclusive); +		struct wlr_box *usable_area, int exclusive);  static void arrangelayers(Monitor *m);  static void axisnotify(struct wl_listener *listener, void *data);  static void buttonpress(struct wl_listener *listener, void *data); @@ -214,6 +220,7 @@ static void chvt(const Arg *arg);  static void cleanup(void);  static void cleanupkeyboard(struct wl_listener *listener, void *data);  static void cleanupmon(struct wl_listener *listener, void *data); +static void closemon(Monitor *m);  static void commitlayersurfacenotify(struct wl_listener *listener, void *data);  static void commitnotify(struct wl_listener *listener, void *data);  static void createkeyboard(struct wlr_input_device *device); @@ -227,7 +234,7 @@ static void destroylayersurfacenotify(struct wl_listener *listener, void *data);  static void destroynotify(struct wl_listener *listener, void *data);  static void destroyxdeco(struct wl_listener *listener, void *data);  static Monitor *dirtomon(int dir); -static void focusclient(Client *old, Client *c, int lift); +static void focusclient(Client *c, int lift);  static void focusmon(const Arg *arg);  static void focusstack(const Arg *arg);  static void fullscreennotify(struct wl_listener *listener, void *data); @@ -240,13 +247,16 @@ static void keypress(struct wl_listener *listener, void *data);  static void keypressmod(struct wl_listener *listener, void *data);  static void killclient(const Arg *arg);  static void maplayersurfacenotify(struct wl_listener *listener, void *data); -static void maprequest(struct wl_listener *listener, void *data); +static void mapnotify(struct wl_listener *listener, void *data);  static void maximizeclient(Client *c);  static void monocle(Monitor *m);  static void motionabsolute(struct wl_listener *listener, void *data);  static void motionnotify(uint32_t time);  static void motionrelative(struct wl_listener *listener, void *data);  static void moveresize(const Arg *arg); +static void outputmgrapply(struct wl_listener *listener, void *data); +static void outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test); +static void outputmgrtest(struct wl_listener *listener, void *data);  static void pointerfocus(Client *c, struct wlr_surface *surface,  		double sx, double sy, uint32_t time);  static void quit(const Arg *arg); @@ -268,7 +278,6 @@ static void setmfact(const Arg *arg);  static void setmon(Client *c, Monitor *m, unsigned int newtags);  static void setup(void);  static void sigchld(int unused); -static bool shouldfocusclients();  static void spawn(const Arg *arg);  static void tag(const Arg *arg);  static void tagmon(const Arg *arg); @@ -282,6 +291,7 @@ static void unmaplayersurfacenotify(struct wl_listener *listener, void *data);  static void unmapnotify(struct wl_listener *listener, void *data);  static void updatemons();  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); @@ -300,8 +310,11 @@ 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_xdg_decoration_manager_v1 *xdeco_mgr; +static struct wlr_output_manager_v1 *output_mgr; +static struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard_mgr;  static struct wlr_cursor *cursor;  static struct wlr_xcursor_manager *cursor_mgr; @@ -328,16 +341,20 @@ 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 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_xdeco = {.notify = createxdeco};  static struct wl_listener new_xdg_surface = {.notify = createnotify};  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_cursor = {.notify = setcursor};  static struct wl_listener request_set_psel = {.notify = setpsel};  static struct wl_listener request_set_sel = {.notify = setsel};  #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); @@ -379,53 +396,61 @@ applyexclusive(struct wlr_box *usable_area,  		uint32_t anchor, int32_t exclusive,  		int32_t margin_top, int32_t margin_right,  		int32_t margin_bottom, int32_t margin_left) { +	if (exclusive <= 0) +		return; +  	struct {  		uint32_t singular_anchor;  		uint32_t anchor_triplet;  		int *positive_axis;  		int *negative_axis;  		int margin; -	} edges[4]; - -	if (exclusive <= 0) -		return; - -	// Top -	edges[0].singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP; -	edges[0].anchor_triplet = -		ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | -		ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | -		ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP; -	edges[0].positive_axis = &usable_area->y; -	edges[0].negative_axis = &usable_area->height; -	edges[0].margin = margin_top; -	// Bottom -	edges[1].singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; -	edges[1].anchor_triplet = -		ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | -		ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | -		ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; -	edges[1].positive_axis = NULL; -	edges[1].negative_axis = &usable_area->height; -	edges[1].margin = margin_bottom; -	// Left -	edges[2].singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT; -	edges[2].anchor_triplet = -		ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | -		ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | -		ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; -	edges[2].positive_axis = &usable_area->x; -	edges[2].negative_axis = &usable_area->width; -	edges[2].margin = margin_left; -	// Right -	edges[3].singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; -	edges[3].anchor_triplet = -		ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | -		ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | -		ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; -	edges[3].positive_axis = NULL; -	edges[3].negative_axis = &usable_area->width; -	edges[3].margin = margin_right; +	} edges[] = { +		// Top +		{ +			.singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP, +			.anchor_triplet = +				ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | +				ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | +				ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP, +			.positive_axis = &usable_area->y, +			.negative_axis = &usable_area->height, +			.margin = margin_top, +		}, +		// Bottom +		{ +			.singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM, +			.anchor_triplet = +				ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | +				ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | +				ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM, +			.positive_axis = NULL, +			.negative_axis = &usable_area->height, +			.margin = margin_bottom, +		}, +		// Left +		{ +			.singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT, +			.anchor_triplet = +				ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | +				ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | +				ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM, +			.positive_axis = &usable_area->x, +			.negative_axis = &usable_area->width, +			.margin = margin_left, +		}, +		// Right +		{ +			.singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT, +			.anchor_triplet = +				ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | +				ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | +				ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM, +			.positive_axis = NULL, +			.negative_axis = &usable_area->width, +			.margin = margin_right, +		}, +	};  	for (size_t i = 0; i < LENGTH(edges); ++i) {  		if ((anchor == edges[i].singular_anchor || anchor == edges[i].anchor_triplet) @@ -442,13 +467,8 @@ applyexclusive(struct wlr_box *usable_area,  void  applyrules(Client *c)  { -	const char *appid, *title; -	unsigned int i, newtags = 0; -	const Rule *r; -	Monitor *mon = selmon, *m; -  	/* rule matching */ -	c->isfloating = 0; +	const char *appid, *title;  #ifdef XWAYLAND  	if (c->type != XDGShell) {  		updatewindowtype(c); @@ -465,6 +485,9 @@ applyrules(Client *c)  	if (!title)  		title = broken; +	unsigned int i, newtags = 0; +	const Rule *r; +	Monitor *mon = selmon, *m;  	for (r = rules; r < END(rules); r++) {  		if ((!r->title || strstr(title, r->title))  				&& (!r->id || strstr(appid, r->id))) { @@ -486,11 +509,11 @@ arrange(Monitor *m)  		m->lt[m->sellt]->arrange(m);  	else if (m->fullscreenclient)  		maximizeclient(m->fullscreenclient); -	/* XXX recheck pointer focus here... or in resize()? */ +	/* TODO recheck pointer focus here... or in resize()? */  }  void -arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, bool exclusive) +arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int exclusive)  {  	LayerSurface *layersurface;  	struct wlr_box full_area = m->m; @@ -498,22 +521,20 @@ arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, bool  	wl_list_for_each(layersurface, list, link) {  		struct wlr_layer_surface_v1 *wlr_layer_surface = layersurface->layer_surface;  		struct wlr_layer_surface_v1_state *state = &wlr_layer_surface->current; -		struct wlr_box bounds;  		struct wlr_box box = {  			.width = state->desired_width,  			.height = state->desired_height  		}; -		const uint32_t both_horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT -			| ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; -		const uint32_t both_vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP -			| ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;  		if (exclusive != (state->exclusive_zone > 0))  			continue; -		bounds = state->exclusive_zone == -1 ? full_area : *usable_area; +		struct wlr_box bounds = state->exclusive_zone == -1 ? +			full_area : *usable_area;  		// Horizontal axis +		const uint32_t both_horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT +			| ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;  		if ((state->anchor & both_horiz) && box.width == 0) {  			box.x = bounds.x;  			box.width = bounds.width; @@ -525,6 +546,8 @@ arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, bool  			box.x = bounds.x + ((bounds.width / 2) - (box.width / 2));  		}  		// Vertical axis +		const uint32_t both_vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP +			| ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;  		if ((state->anchor & both_vert) && box.height == 0) {  			box.y = bounds.y;  			box.height = bounds.height; @@ -569,23 +592,16 @@ void  arrangelayers(Monitor *m)  {  	struct wlr_box usable_area = m->m; -	uint32_t layers_above_shell[] = { -		ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, -		ZWLR_LAYER_SHELL_V1_LAYER_TOP, -	}; -	size_t nlayers = LENGTH(layers_above_shell); -	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, true); +			&usable_area, 1);  	arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], -			&usable_area, true); +			&usable_area, 1);  	arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], -			&usable_area, true); +			&usable_area, 1);  	arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], -			&usable_area, true); +			&usable_area, 1);  	if (memcmp(&usable_area, &m->w, sizeof(struct wlr_box))) {  		m->w = usable_area; @@ -594,20 +610,29 @@ arrangelayers(Monitor *m)  	// Arrange non-exlusive surfaces from top->bottom  	arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], -			&usable_area, false); +			&usable_area, 0);  	arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], -			&usable_area, false); +			&usable_area, 0);  	arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], -			&usable_area, false); +			&usable_area, 0);  	arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], -			&usable_area, false); +			&usable_area, 0);  	// Find topmost keyboard interactive layer, if such a layer exists +	uint32_t layers_above_shell[] = { +		ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, +		ZWLR_LAYER_SHELL_V1_LAYER_TOP, +	}; +	size_t nlayers = LENGTH(layers_above_shell); +	LayerSurface *layersurface; +	struct wlr_keyboard *kb = wlr_seat_get_keyboard(seat);  	for (size_t i = 0; i < nlayers; ++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. +				focusclient(NULL, 0);  				wlr_seat_keyboard_notify_enter(seat, layersurface->layer_surface->surface,  						kb->keycodes, kb->num_keycodes, &kb->modifiers);  				return; @@ -622,6 +647,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_event_pointer_axis *event = data; +	wlr_idle_notify_activity(idle, seat);  	/* Notify the client with pointer focus of the axis event. */  	wlr_seat_pointer_notify_axis(seat,  			event->time_msec, event->orientation, event->delta, @@ -632,19 +658,19 @@ void  buttonpress(struct wl_listener *listener, void *data)  {  	struct wlr_event_pointer_button *event = data; -	struct wlr_keyboard *keyboard; -	uint32_t mods; -	Client *c; -	const Button *b; + +	wlr_idle_notify_activity(idle, seat);  	switch (event->state) {  	case WLR_BUTTON_PRESSED:;  		/* Change focus if the button was _pressed_ over a client */ +		Client *c;  		if ((c = xytoclient(cursor->x, cursor->y))) -			focusclient(selclient(), c, 1); +			focusclient(c, 1); -		keyboard = wlr_seat_get_keyboard(seat); -		mods = wlr_keyboard_get_modifiers(keyboard); +		struct wlr_keyboard* keyboard = wlr_seat_get_keyboard(seat); +		uint32_t mods = wlr_keyboard_get_modifiers(keyboard); +		const Button *b;  		for (b = buttons; b < END(buttons); b++) {  			if (CLEANMASK(mods) == CLEANMASK(b->mod) &&  					event->button == b->button && b->func) { @@ -655,7 +681,7 @@ buttonpress(struct wl_listener *listener, void *data)  		break;  	case WLR_BUTTON_RELEASED:  		/* If you released any buttons, we exit interactive move/resize mode. */ -		/* XXX should reset to the pointer focus's current setcursor */ +		/* 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); @@ -699,6 +725,9 @@ cleanupkeyboard(struct wl_listener *listener, void *data)  	struct wlr_input_device *device = data;  	Keyboard *kb = device->data; +	wl_list_remove(&kb->link); +	wl_list_remove(&kb->modifiers.link); +	wl_list_remove(&kb->key.link);  	wl_list_remove(&kb->destroy.link);  	free(kb);  } @@ -710,9 +739,33 @@ cleanupmon(struct wl_listener *listener, void *data)  	Monitor *m = wlr_output->data;  	wl_list_remove(&m->destroy.link); +	wl_list_remove(&m->frame.link); +	wl_list_remove(&m->link); +	wlr_output_layout_remove(output_layout, m->wlr_output); +	updatemons(); + +	int nmons = wl_list_length(&mons), i = 0; +	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); +} -	updatemons(); +void +closemon(Monitor *m) +{ +	// move closed monitor's clients to the focused one +	Client *c; + +	wl_list_for_each(c, &clients, link) { +		if (c->isfloating && c->geom.x > m->m.width) +			resize(c, c->geom.x - m->w.width, c->geom.y, +				c->geom.width, c->geom.height, 0); +		if (c->mon == m) +			setmon(c, selmon, c->tags); +	}  }  void @@ -721,12 +774,11 @@ commitlayersurfacenotify(struct wl_listener *listener, void *data)  	LayerSurface *layersurface = wl_container_of(listener, layersurface, surface_commit);  	struct wlr_layer_surface_v1 *wlr_layer_surface = layersurface->layer_surface;  	struct wlr_output *wlr_output = wlr_layer_surface->output; -	Monitor *m;  	if (!wlr_output)  		return; -	m = wlr_output->data; +	Monitor *m = wlr_output->data;  	arrangelayers(m);  	if (layersurface->layer != wlr_layer_surface->current.layer) { @@ -750,16 +802,12 @@ commitnotify(struct wl_listener *listener, void *data)  void  createkeyboard(struct wlr_input_device *device)  { -	struct xkb_context *context; -	struct xkb_keymap *keymap; -	Keyboard *kb; - -	kb = device->data = calloc(1, sizeof(*kb)); +	Keyboard *kb = device->data = calloc(1, sizeof(*kb));  	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, +	struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); +	struct xkb_keymap *keymap = xkb_map_new_from_names(context, &xkb_rules,  		XKB_KEYMAP_COMPILE_NO_FLAGS);  	wlr_keyboard_set_keymap(device->keyboard, keymap); @@ -787,9 +835,6 @@ createmon(struct wl_listener *listener, void *data)  	/* This event is raised by the backend when a new output (aka a display or  	 * monitor) becomes available. */  	struct wlr_output *wlr_output = data; -	Monitor *m; -	const MonitorRule *r; -	size_t nlayers = LENGTH(m->layers);  	/* The mode is a tuple of (width, height, refresh rate), and each  	 * monitor supports only a specific set of modes. We just pick the @@ -798,49 +843,77 @@ createmon(struct wl_listener *listener, void *data)  	wlr_output_set_mode(wlr_output, wlr_output_preferred_mode(wlr_output));  	/* Allocates and configures monitor state using configured rules */ -	m = wlr_output->data = calloc(1, sizeof(*m)); +	Monitor *m = wlr_output->data = calloc(1, sizeof(*m));  	m->wlr_output = wlr_output;  	m->tagset[0] = m->tagset[1] = 1; -	for (r = monrules; r < END(monrules); r++) { +	m->position = -1; +	for (const MonitorRule *r = monrules; r < END(monrules); r++) {  		if (!r->name || strstr(wlr_output->name, r->name)) {  			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; +			m->lt[0] = r->lt; +			m->lt[1] = &layouts[LENGTH(layouts) > 1 && r->lt != &layouts[1]];  			wlr_output_set_transform(wlr_output, r->rr); +			m->position = r - monrules;  			break;  		}  	} +	wlr_output_enable_adaptive_sync(wlr_output, 1);  	/* Set up event listeners */  	m->frame.notify = rendermon;  	wl_signal_add(&wlr_output->events.frame, &m->frame);  	m->destroy.notify = cleanupmon;  	wl_signal_add(&wlr_output->events.destroy, &m->destroy); -	wl_list_insert(&mons, &m->link); +	Monitor *moni, *insertmon = NULL; +	int x = 0; +	wl_list_for_each(moni, &mons, link) +		if (m->position > moni->position) +			insertmon = moni; +	if (insertmon) { +		x = insertmon->w.x + insertmon->w.width; +		wl_list_insert(&insertmon->link, &m->link); +	} else { +		wl_list_insert(&mons, &m->link); +	}  	wlr_output_enable(wlr_output, 1);  	if (!wlr_output_commit(wlr_output))  		return; -	/* Adds this to the output layout. The add_auto function arranges outputs -	 * from left-to-right in the order they appear. A more sophisticated -	 * compositor would let the user configure the arrangement of outputs in the -	 * layout. +	/* Adds this to the output layout in the order it was configured in.  	 *  	 * The output layout utility automatically adds a wl_output global to the  	 * display, which Wayland clients can see to find out information about the  	 * output (such as DPI, scale factor, manufacturer, etc).  	 */ -	wlr_output_layout_add_auto(output_layout, wlr_output); +	wlr_output_layout_add(output_layout, wlr_output, x, 0); +	wl_list_for_each_reverse(moni, &mons, link) { +		/* All monitors to the right of the new one must be moved */ +		if (moni == m) +			break; +		wlr_output_layout_move(output_layout, moni->wlr_output, moni->w.x + m->wlr_output->width, 0); +	}  	sgeom = *wlr_output_layout_get_box(output_layout, NULL); +	size_t nlayers = LENGTH(m->layers);  	for (size_t i = 0; i < nlayers; ++i)  		wl_list_init(&m->layers[i]);  	/* When adding monitors, the geometries of all monitors must be updated */  	updatemons(); +	wl_list_for_each(m, &mons, link) { +		/* The first monitor in the list is the most recently added */ +		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; +	}  }  void @@ -853,6 +926,9 @@ createnotify(struct wl_listener *listener, void *data)  	if (xdg_surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL)  		return; +	wl_list_for_each(c, &clients, link) +		if (c->isfullscreen && VISIBLEON(c, c->mon)) +			setfullscreen(c, 0);  	/* Allocate a Client for this surface */  	c = xdg_surface->data = calloc(1, sizeof(*c)); @@ -866,7 +942,7 @@ createnotify(struct wl_listener *listener, void *data)  	/* Listen to the various events it can emit */  	c->commit.notify = commitnotify;  	wl_signal_add(&xdg_surface->surface->events.commit, &c->commit); -	c->map.notify = maprequest; +	c->map.notify = mapnotify;  	wl_signal_add(&xdg_surface->events.map, &c->map);  	c->unmap.notify = unmapnotify;  	wl_signal_add(&xdg_surface->events.unmap, &c->unmap); @@ -882,15 +958,12 @@ void  createlayersurface(struct wl_listener *listener, void *data)  {  	struct wlr_layer_surface_v1 *wlr_layer_surface = data; -	LayerSurface *layersurface; -	Monitor *m; -	struct wlr_layer_surface_v1_state old_state;  	if (!wlr_layer_surface->output) {  		wlr_layer_surface->output = selmon->wlr_output;  	} -	layersurface = calloc(1, sizeof(LayerSurface)); +	LayerSurface *layersurface = calloc(1, sizeof(LayerSurface));  	layersurface->surface_commit.notify = commitlayersurfacenotify;  	wl_signal_add(&wlr_layer_surface->surface->events.commit, @@ -905,14 +978,14 @@ createlayersurface(struct wl_listener *listener, void *data)  	layersurface->layer_surface = wlr_layer_surface;  	wlr_layer_surface->data = layersurface; -	m = wlr_layer_surface->output->data; +	Monitor *m = wlr_layer_surface->output->data;  	wl_list_insert(&m->layers[wlr_layer_surface->client_pending.layer],  			&layersurface->link);  	// Temporarily set the layer's current state to client_pending  	// so that we can easily arrange it -	old_state = wlr_layer_surface->current; +	struct wlr_layer_surface_v1_state old_state = wlr_layer_surface->current;  	wlr_layer_surface->current = wlr_layer_surface->client_pending;  	arrangelayers(m);  	wlr_layer_surface->current = old_state; @@ -968,7 +1041,6 @@ void  destroylayersurfacenotify(struct wl_listener *listener, void *data)  {  	LayerSurface *layersurface = wl_container_of(listener, layersurface, destroy); -	Monitor *m;  	if (layersurface->layer_surface->mapped)  		unmaplayersurface(layersurface); @@ -978,7 +1050,7 @@ destroylayersurfacenotify(struct wl_listener *listener, void *data)  	wl_list_remove(&layersurface->unmap.link);  	wl_list_remove(&layersurface->surface_commit.link);  	if (layersurface->layer_surface->output) { -		m = layersurface->layer_surface->output->data; +		Monitor *m = layersurface->layer_surface->output->data;  		if (m)  			arrangelayers(m);  		layersurface->layer_surface->output = NULL; @@ -1082,31 +1154,53 @@ dirtomon(int dir)  }  void -focusclient(Client *old, Client *c, int lift) +focusclient(Client *c, int lift)  { -	struct wlr_keyboard *kb = wlr_seat_get_keyboard(seat); -  	/* Raise client in stacking order if requested */  	if (c && lift) {  		wl_list_remove(&c->slink);  		wl_list_insert(&stack, &c->slink);  	} -	/* Nothing else to do? */ -	if (c == old) +	struct wlr_surface *old = seat->keyboard_state.focused_surface; + +	if (c && WLR_SURFACE(c) == old)  		return; +	/* Put the new client atop the focus stack and select its monitor */ +	if (c) { +		wl_list_remove(&c->flink); +		wl_list_insert(&fstack, &c->flink); +		selmon = c->mon; +	} +  	/* Deactivate old client if focus is changing */ -	if (c != old && old) { +	if (old && (!c || WLR_SURFACE(c) != old)) { +		if (wlr_surface_is_xdg_surface(old)) +			wlr_xdg_toplevel_set_activated( +					wlr_xdg_surface_from_wlr_surface(old), 0);  #ifdef XWAYLAND -		if (old->type != XDGShell) -			wlr_xwayland_surface_activate(old->surface.xwayland, 0); -		else +		else if (wlr_surface_is_xwayland_surface(old)) +			wlr_xwayland_surface_activate( +					wlr_xwayland_surface_from_wlr_surface(old), 0);  #endif -			wlr_xdg_toplevel_set_activated(old->surface.xdg, 0); +		/* If an overlay is focused, don't focus or activate the client, +		 * but only update its position in fstack to render its border with focuscolor +		 * and focus it after the overlay is closed. +		 * It's probably pointless to check if old is a layer surface +		 * since it can't be anything else at this point. */ +		else if (wlr_surface_is_layer_surface(old)) { +			struct wlr_layer_surface_v1 *wlr_layer_surface = +				wlr_layer_surface_v1_from_wlr_surface(old); + +			if (wlr_layer_surface->mapped && ( +						wlr_layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP || +						wlr_layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY +						)) +				return; +		}  	} -	/* Update wlroots' keyboard focus */  	if (!c) {  		/* With no client, all we have left is to clear focus */  		wlr_seat_keyboard_notify_clear_focus(seat); @@ -1114,14 +1208,9 @@ focusclient(Client *old, Client *c, int lift)  	}  	/* Have a client, so focus its top-level wlr_surface */ -	if (shouldfocusclients(c->mon)) -		wlr_seat_keyboard_notify_enter(seat, WLR_SURFACE(c), -				kb->keycodes, kb->num_keycodes, &kb->modifiers); - -	/* Put the new client atop the focus stack and select its monitor */ -	wl_list_remove(&c->flink); -	wl_list_insert(&fstack, &c->flink); -	selmon = c->mon; +	struct wlr_keyboard *kb = wlr_seat_get_keyboard(seat); +	wlr_seat_keyboard_notify_enter(seat, WLR_SURFACE(c), +			kb->keycodes, kb->num_keycodes, &kb->modifiers);  	/* Activate the new client */  #ifdef XWAYLAND @@ -1135,10 +1224,10 @@ focusclient(Client *old, Client *c, int lift)  void  focusmon(const Arg *arg)  { -	Client *sel = selclient(); - -	selmon = dirtomon(arg->i); -	focusclient(sel, focustop(selmon), 1); +	do +		selmon = dirtomon(arg->i); +	while (!selmon->wlr_output->enabled); +	focusclient(focustop(selmon), 1);  }  void @@ -1164,7 +1253,7 @@ focusstack(const Arg *arg)  		}  	}  	/* If only one client is visible on selmon, then c == sel */ -	focusclient(sel, c, 1); +	focusclient(c, 1);  }  Client * @@ -1198,7 +1287,6 @@ inputdevice(struct wl_listener *listener, void *data)  	/* This event is raised by the backend when a new input device becomes  	 * available. */  	struct wlr_input_device *device = data; -	uint32_t caps;  	switch (device->type) {  	case WLR_INPUT_DEVICE_KEYBOARD:  		createkeyboard(device); @@ -1207,14 +1295,14 @@ inputdevice(struct wl_listener *listener, void *data)  		createpointer(device);  		break;  	default: -		/* XXX handle other input device types */ +		/* TODO handle other input device types */  		break;  	}  	/* We need to let the wlr_seat know what our capabilities are, which is  	 * communiciated to the client. In dwl we always have a cursor, even if  	 * there are no pointer devices, so we always include that capability. */ -	/* XXX do we actually require a cursor? */ -	caps = WL_SEAT_CAPABILITY_POINTER; +	/* TODO do we actually require a cursor? */ +	uint32_t caps = WL_SEAT_CAPABILITY_POINTER;  	if (!wl_list_empty(&keyboards))  		caps |= WL_SEAT_CAPABILITY_KEYBOARD;  	wlr_seat_set_capabilities(seat, caps); @@ -1243,10 +1331,10 @@ keybinding(uint32_t mods, xkb_keysym_t sym)  void  keypress(struct wl_listener *listener, void *data)  { +	int i;  	/* This event is raised when a key is pressed or released. */  	Keyboard *kb = wl_container_of(listener, kb, key);  	struct wlr_event_keyboard_key *event = data; -	int i;  	/* Translate libinput keycode -> xkbcommon */  	uint32_t keycode = event->keycode + 8; @@ -1257,6 +1345,9 @@ keypress(struct wl_listener *listener, void *data)  	int handled = 0;  	uint32_t mods = wlr_keyboard_get_modifiers(kb->device->keyboard); + +	wlr_idle_notify_activity(idle, seat); +  	/* On _press_, attempt to process a compositor keybinding. */  	if (event->state == WL_KEYBOARD_KEY_STATE_PRESSED)  		for (i = 0; i < nsyms; i++) @@ -1312,7 +1403,7 @@ maplayersurfacenotify(struct wl_listener *listener, void *data)  }  void -maprequest(struct wl_listener *listener, void *data) +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), *oldfocus = selclient(); @@ -1350,7 +1441,7 @@ maprequest(struct wl_listener *listener, void *data)  	if (c->mon->fullscreenclient && c->mon->fullscreenclient == oldfocus  			&& !c->isfloating && c->mon->lt[c->mon->sellt]->arrange) {  		maximizeclient(c->mon->fullscreenclient); -		focusclient(c, c->mon->fullscreenclient, 1); +		focusclient(c->mon->fullscreenclient, 1);  		/* give the focus back the fullscreen client on that monitor if exists,  		 * is focused and the new client isn't floating */  	} @@ -1388,18 +1479,14 @@ motionabsolute(struct wl_listener *listener, void *data)  void  motionnotify(uint32_t time)  { -	double sx = 0, sy = 0; -	struct wlr_surface *surface = NULL; -	Client *c = NULL; -	struct timespec now; -	if (!time) { -		clock_gettime(CLOCK_MONOTONIC, &now); -		time = now.tv_sec * 1000 + now.tv_nsec / 1000000; -	} +	// time is 0 in internal calls meant to restore pointer focus. +	if (time) { +		wlr_idle_notify_activity(idle, seat); -	/* Update selmon (even while dragging a window) */ -	if (sloppyfocus) -		selmon = xytomon(cursor->x, cursor->y); +		/* Update selmon (even while dragging a window) */ +		if (sloppyfocus) +			selmon = xytomon(cursor->x, cursor->y); +	}  	/* If we are currently grabbing the mouse, handle and return */  	if (cursor_mode == CurMove) { @@ -1414,6 +1501,9 @@ motionnotify(uint32_t time)  		return;  	} +	struct wlr_surface *surface = NULL; +	double sx = 0, sy = 0; +	Client *c = NULL;  	if ((surface = xytolayersurface(&selmon->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY],  					cursor->x, cursor->y, &sx, &sy)))  		; @@ -1452,7 +1542,7 @@ 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) +	if (!surface && time)  		wlr_xcursor_manager_set_cursor_image(cursor_mgr,  				"left_ptr", cursor); @@ -1503,6 +1593,72 @@ moveresize(const Arg *arg)  }  void +outputmgrapply(struct wl_listener *listener, void *data) +{ +	struct wlr_output_configuration_v1 *config = data; +	outputmgrapplyortest(config, 0); +} + +void +outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test) +{ +	struct wlr_output_configuration_head_v1 *config_head; +	int ok = 1; + +	wl_list_for_each(config_head, &config->heads, link) { +		struct wlr_output *wlr_output = config_head->state.output; + +		wlr_output_enable(wlr_output, config_head->state.enabled); +		if (config_head->state.enabled) { +			if (config_head->state.mode) +				wlr_output_set_mode(wlr_output, config_head->state.mode); +			else +				wlr_output_set_custom_mode(wlr_output, +						config_head->state.custom_mode.width, +						config_head->state.custom_mode.height, +						config_head->state.custom_mode.refresh); + +			wlr_output_layout_move(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); +		} else if (wl_list_length(&mons) > 1) { +			Monitor *m; +			wl_list_for_each(m, &mons, link) { +				if (m->wlr_output->name == wlr_output->name) { +					// focus the left monitor (relative to the current focus) +					m->wlr_output->enabled = !m->wlr_output->enabled; +					Arg ar = {.i = -1}; +					focusmon(&ar); +					closemon(m); +					m->wlr_output->enabled = !m->wlr_output->enabled; +				} +			} +		} + +		if (test) { +			ok &= wlr_output_test(wlr_output); +			wlr_output_rollback(wlr_output); +		} else +			ok &= wlr_output_commit(wlr_output); +	} +	if (ok) { +		wlr_output_configuration_v1_send_succeeded(config); +		if (!test) +			updatemons(); +	} else +		wlr_output_configuration_v1_send_failed(config); +	wlr_output_configuration_v1_destroy(config); +} + +void +outputmgrtest(struct wl_listener *listener, void *data) +{ +	struct wlr_output_configuration_v1 *config = data; +	outputmgrapplyortest(config, 1); +} + +void  pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy,  		uint32_t time)  { @@ -1516,6 +1672,13 @@ pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy,  		return;  	} +	int internal_call = !time; +	if (!time) { +		struct timespec now; +		clock_gettime(CLOCK_MONOTONIC, &now); +		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); @@ -1534,8 +1697,8 @@ pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy,  		return;  #endif -	if (sloppyfocus) -		focusclient(selclient(), c, 0); +	if (sloppyfocus && !internal_call) +		focusclient(c, 0);  }  void @@ -1550,10 +1713,6 @@ 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 @@ -1568,14 +1727,17 @@ render(struct wlr_surface *surface, int sx, int sy, void *data)  	 * 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). */ +	double ox = 0, oy = 0;  	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; +	struct wlr_box obox = { +		.x = ox + rdata->x + sx, +		.y = oy + rdata->y + sy, +		.width = surface->current.width, +		.height = surface->current.height, +	};  	scalebox(&obox, output->scale);  	/* @@ -1589,7 +1751,9 @@ render(struct wlr_surface *surface, int sx, int sy, void *data)  	 * Naturally you can do this any way you like, for example to make a 3D  	 * compositor.  	 */ -	transform = wlr_output_transform_invert(surface->current.transform); +	float matrix[9]; +	enum wl_output_transform transform = wlr_output_transform_invert( +			surface->current.transform);  	wlr_matrix_project_box(matrix, &obox, transform, 0,  		output->transform_matrix); @@ -1662,13 +1826,14 @@ renderclients(Monitor *m, struct timespec *now)  void  renderlayer(struct wl_list *layer_surfaces, struct timespec *now)  { -	struct render_data rdata;  	LayerSurface *layersurface;  	wl_list_for_each(layersurface, layer_surfaces, link) { -		rdata.output = layersurface->layer_surface->output; -		rdata.when = now; -		rdata.x = layersurface->geo.x; -		rdata.y = layersurface->geo.y; +		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); @@ -1678,9 +1843,6 @@ renderlayer(struct wl_list *layer_surfaces, struct timespec *now)  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); @@ -1689,6 +1851,8 @@ rendermon(struct wl_listener *listener, void *data)  	clock_gettime(CLOCK_MONOTONIC, &now);  	/* Do not render if any XDG clients have an outstanding resize. */ +	Client *c; +	int render = 1;  	wl_list_for_each(c, &stack, slink) {  		if (c->resize) {  			wlr_surface_send_frame_done(WLR_SURFACE(c), &now); @@ -1738,11 +1902,11 @@ resize(Client *c, int x, int y, int w, int h, int interact)  	 * compositor, you'd wait for the client to prepare a buffer at  	 * the new size, then commit any movement that was prepared.  	 */ -	struct wlr_box *bbox = interact ? &sgeom : &c->mon->w;  	c->geom.x = x;  	c->geom.y = y;  	c->geom.width = w;  	c->geom.height = h; +	struct wlr_box *bbox = interact ? &sgeom : &c->mon->w;  	applybounds(c, bbox);  	/* wlroots makes this a no-op if size hasn't changed */  #ifdef XWAYLAND @@ -1759,8 +1923,6 @@ resize(Client *c, int x, int y, int w, int h, int interact)  void  run(char *startup_cmd)  { -	pid_t startup_pid = -1; -  	/* Add a Unix socket to the Wayland display. */  	const char *socket = wl_display_add_socket_auto(dpy);  	if (!socket) @@ -1775,7 +1937,7 @@ run(char *startup_cmd)  	 * cursor position, and set default cursor image */  	selmon = xytomon(cursor->x, cursor->y); -	/* XXX hack to get cursor to display in its initial location (100, 100) +	/* TODO hack to get cursor to display in its initial location (100, 100)  	 * instead of (0, 0) and then jumping.  still may not be fully  	 * initialized, as the image/coordinates are not transformed for the  	 * monitor when displayed here */ @@ -1785,8 +1947,10 @@ run(char *startup_cmd)  	/* Set the WAYLAND_DISPLAY environment variable to our socket and run the  	 * startup command if requested. */  	setenv("WAYLAND_DISPLAY", socket, 1); + +	pid_t startup_pid = -1;  	if (startup_cmd) { -		startup_pid = fork(); +		pid_t startup_pid = fork();  		if (startup_pid < 0)  			EBARF("startup: fork");  		if (startup_pid == 0) { @@ -1794,6 +1958,7 @@ run(char *startup_cmd)  			EBARF("startup: execl");  		}  	} +  	/* Run the Wayland event loop. This does not return until you exit the  	 * compositor. Starting the backend rigged up all of the necessary event  	 * loop configuration to listen to libinput events, DRM events, generate @@ -1830,7 +1995,7 @@ setcursor(struct wl_listener *listener, void *data)  	/* This event is raised by the seat when a client provides a cursor image */  	struct wlr_seat_pointer_request_set_cursor_event *event = data;  	/* If we're "grabbing" the cursor, don't use the client's image */ -	/* XXX still need to save the provided surface to restore later */ +	/* TODO still need to save the provided surface to restore later */  	if (cursor_mode != CurNormal)  		return;  	/* This can be sent by any client, so we check to make sure this one is @@ -1857,7 +2022,7 @@ setlayout(const Arg *arg)  		selmon->sellt ^= 1;  	if (arg && arg->v)  		selmon->lt[selmon->sellt] = (Layout *)arg->v; -	/* XXX change layout symbol? */ +	/* TODO change layout symbol? */  	arrange(selmon);  } @@ -1865,11 +2030,9 @@ setlayout(const Arg *arg)  void  setmfact(const Arg *arg)  { -	float f; -  	if (!arg || !selmon->lt[selmon->sellt]->arrange)  		return; -	f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; +	float f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0;  	if (f < 0.1 || f > 0.9)  		return;  	selmon->mfact = f; @@ -1880,13 +2043,12 @@ void  setmon(Client *c, Monitor *m, unsigned int newtags)  {  	Monitor *oldmon = c->mon; -	Client *oldsel = selclient();  	if (oldmon == m)  		return;  	c->mon = m; -	/* XXX leave/enter is not optimal but works */ +	/* TODO leave/enter is not optimal but works */  	if (oldmon) {  		wlr_surface_send_leave(WLR_SURFACE(c), oldmon->wlr_output);  		arrange(oldmon); @@ -1898,7 +2060,7 @@ setmon(Client *c, Monitor *m, unsigned int newtags)  		c->tags = newtags ? newtags : m->tagset[m->seltags]; /* assign tags of target monitor */  		arrange(m);  	} -	focusclient(oldsel, focustop(selmon), 1); +	focusclient(focustop(selmon), 1);  }  void @@ -1959,6 +2121,7 @@ setup(void)  	compositor = wlr_compositor_create(dpy, 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); @@ -1985,6 +2148,8 @@ setup(void)  	wl_list_init(&stack);  	wl_list_init(&independents); +	idle = wlr_idle_create(dpy); +  	layer_shell = wlr_layer_shell_v1_create(dpy);  	wl_signal_add(&layer_shell->events.new_surface, &new_layer_shell_surface); @@ -2035,6 +2200,9 @@ setup(void)  	 */  	wl_list_init(&keyboards);  	wl_signal_add(&backend->events.new_input, &new_input); +	virtual_keyboard_mgr = wlr_virtual_keyboard_manager_v1_create(dpy); +	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); @@ -2043,12 +2211,16 @@ setup(void)  	wl_signal_add(&seat->events.request_set_primary_selection,  			&request_set_psel); +	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); +  #ifdef XWAYLAND  	/*  	 * Initialise the XWayland X server.  	 * It will be started when the first X client is started.  	 */ -	xwayland = wlr_xwayland_create(dpy, compositor, true); +	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); @@ -2067,7 +2239,7 @@ setup(void)  					xcursor->images[0]->hotspot_x, xcursor->images[0]->hotspot_y);  		} -		setenv("DISPLAY", xwayland->display_name, true); +		setenv("DISPLAY", xwayland->display_name, 1);  	} else {  		fprintf(stderr, "failed to setup XWayland X server, continuing without it\n");  	} @@ -2083,22 +2255,6 @@ sigchld(int unused)  		;  } -bool -shouldfocusclients(Monitor *m) -{ -	LayerSurface *layersurface; -	uint32_t layers_above_shell[] = { -		ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, -		ZWLR_LAYER_SHELL_V1_LAYER_TOP, -	}; -	for (size_t i = 0; i < LENGTH(layers_above_shell); ++i) -		wl_list_for_each(layersurface, &m->layers[layers_above_shell[i]], link) -			if (layersurface->layer_surface->current.keyboard_interactive && -					layersurface->layer_surface->mapped) -				return false; -	return true; -} -  void  spawn(const Arg *arg)  { @@ -2115,7 +2271,7 @@ tag(const Arg *arg)  	Client *sel = selclient();  	if (sel && arg->ui & TAGMASK) {  		sel->tags = arg->ui & TAGMASK; -		focusclient(sel, focustop(selmon), 1); +		focusclient(focustop(selmon), 1);  		arrange(selmon);  	}  } @@ -2177,14 +2333,13 @@ togglefloating(const Arg *arg)  void  toggletag(const Arg *arg)  { -	unsigned int newtags;  	Client *sel = selclient();  	if (!sel)  		return; -	newtags = sel->tags ^ (arg->ui & TAGMASK); +	unsigned int newtags = sel->tags ^ (arg->ui & TAGMASK);  	if (newtags) {  		sel->tags = newtags; -		focusclient(sel, focustop(selmon), 1); +		focusclient(focustop(selmon), 1);  		arrange(selmon);  	}  } @@ -2192,12 +2347,11 @@ toggletag(const Arg *arg)  void  toggleview(const Arg *arg)  { -	Client *sel = selclient();  	unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK);  	if (newtagset) {  		selmon->tagset[selmon->seltags] = newtagset; -		focusclient(sel, focustop(selmon), 1); +		focusclient(focustop(selmon), 1);  		arrange(selmon);  	}  } @@ -2205,10 +2359,10 @@ toggleview(const Arg *arg)  void  unmaplayersurface(LayerSurface *layersurface)  { -	layersurface->layer_surface->mapped = false; +	layersurface->layer_surface->mapped = 0;  	if (layersurface->layer_surface->surface ==  			seat->keyboard_state.focused_surface) -		focusclient(NULL, selclient(), 1); +		focusclient(selclient(), 1);  	motionnotify(0);  } @@ -2237,30 +2391,50 @@ unmapnotify(struct wl_listener *listener, void *data)  void  updatemons()  { +	struct wlr_output_configuration_v1 *config = +		wlr_output_configuration_v1_create();  	Monitor *m; +	sgeom = *wlr_output_layout_get_box(output_layout, NULL);  	wl_list_for_each(m, &mons, link) { +		struct wlr_output_configuration_head_v1 *config_head = +			wlr_output_configuration_head_v1_create(config, m->wlr_output); +  		/* Get the effective monitor geometry to use for surfaces */  		m->m = m->w = *wlr_output_layout_get_box(output_layout, m->wlr_output);  		/* Calculate the effective monitor geometry to use for clients */  		arrangelayers(m);  		/* Don't move clients to the left output when plugging monitors */  		arrange(m); + +		config_head->state.enabled = m->wlr_output->enabled; +		config_head->state.mode = m->wlr_output->current_mode; +		config_head->state.x = m->m.x; +		config_head->state.y = m->m.y;  	} + +	wlr_output_manager_v1_set_configuration(output_mgr, config);  }  void  view(const Arg *arg)  { -	Client *sel = selclient();  	if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])  		return;  	selmon->seltags ^= 1; /* toggle sel tagset */  	if (arg->ui & TAGMASK)  		selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; -	focusclient(sel, focustop(selmon), 1); +	focusclient(focustop(selmon), 1);  	arrange(selmon);  } +void +virtualkeyboard(struct wl_listener *listener, void *data) +{ +	struct wlr_virtual_keyboard_v1 *keyboard = data; +	struct wlr_input_device *device = &keyboard->input_device; +	createkeyboard(device); +} +  Client *  xytoclient(double x, double y)  { @@ -2304,7 +2478,7 @@ xytomon(double x, double y)  void  zoom(const Arg *arg)  { -	Client *c, *sel = selclient(), *oldsel = sel; +	Client *c, *sel = selclient();  	if (!sel || !selmon->lt[selmon->sellt]->arrange || sel->isfloating)  		return; @@ -2329,7 +2503,7 @@ zoom(const Arg *arg)  	wl_list_remove(&sel->link);  	wl_list_insert(&clients, &sel->link); -	focusclient(oldsel, sel, 1); +	focusclient(sel, 1);  	arrange(selmon);  } @@ -2345,24 +2519,38 @@ activatex11(struct wl_listener *listener, void *data)  }  void +configurex11(struct wl_listener *listener, void *data) +{ +	Client *c = wl_container_of(listener, c, configure); +	struct wlr_xwayland_surface_configure_event *event = data; +	wlr_xwayland_surface_configure(c->surface.xwayland, +			event->x, event->y, event->width, event->height); +} + +void  createnotifyx11(struct wl_listener *listener, void *data)  { -	struct wlr_xwayland_surface *xwayland_surface = data;  	Client *c; +	wl_list_for_each(c, &clients, link) +		if (c->isfullscreen && VISIBLEON(c, c->mon)) +			setfullscreen(c, 0);  	/* Allocate a Client for this surface */ +	struct wlr_xwayland_surface *xwayland_surface = data;  	c = xwayland_surface->data = calloc(1, sizeof(*c));  	c->surface.xwayland = xwayland_surface;  	c->type = xwayland_surface->override_redirect ? X11Unmanaged : X11Managed;  	c->bw = borderpx;  	/* Listen to the various events it can emit */ -	c->map.notify = maprequest; +	c->map.notify = mapnotify;  	wl_signal_add(&xwayland_surface->events.map, &c->map);  	c->unmap.notify = unmapnotify;  	wl_signal_add(&xwayland_surface->events.unmap, &c->unmap);  	c->activate.notify = activatex11;  	wl_signal_add(&xwayland_surface->events.request_activate, &c->activate); +	c->configure.notify = configurex11; +	wl_signal_add(&xwayland_surface->events.request_configure, &c->configure);  	c->destroy.notify = destroynotify;  	wl_signal_add(&xwayland_surface->events.destroy, &c->destroy); @@ -2375,10 +2563,8 @@ Atom  getatom(xcb_connection_t *xc, const char *name)  {  	Atom atom = 0; -	xcb_intern_atom_cookie_t cookie;  	xcb_intern_atom_reply_t *reply; - -	cookie = xcb_intern_atom(xc, 0, strlen(name), name); +	xcb_intern_atom_cookie_t cookie = xcb_intern_atom(xc, 0, strlen(name), name);  	if ((reply = xcb_intern_atom_reply(xc, cookie, NULL)))  		atom = reply->atom;  	free(reply); @@ -2390,23 +2576,25 @@ 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; +		struct wlr_box geom = { +			.x = c->surface.xwayland->x, +			.y = c->surface.xwayland->y, +			.width = c->surface.xwayland->width, +			.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; +		struct render_data rdata = { +			.output = output, +			.when = now, +			.x = c->surface.xwayland->x, +			.y = c->surface.xwayland->y, +		};  		wlr_surface_for_each_surface(c->surface.xwayland->surface, render, &rdata);  	} @@ -2415,8 +2603,7 @@ renderindependents(struct wlr_output *output, struct timespec *now)  void  updatewindowtype(Client *c)  { -	size_t i; -	for (i = 0; i < c->surface.xwayland->window_type_len; i++) +	for (size_t i = 0; i < c->surface.xwayland->window_type_len; i++)  		if (c->surface.xwayland->window_type[i] == netatom[NetWMWindowTypeDialog] ||  				c->surface.xwayland->window_type[i] == netatom[NetWMWindowTypeSplash] ||  				c->surface.xwayland->window_type[i] == netatom[NetWMWindowTypeToolbar] || @@ -2444,6 +2631,13 @@ xwaylandready(struct wl_listener *listener, void *data)  	/* assign the one and only seat */  	wlr_xwayland_set_seat(xwayland, seat); +	/* Set the default XWayland cursor to match the rest of dwl. */ +	struct wlr_xcursor *xcursor = wlr_xcursor_manager_get_xcursor(cursor_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); +  	xcb_disconnect(xc);  } @@ -2456,12 +2650,13 @@ xytoindependent(double x, double y)  	 * client loses focus, which ensures that unmanaged are only visible on  	 * the current tag. */  	Client *c; -	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; +		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;  	} | 
