diff options
Diffstat (limited to 'dwl.c')
| -rw-r--r-- | dwl.c | 195 | 
1 files changed, 114 insertions, 81 deletions
| @@ -73,7 +73,7 @@  /* enums */  enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */  enum { XDGShell, LayerShell, X11Managed, X11Unmanaged }; /* client types */ -enum { LyrBg, LyrBottom, LyrTop, LyrOverlay, LyrTile, LyrFloat, LyrNoFocus, NUM_LAYERS }; /* scene layers */ +enum { LyrBg, LyrBottom, LyrTop, LyrOverlay, LyrTile, LyrFloat, LyrDragIcon, NUM_LAYERS }; /* scene layers */  #ifdef XWAYLAND  enum { NetWMWindowTypeDialog, NetWMWindowTypeSplash, NetWMWindowTypeToolbar,  	NetWMWindowTypeUtility, NetLast }; /* EWMH atoms */ @@ -225,11 +225,11 @@ static void createmon(struct wl_listener *listener, void *data);  static void createnotify(struct wl_listener *listener, void *data);  static void createpointer(struct wlr_pointer *pointer);  static void cursorframe(struct wl_listener *listener, void *data); +static void destroydragicon(struct wl_listener *listener, void *data);  static void destroyidleinhibitor(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); @@ -337,6 +337,7 @@ static struct wl_listener cursor_button = {.notify = buttonpress};  static struct wl_listener cursor_frame = {.notify = cursorframe};  static struct wl_listener cursor_motion = {.notify = motionrelative};  static struct wl_listener cursor_motion_absolute = {.notify = motionabsolute}; +static struct wl_listener drag_icon_destroy = {.notify = destroydragicon};  static struct wl_listener idle_inhibitor_create = {.notify = createidleinhibitor};  static struct wl_listener idle_inhibitor_destroy = {.notify = destroyidleinhibitor};  static struct wl_listener layout_change = {.notify = updatemons}; @@ -353,7 +354,6 @@ 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); @@ -390,9 +390,9 @@ applybounds(Client *c, struct wlr_box *bbox)  		c->geom.height = MAX(min.height + (2 * c->bw), c->geom.height);  		/* Some clients set them max size to INT_MAX, which does not violates  		 * the protocol but its innecesary, they can set them max size to zero. */ -		if (max.width > 0 && !(2 * c->bw > INT_MAX - max.width)) // Checks for overflow +		if (max.width > 0 && !(2 * c->bw > INT_MAX - max.width)) /* Checks for overflow */  			c->geom.width = MIN(max.width + (2 * c->bw), c->geom.width); -		if (max.height > 0 && !(2 * c->bw > INT_MAX - max.height)) // Checks for overflow +		if (max.height > 0 && !(2 * c->bw > INT_MAX - max.height)) /* Checks for overflow */  			c->geom.height = MIN(max.height + (2 * c->bw), c->geom.height);  	} @@ -538,8 +538,7 @@ buttonpress(struct wl_listener *listener, void *data)  	case WLR_BUTTON_PRESSED:  		/* Change focus if the button was _pressed_ over a client */  		xytonode(cursor->x, cursor->y, NULL, &c, NULL, NULL, NULL); -		/* Don't focus unmanaged clients */ -		if (c && !client_is_unmanaged(c)) +		if (c && (!client_is_unmanaged(c) || client_wants_focus(c)))  			focusclient(c, 1);  		keyboard = wlr_seat_get_keyboard(seat); @@ -642,7 +641,15 @@ void  cleanupmon(struct wl_listener *listener, void *data)  {  	Monitor *m = wl_container_of(listener, m, destroy); -	int nmons, i = 0; +	LayerSurface *l, *tmp; +	int i; + +	for (i = 0; i <= ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY; i++) { +		wl_list_for_each_safe(l, tmp, &m->layers[i], link) { +			wlr_scene_node_set_enabled(&l->scene->node, 0); +			wlr_layer_surface_v1_destroy(l->layer_surface); +		} +	}  	wl_list_remove(&m->destroy.link);  	wl_list_remove(&m->frame.link); @@ -651,12 +658,6 @@ cleanupmon(struct wl_listener *listener, void *data)  	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); - -	focusclient(focustop(selmon), 1);  	closemon(m);  	free(m);  } @@ -664,16 +665,26 @@ cleanupmon(struct wl_listener *listener, void *data)  void  closemon(Monitor *m)  { -	/* move closed monitor's clients to the focused one */ +	/* update selmon if needed and +	 * move closed monitor's clients to the focused one */  	Client *c; +	if (wl_list_empty(&mons)) { +		selmon = NULL; +	} else if (m == selmon) { +		int nmons = wl_list_length(&mons), i = 0; +		do /* don't switch to disabled mons */ +			selmon = wl_container_of(mons.next, selmon, link); +		while (!selmon->wlr_output->enabled && i++ < nmons); +	}  	wl_list_for_each(c, &clients, link) {  		if (c->isfloating && c->geom.x > m->m.width)  			resize(c, (struct wlr_box){.x = c->geom.x - m->w.width, .y = c->geom.y,  				.width = c->geom.width, .height = c->geom.height}, 0);  		if (c->mon == m) -			setmon(c, selmon == m ? NULL : selmon, c->tags); +			setmon(c, selmon, c->tags);  	} +	focusclient(focustop(selmon), 1);  	printstatus();  } @@ -947,8 +958,8 @@ createpointer(struct wlr_pointer *pointer)  		if (libinput_device_config_scroll_get_methods(libinput_device) != LIBINPUT_CONFIG_SCROLL_NO_SCROLL)  			libinput_device_config_scroll_set_method (libinput_device, scroll_method); -		 if (libinput_device_config_click_get_methods(libinput_device) != LIBINPUT_CONFIG_CLICK_METHOD_NONE) -                        libinput_device_config_click_set_method (libinput_device, click_method); +		if (libinput_device_config_click_get_methods(libinput_device) != LIBINPUT_CONFIG_CLICK_METHOD_NONE) +			libinput_device_config_click_set_method (libinput_device, click_method);  		if (libinput_device_config_send_events_get_modes(libinput_device))  			libinput_device_config_send_events_set_mode(libinput_device, send_events_mode); @@ -974,6 +985,16 @@ cursorframe(struct wl_listener *listener, void *data)  }  void +destroydragicon(struct wl_listener *listener, void *data) +{ +	struct wlr_drag_icon *icon = data; +	wlr_scene_node_destroy(icon->data); +	/* Focus enter isn't sent during drag, so refocus the focused node. */ +	focusclient(selclient(), 1); +	motionnotify(0); +} + +void  destroyidleinhibitor(struct wl_listener *listener, void *data)  {  	/* `data` is the wlr_surface of the idle inhibitor being destroyed, @@ -1019,10 +1040,12 @@ Monitor *  dirtomon(enum wlr_direction dir)  {  	struct wlr_output *next; -	if ((next = wlr_output_layout_adjacent_output(output_layout, +	if (wlr_output_layout_get(output_layout, selmon->wlr_output) +			&& (next = wlr_output_layout_adjacent_output(output_layout,  			dir, selmon->wlr_output, selmon->m.x, selmon->m.y)))  		return next->data; -	if ((next = wlr_output_layout_farthest_output(output_layout, +	if (wlr_output_layout_get(output_layout, selmon->wlr_output) +			&& (next = wlr_output_layout_farthest_output(output_layout,  			dir ^ (WLR_DIRECTION_LEFT|WLR_DIRECTION_RIGHT),  			selmon->wlr_output, selmon->m.x, selmon->m.y)))  		return next->data; @@ -1030,16 +1053,6 @@ dirtomon(enum wlr_direction dir)  }  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  focusclient(Client *c, int lift)  {  	struct wlr_surface *old = seat->keyboard_state.focused_surface; @@ -1053,15 +1066,14 @@ focusclient(Client *c, int lift)  		return;  	/* Put the new client atop the focus stack and select its monitor */ -	if (c) { +	if (c && !client_is_unmanaged(c)) {  		wl_list_remove(&c->flink);  		wl_list_insert(&fstack, &c->flink);  		selmon = c->mon;  		c->isurgent = 0;  		client_restack_surface(c); -		/* Don't change border color if there is a exclusive focus -		 * (at this moment it means that a layer surface is focused) */ +		/* Don't change border color if there is an exclusive focus */  		if (!exclusive_focus)  			for (i = 0; i < 4; i++)  				wlr_scene_rect_set_color(c->border[i], focuscolor); @@ -1072,6 +1084,7 @@ focusclient(Client *c, int lift)  		/* 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. */ +		Client *w = client_from_wlr_surface(old);  		if (wlr_surface_is_layer_surface(old)) {  			struct wlr_layer_surface_v1 *wlr_layer_surface =  				wlr_layer_surface_v1_from_wlr_surface(old); @@ -1080,11 +1093,13 @@ focusclient(Client *c, int lift)  					&& (wlr_layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP  					|| wlr_layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY))  				return; -		} else { -			Client *w; -			if ((w = client_from_wlr_surface(old))) -				for (i = 0; i < 4; i++) -					wlr_scene_rect_set_color(w->border[i], bordercolor); +		} else if (w && w == exclusive_focus && client_wants_focus(w)) { +			return; +		/* Don't deactivate old client if the new one wants focus, as this causes issues with winecfg +		 * and probably other clients */ +		} else if (w && !client_is_unmanaged(w) && (!c || !client_wants_focus(c))) { +			for (i = 0; i < 4; i++) +				wlr_scene_rect_set_color(w->border[i], bordercolor);  			client_activate_surface(old, 0);  		} @@ -1322,6 +1337,10 @@ mapnotify(struct wl_listener *listener, void *data)  		wlr_scene_node_reparent(&c->scene->node, layers[LyrFloat]);  		wlr_scene_node_set_position(&c->scene->node, c->geom.x + borderpx,  			c->geom.y + borderpx); +		if (client_wants_focus(c)) { +			focusclient(c, 1); +			exclusive_focus = c; +		}  		return;  	}  #endif @@ -1380,7 +1399,8 @@ monocle(Monitor *m)  			continue;  		resize(c, m->w, 0);  	} -	focusclient(focustop(m), 1); +	if ((c = focustop(m))) +		wlr_scene_node_raise_to_top(&c->scene->node);  }  void @@ -1402,6 +1422,7 @@ motionnotify(uint32_t time)  {  	double sx = 0, sy = 0;  	Client *c = NULL; +	LayerSurface *l;  	struct wlr_surface *surface = NULL;  	struct wlr_drag_icon *icon; @@ -1433,17 +1454,19 @@ motionnotify(uint32_t time)  	/* Find the client under the pointer and send the event along. */  	xytonode(cursor->x, cursor->y, &surface, &c, NULL, &sx, &sy); -	if (cursor_mode == CurPressed) { -		surface = seat->pointer_state.focused_surface; -		c = client_from_wlr_surface(surface); -		sx = c ? cursor->x - c->geom.x : 0; -		sy = c ? cursor->y - c->geom.y : 0; +	if (cursor_mode == CurPressed && !seat->drag) { +		if ((l = toplevel_from_wlr_layer_surface( +				 seat->pointer_state.focused_surface))) { +			surface = seat->pointer_state.focused_surface; +			sx = cursor->x - l->geom.x; +			sy = cursor->y - l->geom.y; +		}  	}  	/* 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 && (!cursor_image || strcmp(cursor_image, "left_ptr"))) +	if (!surface && !seat->drag && (!cursor_image || strcmp(cursor_image, "left_ptr")))  		wlr_xcursor_manager_set_cursor_image(cursor_mgr, (cursor_image = "left_ptr"), cursor);  	pointerfocus(c, surface, sx, sy, time); @@ -1467,7 +1490,7 @@ motionrelative(struct wl_listener *listener, void *data)  void  moveresize(const Arg *arg)  { -	if (cursor_mode != CurNormal) +	if (cursor_mode != CurNormal && cursor_mode != CurPressed)  		return;  	xytonode(cursor->x, cursor->y, NULL, &grabc, NULL, NULL, NULL);  	if (!grabc || client_is_unmanaged(grabc)) @@ -1512,28 +1535,13 @@ outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test)  	struct wlr_output_configuration_head_v1 *config_head;  	int ok = 1; -	/* First disable outputs we need to disable */ -	wl_list_for_each(config_head, &config->heads, link) { -		struct wlr_output *wlr_output = config_head->state.output; -		if (!wlr_output->enabled || config_head->state.enabled) -			continue; -		wlr_output_enable(wlr_output, 0); -		if (test) { -			ok &= wlr_output_test(wlr_output); -			wlr_output_rollback(wlr_output); -		} else { -			ok &= wlr_output_commit(wlr_output); -		} -	} - -	/* Then enable outputs that need to */  	wl_list_for_each(config_head, &config->heads, link) {  		struct wlr_output *wlr_output = config_head->state.output;  		Monitor *m = wlr_output->data; -		if (!config_head->state.enabled) -			continue; -		wlr_output_enable(wlr_output, 1); +		wlr_output_enable(wlr_output, config_head->state.enabled); +		if (!config_head->state.enabled) +			goto apply_or_test;  		if (config_head->state.mode)  			wlr_output_set_mode(wlr_output, config_head->state.mode);  		else @@ -1550,6 +1558,7 @@ outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test)  		wlr_output_set_transform(wlr_output, config_head->state.transform);  		wlr_output_set_scale(wlr_output, config_head->state.scale); +apply_or_test:  		if (test) {  			ok &= wlr_output_test(wlr_output);  			wlr_output_rollback(wlr_output); @@ -1559,7 +1568,7 @@ outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test)  			 * we test if that mode does not fail rather than just call wlr_output_commit().  			 * We do not test normal modes because (at least in my hardware (@sevz17))  			 * wlr_output_test() fails even if that mode can actually be set */ -			if (!config_head->state.mode) +			if (!config_head->state.mode && config_head->state.enabled)  				ok &= (output_ok = wlr_output_test(wlr_output)  						&& wlr_output_commit(wlr_output));  			else @@ -1579,6 +1588,9 @@ outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test)  	else  		wlr_output_configuration_v1_send_failed(config);  	wlr_output_configuration_v1_destroy(config); + +	/* TODO: use a wrapper function? */ +	updatemons(NULL, NULL);  }  void @@ -1805,7 +1817,7 @@ setcursor(struct wl_listener *listener, void *data)  	/* If we're "grabbing" the cursor, don't use the client's image, we will  	 * restore it after "grabbing" sending a leave event, followed by a enter  	 * event, which will result in the client requesting set the cursor surface */ -	if (cursor_mode != CurNormal) +	if (cursor_mode != CurNormal && cursor_mode != CurPressed)  		return;  	cursor_image = NULL;  	/* This can be sent by any client, so we check to make sure this one is @@ -1980,7 +1992,7 @@ setup(void)  	layers[LyrFloat] = wlr_scene_tree_create(&scene->tree);  	layers[LyrTop] = wlr_scene_tree_create(&scene->tree);  	layers[LyrOverlay] = wlr_scene_tree_create(&scene->tree); -	layers[LyrNoFocus] = wlr_scene_tree_create(&scene->tree); +	layers[LyrDragIcon] = wlr_scene_tree_create(&scene->tree);  	/* Create a renderer with the default implementation */  	if (!(drw = wlr_renderer_autocreate(backend))) @@ -2143,7 +2155,7 @@ startdrag(struct wl_listener *listener, void *data)  	if (!drag->icon)  		return; -	drag->icon->data = wlr_scene_subsurface_tree_create(layers[LyrNoFocus], drag->icon->surface); +	drag->icon->data = wlr_scene_subsurface_tree_create(layers[LyrDragIcon], drag->icon->surface);  	motionnotify(0);  	wl_signal_add(&drag->icon->events.destroy, &drag_icon_destroy);  } @@ -2278,14 +2290,17 @@ unmapnotify(struct wl_listener *listener, void *data)  	if (c->mon)  		c->mon->un_map = 1; -	if (client_is_unmanaged(c)) -		goto end; - -	wl_list_remove(&c->link); -	setmon(c, NULL, 0); -	wl_list_remove(&c->flink); +	if (client_is_unmanaged(c)) { +		if (c == exclusive_focus) +			exclusive_focus = NULL; +		if (client_surface(c) == seat->keyboard_state.focused_surface) +			focusclient(selclient(), 1); +	} else { +		wl_list_remove(&c->link); +		setmon(c, NULL, 0); +		wl_list_remove(&c->flink); +	} -end:  	wl_list_remove(&c->commit.link);  	wlr_scene_node_destroy(&c->scene->node);  	printstatus(); @@ -2305,14 +2320,32 @@ updatemons(struct wl_listener *listener, void *data)  	struct wlr_output_configuration_v1 *config =  		wlr_output_configuration_v1_create();  	Client *c; +	struct wlr_output_configuration_head_v1 *config_head;  	Monitor *m; + +	/* First remove from the layout the disabled monitors */ +	wl_list_for_each(m, &mons, link) { +		if (m->wlr_output->enabled) +			continue; +		config_head = wlr_output_configuration_head_v1_create(config, m->wlr_output); +		config_head->state.enabled = 0; +		/* Remove this output from the layout to avoid cursor enter inside it */ +		wlr_output_layout_remove(output_layout, m->wlr_output); +		closemon(m); +		memset(&m->m, 0, sizeof(m->m)); +		memset(&m->w, 0, sizeof(m->w)); +	} +	/* Insert outputs that need to */ +	wl_list_for_each(m, &mons, link) +		if (m->wlr_output->enabled +				&& !wlr_output_layout_get(output_layout, m->wlr_output)) +			wlr_output_layout_add_auto(output_layout, m->wlr_output); +	/* Now that we update the output layout we can get its box */  	wlr_output_layout_get_box(output_layout, NULL, &sgeom);  	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); - -		/* TODO: move clients off disabled monitors */ -		/* TODO: move focus if selmon is disabled */ +		if (!m->wlr_output->enabled) +			continue; +		config_head = wlr_output_configuration_head_v1_create(config, m->wlr_output);  		/* Get the effective monitor geometry to use for surfaces */  		wlr_output_layout_get_box(output_layout, m->wlr_output, &(m->m)); @@ -2323,7 +2356,7 @@ updatemons(struct wl_listener *listener, void *data)  		/* Don't move clients to the left output when plugging monitors */  		arrange(m); -		config_head->state.enabled = m->wlr_output->enabled; +		config_head->state.enabled = 1;  		config_head->state.mode = m->wlr_output->current_mode;  		config_head->state.x = m->m.x;  		config_head->state.y = m->m.y; | 
