mirror of
				https://github.com/swaywm/sway.git
				synced 2025-11-03 09:01:43 -05:00 
			
		
		
		
	Fix issues with sticky containers and workspaces
* Attach sticky containers to new workspaces when switching * Fire the close event *before* we start destroying the workspace to prevent a crash Because the sticky container now follows the visible workspace, this simplifies the rendering and container_at logic.
This commit is contained in:
		
							parent
							
								
									13a4b0512e
								
							
						
					
					
						commit
						dc83b158e1
					
				
					 3 changed files with 54 additions and 33 deletions
				
			
		| 
						 | 
				
			
			@ -832,12 +832,13 @@ static void render_floating(struct sway_output *soutput,
 | 
			
		|||
		for (int j = 0; j < output->children->length; ++j) {
 | 
			
		||||
			struct sway_container *workspace = output->children->items[j];
 | 
			
		||||
			struct sway_workspace *ws = workspace->sway_workspace;
 | 
			
		||||
			bool ws_is_visible = workspace_is_visible(workspace);
 | 
			
		||||
			if (!workspace_is_visible(workspace)) {
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			for (int k = 0; k < ws->floating->children->length; ++k) {
 | 
			
		||||
				struct sway_container *floater =
 | 
			
		||||
					ws->floating->children->items[k];
 | 
			
		||||
				if ((ws_is_visible || floater->is_sticky)
 | 
			
		||||
						&& floater_intersects_output(floater, soutput->swayc)) {
 | 
			
		||||
				if (floater_intersects_output(floater, soutput->swayc)) {
 | 
			
		||||
					render_floating_container(soutput, damage, floater);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -64,16 +64,6 @@ void container_create_notify(struct sway_container *container) {
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void container_close_notify(struct sway_container *container) {
 | 
			
		||||
	if (container == NULL) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	// TODO send ipc event type based on the container type
 | 
			
		||||
	if (container->type == C_VIEW || container->type == C_WORKSPACE) {
 | 
			
		||||
		ipc_event_window(container, "close");
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void container_update_textures_recursive(struct sway_container *con) {
 | 
			
		||||
	container_update_title_textures(con);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -143,7 +133,6 @@ static void _container_destroy(struct sway_container *cont) {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	wl_signal_emit(&cont->events.destroy, cont);
 | 
			
		||||
	container_close_notify(cont);
 | 
			
		||||
 | 
			
		||||
	struct sway_container *parent = cont->parent;
 | 
			
		||||
	if (cont->children != NULL && cont->children->length) {
 | 
			
		||||
| 
						 | 
				
			
			@ -151,6 +140,7 @@ static void _container_destroy(struct sway_container *cont) {
 | 
			
		|||
		// container_remove_child, which removes child from this container
 | 
			
		||||
		while (cont->children != NULL && cont->children->length > 0) {
 | 
			
		||||
			struct sway_container *child = cont->children->items[0];
 | 
			
		||||
			ipc_event_window(child, "close");
 | 
			
		||||
			container_remove_child(child);
 | 
			
		||||
			_container_destroy(child);
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -188,12 +178,11 @@ static struct sway_container *container_workspace_destroy(
 | 
			
		|||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wlr_log(L_DEBUG, "destroying workspace '%s'", workspace->name);
 | 
			
		||||
	ipc_event_window(workspace, "close");
 | 
			
		||||
 | 
			
		||||
	struct sway_container *parent = workspace->parent;
 | 
			
		||||
	if (workspace_is_empty(workspace)) {
 | 
			
		||||
		// destroy the WS if there are no children
 | 
			
		||||
		wlr_log(L_DEBUG, "destroying workspace '%s'", workspace->name);
 | 
			
		||||
		ipc_event_workspace(workspace, NULL, "empty");
 | 
			
		||||
	} else if (output) {
 | 
			
		||||
	if (!workspace_is_empty(workspace) && output) {
 | 
			
		||||
		// Move children to a different workspace on this output
 | 
			
		||||
		struct sway_container *new_workspace = NULL;
 | 
			
		||||
		for (int i = 0; i < output->children->length; i++) {
 | 
			
		||||
| 
						 | 
				
			
			@ -357,10 +346,12 @@ struct sway_container *container_destroy(struct sway_container *con) {
 | 
			
		|||
			if (con->children->length) {
 | 
			
		||||
				for (int i = 0; i < con->children->length; ++i) {
 | 
			
		||||
					struct sway_container *child = con->children->items[0];
 | 
			
		||||
					ipc_event_window(child, "close");
 | 
			
		||||
					container_remove_child(child);
 | 
			
		||||
					container_add_child(parent, child);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			ipc_event_window(con, "close");
 | 
			
		||||
			_container_destroy(con);
 | 
			
		||||
			break;
 | 
			
		||||
		case C_VIEW:
 | 
			
		||||
| 
						 | 
				
			
			@ -635,20 +626,20 @@ struct sway_container *floating_container_at(double lx, double ly,
 | 
			
		|||
		for (int j = 0; j < output->children->length; ++j) {
 | 
			
		||||
			struct sway_container *workspace = output->children->items[j];
 | 
			
		||||
			struct sway_workspace *ws = workspace->sway_workspace;
 | 
			
		||||
			bool ws_is_visible = workspace_is_visible(workspace);
 | 
			
		||||
			if (!workspace_is_visible(workspace)) {
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			for (int k = 0; k < ws->floating->children->length; ++k) {
 | 
			
		||||
				struct sway_container *floater =
 | 
			
		||||
					ws->floating->children->items[k];
 | 
			
		||||
				if (ws_is_visible || floater->is_sticky) {
 | 
			
		||||
					struct wlr_box box = {
 | 
			
		||||
						.x = floater->x,
 | 
			
		||||
						.y = floater->y,
 | 
			
		||||
						.width = floater->width,
 | 
			
		||||
						.height = floater->height,
 | 
			
		||||
					};
 | 
			
		||||
					if (wlr_box_contains_point(&box, lx, ly)) {
 | 
			
		||||
						return container_at(floater, lx, ly, surface, sx, sy);
 | 
			
		||||
					}
 | 
			
		||||
				struct wlr_box box = {
 | 
			
		||||
					.x = floater->x,
 | 
			
		||||
					.y = floater->y,
 | 
			
		||||
					.width = floater->width,
 | 
			
		||||
					.height = floater->height,
 | 
			
		||||
				};
 | 
			
		||||
				if (wlr_box_contains_point(&box, lx, ly)) {
 | 
			
		||||
					return container_at(floater, lx, ly, surface, sx, sy);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -387,7 +387,21 @@ bool workspace_switch(struct sway_container *workspace) {
 | 
			
		|||
		strcpy(prev_workspace_name, active_ws->name);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// TODO: Deal with sticky containers
 | 
			
		||||
	// Move sticky containers to new workspace
 | 
			
		||||
	struct sway_container *next_output = workspace->parent;
 | 
			
		||||
	struct sway_container *next_output_prev_ws =
 | 
			
		||||
		seat_get_active_child(seat, next_output);
 | 
			
		||||
	struct sway_container *floating =
 | 
			
		||||
		next_output_prev_ws->sway_workspace->floating;
 | 
			
		||||
	bool has_sticky = false;
 | 
			
		||||
	for (int i = 0; i < floating->children->length; ++i) {
 | 
			
		||||
		struct sway_container *floater = floating->children->items[i];
 | 
			
		||||
		if (floater->is_sticky) {
 | 
			
		||||
			has_sticky = true;
 | 
			
		||||
			container_remove_child(floater);
 | 
			
		||||
			container_add_child(workspace->sway_workspace->floating, floater);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wlr_log(L_DEBUG, "Switching to workspace %p:%s",
 | 
			
		||||
		workspace, workspace->name);
 | 
			
		||||
| 
						 | 
				
			
			@ -395,6 +409,16 @@ bool workspace_switch(struct sway_container *workspace) {
 | 
			
		|||
	if (next == NULL) {
 | 
			
		||||
		next = workspace;
 | 
			
		||||
	}
 | 
			
		||||
	if (has_sticky) {
 | 
			
		||||
		// If there's a sticky container, we might be setting focus to the same
 | 
			
		||||
		// container that's already focused, so seat_set_focus is effectively a
 | 
			
		||||
		// no op. We therefore need to send the IPC event and clean up the old
 | 
			
		||||
		// workspace here.
 | 
			
		||||
		ipc_event_workspace(active_ws, workspace, "focus");
 | 
			
		||||
		if (!workspace_is_visible(active_ws) && workspace_is_empty(active_ws)) {
 | 
			
		||||
			container_destroy(active_ws);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	seat_set_focus(seat, next);
 | 
			
		||||
	struct sway_container *output = container_parent(workspace, C_OUTPUT);
 | 
			
		||||
	arrange_output(output);
 | 
			
		||||
| 
						 | 
				
			
			@ -418,8 +442,13 @@ bool workspace_is_empty(struct sway_container *ws) {
 | 
			
		|||
	if (ws->children->length) {
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
	if (ws->sway_workspace->floating->children->length) {
 | 
			
		||||
		return false;
 | 
			
		||||
	// Sticky views are not considered to be part of this workspace
 | 
			
		||||
	struct sway_container *floating = ws->sway_workspace->floating;
 | 
			
		||||
	for (int i = 0; i < floating->children->length; ++i) {
 | 
			
		||||
		struct sway_container *floater = floating->children->items[i];
 | 
			
		||||
		if (!floater->is_sticky) {
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue