diff options
Diffstat (limited to 'sway/input')
| -rw-r--r-- | sway/input/cursor.c | 158 | ||||
| -rw-r--r-- | sway/input/input-manager.c | 14 | ||||
| -rw-r--r-- | sway/input/seat.c | 514 | 
3 files changed, 335 insertions, 351 deletions
| diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 00240e84..15993265 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -20,6 +20,7 @@  #include "sway/layers.h"  #include "sway/output.h"  #include "sway/tree/arrange.h" +#include "sway/tree/container.h"  #include "sway/tree/root.h"  #include "sway/tree/view.h"  #include "sway/tree/workspace.h" @@ -50,15 +51,15 @@ static struct wlr_surface *layer_surface_at(struct sway_output *output,  }  /** - * Returns the container at the cursor's position. If there is a surface at that + * Returns the node at the cursor's position. If there is a surface at that   * location, it is stored in **surface (it may not be a view).   */ -static struct sway_container *container_at_coords( +static struct sway_node *node_at_coords(  		struct sway_seat *seat, double lx, double ly,  		struct wlr_surface **surface, double *sx, double *sy) {  	// check for unmanaged views first  #ifdef HAVE_XWAYLAND -	struct wl_list *unmanaged = &root_container.sway_root->xwayland_unmanaged; +	struct wl_list *unmanaged = &root->xwayland_unmanaged;  	struct sway_xwayland_unmanaged *unmanaged_surface;  	wl_list_for_each_reverse(unmanaged_surface, unmanaged, link) {  		struct wlr_xwayland_surface *xsurface = @@ -75,67 +76,64 @@ static struct sway_container *container_at_coords(  	}  #endif  	// find the output the cursor is on -	struct wlr_output_layout *output_layout = -		root_container.sway_root->output_layout;  	struct wlr_output *wlr_output = wlr_output_layout_output_at( -			output_layout, lx, ly); +			root->output_layout, lx, ly);  	if (wlr_output == NULL) {  		return NULL;  	}  	struct sway_output *output = wlr_output->data;  	double ox = lx, oy = ly; -	wlr_output_layout_output_coords(output_layout, wlr_output, &ox, &oy); +	wlr_output_layout_output_coords(root->output_layout, wlr_output, &ox, &oy);  	// find the focused workspace on the output for this seat -	struct sway_container *ws = seat_get_focus_inactive(seat, output->swayc); -	if (ws && ws->type != C_WORKSPACE) { -		ws = container_parent(ws, C_WORKSPACE); -	} -	if (!ws) { -		return output->swayc; -	} +	struct sway_workspace *ws = output_get_active_workspace(output);  	if ((*surface = layer_surface_at(output,  				&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY],  				ox, oy, sx, sy))) { -		return ws; +		return &ws->node;  	} -	if (ws->sway_workspace->fullscreen) { -		return tiling_container_at(ws->sway_workspace->fullscreen, lx, ly, -				surface, sx, sy); +	if (ws->fullscreen) { +		struct sway_container *con = +			tiling_container_at(&ws->fullscreen->node, lx, ly, surface, sx, sy); +		if (con) { +			return &con->node; +		} +		return NULL;  	}  	if ((*surface = layer_surface_at(output,  				&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP],  				ox, oy, sx, sy))) { -		return ws; +		return &ws->node;  	}  	struct sway_container *c;  	if ((c = container_at(ws, lx, ly, surface, sx, sy))) { -		return c; +		return &c->node;  	}  	if ((*surface = layer_surface_at(output,  				&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM],  				ox, oy, sx, sy))) { -		return ws; +		return &ws->node;  	}  	if ((*surface = layer_surface_at(output,  				&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND],  				ox, oy, sx, sy))) { -		return ws; +		return &ws->node;  	} -	c = seat_get_active_child(seat, output->swayc); -	if (c) { -		return c; -	} -	if (!c && output->swayc->children->length) { -		c = output->swayc->children->items[0]; -		return c; -	} +	return &ws->node; +} -	return output->swayc; +static struct sway_container *container_at_coords(struct sway_seat *seat, +		double lx, double ly, +		struct wlr_surface **surface, double *sx, double *sy) { +	struct sway_node *node = node_at_coords(seat, lx, ly, surface, sx, sy); +	if (node && node->type == N_CONTAINER) { +		return node->sway_container; +	} +	return NULL;  }  /** @@ -160,13 +158,14 @@ static bool edge_is_external(struct sway_container *cont, enum wlr_edges edge) {  	// Iterate the parents until we find one with the layout we want,  	// then check if the child has siblings between it and the edge. -	while (cont->type != C_OUTPUT) { -		if (cont->parent->layout == layout) { -			int index = list_find(cont->parent->children, cont); +	while (cont) { +		if (container_parent_layout(cont) == layout) { +			list_t *siblings = container_get_siblings(cont); +			int index = list_find(siblings, cont);  			if (index > 0 && (edge == WLR_EDGE_LEFT || edge == WLR_EDGE_TOP)) {  				return false;  			} -			if (index < cont->parent->children->length - 1 && +			if (index < siblings->length - 1 &&  					(edge == WLR_EDGE_RIGHT || edge == WLR_EDGE_BOTTOM)) {  				return false;  			} @@ -178,10 +177,10 @@ static bool edge_is_external(struct sway_container *cont, enum wlr_edges edge) {  static enum wlr_edges find_edge(struct sway_container *cont,  		struct sway_cursor *cursor) { -	if (cont->type != C_VIEW) { +	if (!cont->view) {  		return WLR_EDGE_NONE;  	} -	struct sway_view *view = cont->sway_view; +	struct sway_view *view = cont->view;  	if (view->border == B_NONE || !view->border_thickness || view->using_csd) {  		return WLR_EDGE_NONE;  	} @@ -219,7 +218,7 @@ static enum wlr_edges find_resize_edge(struct sway_container *cont,  static void handle_down_motion(struct sway_seat *seat,  		struct sway_cursor *cursor, uint32_t time_msec) {  	struct sway_container *con = seat->op_container; -	if (seat_is_input_allowed(seat, con->sway_view->surface)) { +	if (seat_is_input_allowed(seat, con->view->surface)) {  		double moved_x = cursor->cursor->x - seat->op_ref_lx;  		double moved_y = cursor->cursor->y - seat->op_ref_ly;  		double sx = seat->op_ref_con_lx + moved_x; @@ -260,8 +259,7 @@ static void calculate_floating_constraints(struct sway_container *con,  	if (config->floating_maximum_width == -1) { // no maximum  		*max_width = INT_MAX;  	} else if (config->floating_maximum_width == 0) { // automatic -		struct sway_container *ws = container_parent(con, C_WORKSPACE); -		*max_width = ws->width; +		*max_width = con->workspace->width;  	} else {  		*max_width = config->floating_maximum_width;  	} @@ -269,8 +267,7 @@ static void calculate_floating_constraints(struct sway_container *con,  	if (config->floating_maximum_height == -1) { // no maximum  		*max_height = INT_MAX;  	} else if (config->floating_maximum_height == 0) { // automatic -		struct sway_container *ws = container_parent(con, C_WORKSPACE); -		*max_height = ws->height; +		*max_height = con->workspace->height;  	} else {  		*max_height = config->floating_maximum_height;  	} @@ -314,9 +311,9 @@ static void handle_resize_floating_motion(struct sway_seat *seat,  	height = fmax(min_height, fmin(height, max_height));  	// Apply the view's min/max size -	if (con->type == C_VIEW) { +	if (con->view) {  		double view_min_width, view_max_width, view_min_height, view_max_height; -		view_get_constraints(con->sway_view, &view_min_width, &view_max_width, +		view_get_constraints(con->view, &view_min_width, &view_max_width,  				&view_min_height, &view_max_height);  		width = fmax(view_min_width, fmin(width, view_max_width));  		height = fmax(view_min_height, fmin(height, view_max_height)); @@ -357,15 +354,15 @@ static void handle_resize_floating_motion(struct sway_seat *seat,  	con->width += relative_grow_width;  	con->height += relative_grow_height; -	if (con->type == C_VIEW) { -		struct sway_view *view = con->sway_view; +	if (con->view) { +		struct sway_view *view = con->view;  		view->x += relative_grow_x;  		view->y += relative_grow_y;  		view->width += relative_grow_width;  		view->height += relative_grow_height;  	} -	arrange_windows(con); +	arrange_container(con);  }  static void handle_resize_tiling_motion(struct sway_seat *seat, @@ -435,44 +432,40 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec,  	struct wlr_surface *surface = NULL;  	double sx, sy; -	// Find the container beneath the pointer's previous position -	struct sway_container *prev_c = container_at_coords(seat, +	// Find the node beneath the pointer's previous position +	struct sway_node *prev_node = node_at_coords(seat,  			cursor->previous.x, cursor->previous.y, &surface, &sx, &sy);  	// Update the stored previous position  	cursor->previous.x = cursor->cursor->x;  	cursor->previous.y = cursor->cursor->y; -	struct sway_container *c = container_at_coords(seat, +	struct sway_node *node = node_at_coords(seat,  			cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); -	if (c && config->focus_follows_mouse && allow_refocusing) { -		struct sway_container *focus = seat_get_focus(seat); -		if (focus && c->type == C_WORKSPACE) { +	if (node && config->focus_follows_mouse && allow_refocusing) { +		struct sway_node *focus = seat_get_focus(seat); +		if (focus && node->type == N_WORKSPACE) {  			// Only follow the mouse if it would move to a new output  			// Otherwise we'll focus the workspace, which is probably wrong -			if (focus->type != C_OUTPUT) { -				focus = container_parent(focus, C_OUTPUT); -			} -			struct sway_container *output = c; -			if (output->type != C_OUTPUT) { -				output = container_parent(c, C_OUTPUT); -			} -			if (output != focus) { -				seat_set_focus_warp(seat, c, false, true); +			struct sway_output *focused_output = node_get_output(focus); +			struct sway_output *output = node_get_output(node); +			if (output != focused_output) { +				seat_set_focus_warp(seat, node, false, true);  			} -		} else if (c->type == C_VIEW) { -			// Focus c if the following are true: +		} else if (node->type == N_CONTAINER && node->sway_container->view) { +			// Focus node if the following are true:  			// - cursor is over a new view, i.e. entered a new window; and  			// - the new view is visible, i.e. not hidden in a stack or tab; and  			// - the seat does not have a keyboard grab  			if (!wlr_seat_keyboard_has_grab(cursor->seat->wlr_seat) && -					c != prev_c && -					view_is_visible(c->sway_view)) { -				seat_set_focus_warp(seat, c, false, true); +					node != prev_node && +					view_is_visible(node->sway_container->view)) { +				seat_set_focus_warp(seat, node, false, true);  			} else { -				struct sway_container *next_focus = -					seat_get_focus_inactive(seat, &root_container); -				if (next_focus && next_focus->type == C_VIEW && -						view_is_visible(next_focus->sway_view)) { +				struct sway_node *next_focus = +					seat_get_focus_inactive(seat, &root->node); +				if (next_focus && next_focus->type == N_CONTAINER && +						node->sway_container->view && +						view_is_visible(next_focus->sway_container->view)) {  					seat_set_focus_warp(seat, next_focus, false, true);  				}  			} @@ -486,12 +479,12 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec,  		if (client != cursor->image_client) {  			cursor_set_image(cursor, "left_ptr", client);  		} -	} else if (c) { -		// Try a container's resize edge -		enum wlr_edges edge = find_resize_edge(c, cursor); +	} else if (node && node->type == N_CONTAINER) { +		// Try a node's resize edge +		enum wlr_edges edge = find_resize_edge(node->sway_container, cursor);  		if (edge == WLR_EDGE_NONE) {  			cursor_set_image(cursor, "left_ptr", NULL); -		} else if (container_is_floating(c)) { +		} else if (container_is_floating(node->sway_container)) {  			cursor_set_image(cursor, wlr_xcursor_get_resize_name(edge), NULL);  		} else {  			if (edge & (WLR_EDGE_LEFT | WLR_EDGE_RIGHT)) { @@ -684,7 +677,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor,  	// Handle tiling resize via border  	if (resize_edge && button == BTN_LEFT && state == WLR_BUTTON_PRESSED &&  			!is_floating) { -		seat_set_focus(seat, cont); +		seat_set_focus(seat, &cont->node);  		seat_begin_resize_tiling(seat, cont, button, edge);  		return;  	} @@ -713,7 +706,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor,  				image = "sw-resize";  			}  			cursor_set_image(seat->cursor, image, NULL); -			seat_set_focus(seat, cont); +			seat_set_focus(seat, &cont->node);  			seat_begin_resize_tiling(seat, cont, button, edge);  			return;  		} @@ -725,7 +718,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor,  		uint32_t btn_move = config->floating_mod_inverse ? BTN_RIGHT : BTN_LEFT;  		if (button == btn_move && state == WLR_BUTTON_PRESSED &&  				(mod_pressed || on_titlebar)) { -			while (cont->parent->type != C_WORKSPACE) { +			while (cont->parent) {  				cont = cont->parent;  			}  			seat_begin_move(seat, cont, button); @@ -747,7 +740,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor,  			BTN_LEFT : BTN_RIGHT;  		if (mod_pressed && button == btn_resize) {  			struct sway_container *floater = cont; -			while (floater->parent->type != C_WORKSPACE) { +			while (floater->parent) {  				floater = floater->parent;  			}  			edge = 0; @@ -762,7 +755,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor,  	// Handle mousedown on a container surface  	if (surface && cont && state == WLR_BUTTON_PRESSED) { -		seat_set_focus(seat, cont); +		seat_set_focus(seat, &cont->node);  		seat_pointer_notify_button(seat, time_msec, button, state);  		seat_begin_down(seat, cont, button, sx, sy);  		return; @@ -770,7 +763,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor,  	// Handle clicking a container surface  	if (cont) { -		seat_set_focus(seat, cont); +		seat_set_focus(seat, &cont->node);  		seat_pointer_notify_button(seat, time_msec, button, state);  		return;  	} @@ -1025,8 +1018,7 @@ struct sway_cursor *sway_cursor_create(struct sway_seat *seat) {  	cursor->previous.y = wlr_cursor->y;  	cursor->seat = seat; -	wlr_cursor_attach_output_layout(wlr_cursor, -		root_container.sway_root->output_layout); +	wlr_cursor_attach_output_layout(wlr_cursor, root->output_layout);  	// input events  	wl_signal_add(&wlr_cursor->events.motion, &cursor->motion); diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c index c820e032..b4352c6a 100644 --- a/sway/input/input-manager.c +++ b/sway/input/input-manager.c @@ -293,12 +293,10 @@ static void handle_inhibit_deactivate(struct wl_listener *listener, void *data)  	struct sway_seat *seat;  	wl_list_for_each(seat, &input_manager->seats, link) {  		seat_set_exclusive_client(seat, NULL); -		struct sway_container *previous = seat_get_focus(seat); +		struct sway_node *previous = seat_get_focus(seat);  		if (previous) { -			wlr_log(WLR_DEBUG, "Returning focus to %p %s '%s'", previous, -					container_type_to_str(previous->type), previous->name);  			// Hack to get seat to re-focus the return value of get_focus -			seat_set_focus(seat, previous->parent); +			seat_set_focus(seat, NULL);  			seat_set_focus(seat, previous);  		}  	} @@ -369,10 +367,10 @@ struct sway_input_manager *input_manager_create(  }  bool input_manager_has_focus(struct sway_input_manager *input, -		struct sway_container *container) { +		struct sway_node *node) {  	struct sway_seat *seat = NULL;  	wl_list_for_each(seat, &input->seats, link) { -		if (seat_get_focus(seat) == container) { +		if (seat_get_focus(seat) == node) {  			return true;  		}  	} @@ -381,10 +379,10 @@ bool input_manager_has_focus(struct sway_input_manager *input,  }  void input_manager_set_focus(struct sway_input_manager *input, -		struct sway_container *container) { +		struct sway_node *node) {  	struct sway_seat *seat;  	wl_list_for_each(seat, &input->seats, link) { -		seat_set_focus(seat, container); +		seat_set_focus(seat, node);  	}  } diff --git a/sway/input/seat.c b/sway/input/seat.c index 4b7c7893..2f7a3318 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -47,48 +47,36 @@ void seat_destroy(struct sway_seat *seat) {  		seat_device_destroy(seat_device);  	}  	sway_cursor_destroy(seat->cursor); -	wl_list_remove(&seat->new_container.link); +	wl_list_remove(&seat->new_node.link);  	wl_list_remove(&seat->new_drag_icon.link);  	wl_list_remove(&seat->link);  	wlr_seat_destroy(seat->wlr_seat);  } -static struct sway_seat_container *seat_container_from_container( -		struct sway_seat *seat, struct sway_container *con); +static struct sway_seat_node *seat_node_from_node( +		struct sway_seat *seat, struct sway_node *node); -static void seat_container_destroy(struct sway_seat_container *seat_con) { -	struct sway_container *con = seat_con->container; -	struct sway_container *child = NULL; - -	if (con->children != NULL) { -		for (int i = 0; i < con->children->length; ++i) { -			child = con->children->items[i]; -			struct sway_seat_container *seat_child = -				seat_container_from_container(seat_con->seat, child); -			seat_container_destroy(seat_child); -		} -	} - -	wl_list_remove(&seat_con->destroy.link); -	wl_list_remove(&seat_con->link); -	free(seat_con); +static void seat_node_destroy(struct sway_seat_node *seat_node) { +	wl_list_remove(&seat_node->destroy.link); +	wl_list_remove(&seat_node->link); +	free(seat_node);  }  /**   * Activate all views within this container recursively.   */ -static void seat_send_activate(struct sway_container *con, -		struct sway_seat *seat) { -	if (con->type == C_VIEW) { -		if (!seat_is_input_allowed(seat, con->sway_view->surface)) { +static void seat_send_activate(struct sway_node *node, struct sway_seat *seat) { +	if (node_is_view(node)) { +		if (!seat_is_input_allowed(seat, node->sway_container->view->surface)) {  			wlr_log(WLR_DEBUG, "Refusing to set focus, input is inhibited");  			return;  		} -		view_set_activated(con->sway_view, true); +		view_set_activated(node->sway_container->view, true);  	} else { -		for (int i = 0; i < con->children->length; ++i) { -			struct sway_container *child = con->children->items[i]; -			seat_send_activate(child, seat); +		list_t *children = node_get_children(node); +		for (int i = 0; i < children->length; ++i) { +			struct sway_container *child = children->items[i]; +			seat_send_activate(&child->node, seat);  		}  	}  } @@ -98,14 +86,15 @@ static void seat_send_activate(struct sway_container *con,   * If con is a container, set all child views as active and don't enable   * keyboard input on any.   */ -static void seat_send_focus(struct sway_container *con, -		struct sway_seat *seat) { -	seat_send_activate(con, seat); +static void seat_send_focus(struct sway_node *node, struct sway_seat *seat) { +	seat_send_activate(node, seat); -	if (con->type == C_VIEW -			&& seat_is_input_allowed(seat, con->sway_view->surface)) { +	struct sway_view *view = node->type == N_CONTAINER ? +		node->sway_container->view : NULL; + +	if (view && seat_is_input_allowed(seat, view->surface)) {  #ifdef HAVE_XWAYLAND -		if (con->sway_view->type == SWAY_VIEW_XWAYLAND) { +		if (view->type == SWAY_VIEW_XWAYLAND) {  			struct wlr_xwayland *xwayland =  				seat->input->server->xwayland.wlr_xwayland;  			wlr_xwayland_set_seat(xwayland, seat->wlr_seat); @@ -114,71 +103,67 @@ static void seat_send_focus(struct sway_container *con,  		struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat);  		if (keyboard) {  			wlr_seat_keyboard_notify_enter(seat->wlr_seat, -					con->sway_view->surface, keyboard->keycodes, +					view->surface, keyboard->keycodes,  					keyboard->num_keycodes, &keyboard->modifiers);  		} else {  			wlr_seat_keyboard_notify_enter( -					seat->wlr_seat, con->sway_view->surface, NULL, 0, NULL); +					seat->wlr_seat, view->surface, NULL, 0, NULL);  		}  	}  } -void seat_focus_inactive_children_for_each(struct sway_seat *seat, -		struct sway_container *container, -		void (*f)(struct sway_container *container, void *data), void *data) { -	struct sway_seat_container *current = NULL; +void seat_for_each_node(struct sway_seat *seat, +		void (*f)(struct sway_node *node, void *data), void *data) { +	struct sway_seat_node *current = NULL;  	wl_list_for_each(current, &seat->focus_stack, link) { -		if (current->container->parent == NULL) { -			continue; -		} -		if (current->container->parent == container) { -			f(current->container, data); -		} +		f(current->node, data);  	}  }  struct sway_container *seat_get_focus_inactive_view(struct sway_seat *seat, -		struct sway_container *ancestor) { -	if (ancestor->type == C_VIEW) { -		return ancestor; +		struct sway_node *ancestor) { +	if (ancestor->type == N_CONTAINER && ancestor->sway_container->view) { +		return ancestor->sway_container;  	} -	struct sway_seat_container *current; +	struct sway_seat_node *current;  	wl_list_for_each(current, &seat->focus_stack, link) { -		struct sway_container *con = current->container; -		if (con->type == C_VIEW && container_has_ancestor(con, ancestor)) { -			return con; +		struct sway_node *node = current->node; +		if (node->type == N_CONTAINER && node->sway_container->view && +				node_has_ancestor(node, ancestor)) { +			return node->sway_container;  		}  	}  	return NULL;  } -static void handle_seat_container_destroy(struct wl_listener *listener, -		void *data) { -	struct sway_seat_container *seat_con = -		wl_container_of(listener, seat_con, destroy); -	struct sway_seat *seat = seat_con->seat; -	struct sway_container *con = seat_con->container; -	struct sway_container *parent = con->parent; -	struct sway_container *focus = seat_get_focus(seat); +static void handle_seat_node_destroy(struct wl_listener *listener, void *data) { +	struct sway_seat_node *seat_node = +		wl_container_of(listener, seat_node, destroy); +	struct sway_seat *seat = seat_node->seat; +	struct sway_node *node = seat_node->node; +	struct sway_node *parent = node_get_parent(node); +	struct sway_node *focus = seat_get_focus(seat);  	bool set_focus =  		focus != NULL && -		(focus == con || container_has_ancestor(focus, con)) && -		con->type != C_WORKSPACE; +		(focus == node || node_has_ancestor(focus, node)) && +		node->type == N_CONTAINER; -	seat_container_destroy(seat_con); +	seat_node_destroy(seat_node);  	if (set_focus) { -		struct sway_container *next_focus = NULL; +		struct sway_node *next_focus = NULL;  		while (next_focus == NULL) { -			next_focus = seat_get_focus_inactive_view(seat, parent); +			struct sway_container *con = +				seat_get_focus_inactive_view(seat, parent); +			next_focus = con ? &con->node : NULL; -			if (next_focus == NULL && parent->type == C_WORKSPACE) { +			if (next_focus == NULL && parent->type == N_WORKSPACE) {  				next_focus = parent;  				break;  			} -			parent = parent->parent; +			parent = node_get_parent(parent);  		}  		// the structure change might have caused it to move up to the top of @@ -191,39 +176,39 @@ static void handle_seat_container_destroy(struct wl_listener *listener,  	}  } -static struct sway_seat_container *seat_container_from_container( -		struct sway_seat *seat, struct sway_container *con) { -	if (con->type == C_ROOT || con->type == C_OUTPUT) { -		// these don't get seat containers ever +static struct sway_seat_node *seat_node_from_node( +		struct sway_seat *seat, struct sway_node *node) { +	if (node->type == N_ROOT || node->type == N_OUTPUT) { +		// these don't get seat nodes ever  		return NULL;  	} -	struct sway_seat_container *seat_con = NULL; -	wl_list_for_each(seat_con, &seat->focus_stack, link) { -		if (seat_con->container == con) { -			return seat_con; +	struct sway_seat_node *seat_node = NULL; +	wl_list_for_each(seat_node, &seat->focus_stack, link) { +		if (seat_node->node == node) { +			return seat_node;  		}  	} -	seat_con = calloc(1, sizeof(struct sway_seat_container)); -	if (seat_con == NULL) { -		wlr_log(WLR_ERROR, "could not allocate seat container"); +	seat_node = calloc(1, sizeof(struct sway_seat_node)); +	if (seat_node == NULL) { +		wlr_log(WLR_ERROR, "could not allocate seat node");  		return NULL;  	} -	seat_con->container = con; -	seat_con->seat = seat; -	wl_list_insert(seat->focus_stack.prev, &seat_con->link); -	wl_signal_add(&con->events.destroy, &seat_con->destroy); -	seat_con->destroy.notify = handle_seat_container_destroy; +	seat_node->node = node; +	seat_node->seat = seat; +	wl_list_insert(seat->focus_stack.prev, &seat_node->link); +	wl_signal_add(&node->events.destroy, &seat_node->destroy); +	seat_node->destroy.notify = handle_seat_node_destroy; -	return seat_con; +	return seat_node;  } -static void handle_new_container(struct wl_listener *listener, void *data) { -	struct sway_seat *seat = wl_container_of(listener, seat, new_container); -	struct sway_container *con = data; -	seat_container_from_container(seat, con); +static void handle_new_node(struct wl_listener *listener, void *data) { +	struct sway_seat *seat = wl_container_of(listener, seat, new_node); +	struct sway_node *node = data; +	seat_node_from_node(seat, node);  }  static void drag_icon_damage_whole(struct sway_drag_icon *icon) { @@ -272,8 +257,7 @@ static void drag_icon_handle_unmap(struct wl_listener *listener, void *data) {  	drag_icon_damage_whole(icon);  } -static void drag_icon_handle_destroy(struct wl_listener *listener, -		void *data) { +static void drag_icon_handle_destroy(struct wl_listener *listener, void *data) {  	struct sway_drag_icon *icon = wl_container_of(listener, icon, destroy);  	icon->wlr_drag_icon->data = NULL;  	wl_list_remove(&icon->link); @@ -305,20 +289,29 @@ static void handle_new_drag_icon(struct wl_listener *listener, void *data) {  	icon->destroy.notify = drag_icon_handle_destroy;  	wl_signal_add(&wlr_drag_icon->events.destroy, &icon->destroy); -	wl_list_insert(&root_container.sway_root->drag_icons, &icon->link); +	wl_list_insert(&root->drag_icons, &icon->link);  	drag_icon_update_position(icon);  } -static void collect_focus_iter(struct sway_container *con, void *data) { +static void collect_focus_iter(struct sway_node *node, void *data) {  	struct sway_seat *seat = data; -	struct sway_seat_container *seat_con = -		seat_container_from_container(seat, con); -	if (!seat_con) { +	struct sway_seat_node *seat_node = seat_node_from_node(seat, node); +	if (!seat_node) {  		return;  	} -	wl_list_remove(&seat_con->link); -	wl_list_insert(&seat->focus_stack, &seat_con->link); +	wl_list_remove(&seat_node->link); +	wl_list_insert(&seat->focus_stack, &seat_node->link); +} + +static void collect_focus_workspace_iter(struct sway_workspace *workspace, +		void *data) { +	collect_focus_iter(&workspace->node, data); +} + +static void collect_focus_container_iter(struct sway_container *container, +		void *data) { +	collect_focus_iter(&container->node, data);  }  struct sway_seat *seat_create(struct sway_input_manager *input, @@ -345,12 +338,11 @@ struct sway_seat *seat_create(struct sway_input_manager *input,  	// init the focus stack  	wl_list_init(&seat->focus_stack); -	root_for_each_workspace(collect_focus_iter, seat); -	root_for_each_container(collect_focus_iter, seat); +	root_for_each_workspace(collect_focus_workspace_iter, seat); +	root_for_each_container(collect_focus_container_iter, seat); -	wl_signal_add(&root_container.sway_root->events.new_container, -		&seat->new_container); -	seat->new_container.notify = handle_new_container; +	wl_signal_add(&root->events.new_node, &seat->new_node); +	seat->new_node.notify = handle_new_node;  	wl_signal_add(&seat->wlr_seat->events.new_drag_icon, &seat->new_drag_icon);  	seat->new_drag_icon.notify = handle_new_drag_icon; @@ -388,19 +380,11 @@ static void seat_apply_input_config(struct sway_seat *seat,  	if (mapped_to_output != NULL) {  		wlr_log(WLR_DEBUG, "Mapping input device %s to output %s",  			sway_device->input_device->identifier, mapped_to_output); -		struct sway_container *output = NULL; -		for (int i = 0; i < root_container.children->length; ++i) { -			struct sway_container *_output = root_container.children->items[i]; -			if (strcasecmp(_output->name, mapped_to_output) == 0) { -				output = _output; -				break; -			} -		} +		struct sway_output *output = output_by_name(mapped_to_output);  		if (output) {  			wlr_cursor_map_input_to_output(seat->cursor->cursor, -				sway_device->input_device->wlr_device, -				output->sway_output->wlr_output); -			wlr_log(WLR_DEBUG, "Mapped to output %s", output->name); +				sway_device->input_device->wlr_device, output->wlr_output); +			wlr_log(WLR_DEBUG, "Mapped to output %s", output->wlr_output->name);  		}  	}  } @@ -423,12 +407,12 @@ static void seat_configure_keyboard(struct sway_seat *seat,  	sway_keyboard_configure(seat_device->keyboard);  	wlr_seat_set_keyboard(seat->wlr_seat,  			seat_device->input_device->wlr_device); -	struct sway_container *focus = seat_get_focus(seat); -	if (focus && focus->type == C_VIEW) { +	struct sway_node *focus = seat_get_focus(seat); +	if (focus && node_is_view(focus)) {  		// force notify reenter to pick up the new configuration  		wlr_seat_keyboard_clear_focus(seat->wlr_seat);  		wlr_seat_keyboard_notify_enter(seat->wlr_seat, -				focus->sway_view->surface, wlr_keyboard->keycodes, +				focus->sway_container->view->surface, wlr_keyboard->keycodes,  				wlr_keyboard->num_keycodes, &wlr_keyboard->modifiers);  	}  } @@ -461,8 +445,7 @@ static struct sway_seat_device *seat_get_device(struct sway_seat *seat,  void seat_configure_device(struct sway_seat *seat,  		struct sway_input_device *input_device) { -	struct sway_seat_device *seat_device = -		seat_get_device(seat, input_device); +	struct sway_seat_device *seat_device = seat_get_device(seat, input_device);  	if (!seat_device) {  		return;  	} @@ -512,8 +495,7 @@ void seat_add_device(struct sway_seat *seat,  void seat_remove_device(struct sway_seat *seat,  		struct sway_input_device *input_device) { -	struct sway_seat_device *seat_device = -		seat_get_device(seat, input_device); +	struct sway_seat_device *seat_device = seat_get_device(seat, input_device);  	if (!seat_device) {  		return; @@ -539,11 +521,9 @@ void seat_configure_xcursor(struct sway_seat *seat) {  		}  	} -	for (int i = 0; i < root_container.children->length; ++i) { -		struct sway_container *output_container = -			root_container.children->items[i]; -		struct wlr_output *output = -			output_container->sway_output->wlr_output; +	for (int i = 0; i < root->outputs->length; ++i) { +		struct sway_output *sway_output = root->outputs->items[i]; +		struct wlr_output *output = sway_output->wlr_output;  		bool result =  			wlr_xcursor_manager_load(seat->cursor->xcursor_manager,  				output->scale); @@ -566,17 +546,20 @@ bool seat_is_input_allowed(struct sway_seat *seat,  	return !seat->exclusive_client || seat->exclusive_client == client;  } +static void send_unfocus(struct sway_container *con, void *data) { +	if (con->view) { +		view_set_activated(con->view, false); +	} +} +  // Unfocus the container and any children (eg. when leaving `focus parent`) -static void seat_send_unfocus(struct sway_container *container, -		struct sway_seat *seat) { -	if (container->type == C_VIEW) { -		wlr_seat_keyboard_clear_focus(seat->wlr_seat); -		view_set_activated(container->sway_view, false); +static void seat_send_unfocus(struct sway_node *node, struct sway_seat *seat) { +	wlr_seat_keyboard_clear_focus(seat->wlr_seat); +	if (node->type == N_WORKSPACE) { +		workspace_for_each_container(node->sway_workspace, send_unfocus, seat);  	} else { -		for (int i = 0; i < container->children->length; ++i) { -			struct sway_container *child = container->children->items[i]; -			seat_send_unfocus(child, seat); -		} +		send_unfocus(node->sway_container, seat); +		container_for_each_child(node->sway_container, send_unfocus, seat);  	}  } @@ -586,26 +569,23 @@ static int handle_urgent_timeout(void *data) {  	return 0;  } -void seat_set_focus_warp(struct sway_seat *seat, -		struct sway_container *container, bool warp, bool notify) { +void seat_set_focus_warp(struct sway_seat *seat, struct sway_node *node, +		bool warp, bool notify) {  	if (seat->focused_layer) {  		return;  	} -	struct sway_container *last_focus = seat_get_focus(seat); -	if (last_focus == container) { +	struct sway_node *last_focus = seat_get_focus(seat); +	if (last_focus == node) {  		return;  	} -	struct sway_container *last_workspace = last_focus; -	if (last_workspace && last_workspace->type != C_WORKSPACE) { -		last_workspace = container_parent(last_workspace, C_WORKSPACE); -	} +	struct sway_workspace *last_workspace = seat_get_focused_workspace(seat); -	if (container == NULL) { +	if (node == NULL) {  		// Close any popups on the old focus -		if (last_focus->type == C_VIEW) { -			view_close_popups(last_focus->sway_view); +		if (node_is_view(last_focus)) { +			view_close_popups(last_focus->sway_container->view);  		}  		seat_send_unfocus(last_focus, seat);  		seat->has_focus = false; @@ -613,69 +593,70 @@ void seat_set_focus_warp(struct sway_seat *seat,  		return;  	} -	struct sway_container *new_workspace = container; -	if (new_workspace->type != C_WORKSPACE) { -		new_workspace = container_parent(new_workspace, C_WORKSPACE); -	} +	struct sway_workspace *new_workspace = node->type == N_WORKSPACE ? +		node->sway_workspace : node->sway_container->workspace; +	struct sway_container *container = node->type == N_CONTAINER ? +		node->sway_container : NULL; -	if (last_workspace == new_workspace -			&& last_workspace->sway_workspace->fullscreen -			&& !container_is_fullscreen_or_child(container)) { +	// Deny setting focus to a view which is hidden by a fullscreen container +	if (new_workspace && new_workspace->fullscreen && container && +			!container_is_fullscreen_or_child(container)) {  		return;  	} -	struct sway_container *last_output = last_focus; -	if (last_output && last_output->type != C_OUTPUT) { -		last_output = container_parent(last_output, C_OUTPUT); -	} -	struct sway_container *new_output = container; -	if (new_output->type != C_OUTPUT) { -		new_output = container_parent(new_output, C_OUTPUT); -	} +	struct sway_output *last_output = last_workspace ? +		last_workspace->output : NULL; +	struct sway_output *new_output = new_workspace->output;  	// find new output's old workspace, which might have to be removed if empty -	struct sway_container *new_output_last_ws = NULL; +	struct sway_workspace *new_output_last_ws = NULL;  	if (new_output && last_output != new_output) { -		new_output_last_ws = seat_get_active_child(seat, new_output); +		new_output_last_ws = output_get_active_workspace(new_output);  	} -	if (container->parent) { -		struct sway_seat_container *seat_con = -			seat_container_from_container(seat, container); -		if (seat_con == NULL) { -			return; -		} - -		// put all the ancestors of this container on top of the focus stack -		struct sway_seat_container *parent = -			seat_container_from_container(seat, container->parent); +	// Put the container parents on the focus stack, then the workspace, then +	// the focused container. +	if (container) { +		struct sway_container *parent = container->parent;  		while (parent) { -			wl_list_remove(&parent->link); -			wl_list_insert(&seat->focus_stack, &parent->link); -			container_set_dirty(parent->container); - -			parent = seat_container_from_container(seat, -					parent->container->parent); +			struct sway_seat_node *seat_node = +				seat_node_from_node(seat, &parent->node); +			wl_list_remove(&seat_node->link); +			wl_list_insert(&seat->focus_stack, &seat_node->link); +			node_set_dirty(&parent->node); +			parent = parent->parent;  		} - -		wl_list_remove(&seat_con->link); -		wl_list_insert(&seat->focus_stack, &seat_con->link); +	} +	if (new_workspace) { +		struct sway_seat_node *seat_node = +			seat_node_from_node(seat, &new_workspace->node); +		wl_list_remove(&seat_node->link); +		wl_list_insert(&seat->focus_stack, &seat_node->link); +		node_set_dirty(&new_workspace->node); +	} +	if (container) { +		struct sway_seat_node *seat_node = +			seat_node_from_node(seat, &container->node); +		wl_list_remove(&seat_node->link); +		wl_list_insert(&seat->focus_stack, &seat_node->link); +		node_set_dirty(&container->node);  		if (last_focus) {  			seat_send_unfocus(last_focus, seat); -			container_set_dirty(last_focus); +			node_set_dirty(last_focus); +			struct sway_node *last_parent = node_get_parent(last_focus); +			if (last_parent) { +				node_set_dirty(last_parent); +			}  		} -		seat_send_focus(container, seat); - -		container_set_dirty(container); -		container_set_dirty(container->parent); // for focused_inactive_child +		seat_send_focus(&container->node, seat);  	}  	// emit ipc events  	if (notify && new_workspace && last_workspace != new_workspace) {  		 ipc_event_workspace(last_workspace, new_workspace, "focus");  	} -	if (container->type == C_VIEW) { +	if (container && container->view) {  		ipc_event_window(container, "focus");  	} @@ -684,14 +665,14 @@ void seat_set_focus_warp(struct sway_seat *seat,  	}  	// Close any popups on the old focus -	if (last_focus && last_focus->type == C_VIEW) { -		view_close_popups(last_focus->sway_view); +	if (last_focus && node_is_view(last_focus)) { +		view_close_popups(last_focus->sway_container->view);  	}  	// If urgent, either unset the urgency or start a timer to unset it -	if (container->type == C_VIEW && view_is_urgent(container->sway_view) && -			!container->sway_view->urgent_timer) { -		struct sway_view *view = container->sway_view; +	if (container && container->view && view_is_urgent(container->view) && +			!container->view->urgent_timer) { +		struct sway_view *view = container->view;  		if (last_workspace && last_workspace != new_workspace &&  				config->urgent_timeout > 0) {  			view->urgent_timer = wl_event_loop_add_timer(server.wl_event_loop, @@ -711,12 +692,15 @@ void seat_set_focus_warp(struct sway_seat *seat,  	// If we've focused a floating container, bring it to the front.  	// We do this by putting it at the end of the floating list. -	struct sway_container *floater = container; -	while (floater->parent && floater->parent->type != C_WORKSPACE) { -		floater = floater->parent; -	} -	if (container_is_floating(floater)) { -		list_move_to_end(floater->parent->sway_workspace->floating, floater); +	if (container) { +		struct sway_container *floater = container; +		while (floater->parent) { +			floater = floater->parent; +		} +		if (container_is_floating(floater)) { +			list_move_to_end(floater->workspace->floating, floater); +			node_set_dirty(&floater->workspace->node); +		}  	}  	if (last_focus) { @@ -727,11 +711,8 @@ void seat_set_focus_warp(struct sway_seat *seat,  		if (config->mouse_warping && warp && new_output != last_output) {  				double x = container->x + container->width / 2.0;  				double y = container->y + container->height / 2.0; -				struct wlr_output *wlr_output = -					new_output->sway_output->wlr_output; -				if (!wlr_output_layout_contains_point( -						root_container.sway_root->output_layout, -						wlr_output, seat->cursor->cursor->x, +				if (!wlr_output_layout_contains_point(root->output_layout, +						new_output->wlr_output, seat->cursor->cursor->x,  						seat->cursor->cursor->y)) {  					wlr_cursor_warp(seat->cursor->cursor, NULL, x, y);  					cursor_send_pointer_motion(seat->cursor, 0, true); @@ -744,9 +725,8 @@ void seat_set_focus_warp(struct sway_seat *seat,  	update_debug_tree();  } -void seat_set_focus(struct sway_seat *seat, -		struct sway_container *container) { -	seat_set_focus_warp(seat, container, true, true); +void seat_set_focus(struct sway_seat *seat, struct sway_node *node) { +	seat_set_focus_warp(seat, node, true, true);  }  void seat_set_focus_surface(struct sway_seat *seat, @@ -755,12 +735,11 @@ void seat_set_focus_surface(struct sway_seat *seat,  		return;  	}  	if (seat->has_focus && unfocus) { -		struct sway_container *focus = seat_get_focus(seat); +		struct sway_node *focus = seat_get_focus(seat);  		seat_send_unfocus(focus, seat);  		seat->has_focus = false;  	} -	struct wlr_keyboard *keyboard = -		wlr_seat_get_keyboard(seat->wlr_seat); +	struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat);  	if (keyboard) {  		wlr_seat_keyboard_notify_enter(seat->wlr_seat, surface,  			keyboard->keycodes, keyboard->num_keycodes, &keyboard->modifiers); @@ -773,11 +752,8 @@ void seat_set_focus_layer(struct sway_seat *seat,  		struct wlr_layer_surface *layer) {  	if (!layer && seat->focused_layer) {  		seat->focused_layer = NULL; -		struct sway_container *previous = -			seat_get_focus_inactive(seat, &root_container); +		struct sway_node *previous = seat_get_focus_inactive(seat, &root->node);  		if (previous) { -			wlr_log(WLR_DEBUG, "Returning focus to %p %s '%s'", previous, -					container_type_to_str(previous->type), previous->name);  			// Hack to get seat to re-focus the return value of get_focus  			seat_set_focus(seat, NULL);  			seat_set_focus(seat, previous); @@ -798,13 +774,9 @@ void seat_set_exclusive_client(struct sway_seat *seat,  		seat->exclusive_client = client;  		// Triggers a refocus of the topmost surface layer if necessary  		// TODO: Make layer surface focus per-output based on cursor position -		for (int i = 0; i < root_container.children->length; ++i) { -			struct sway_container *output = root_container.children->items[i]; -			if (!sway_assert(output->type == C_OUTPUT, -						"root container has non-output child")) { -				continue; -			} -			arrange_layers(output->sway_output); +		for (int i = 0; i < root->outputs->length; ++i) { +			struct sway_output *output = root->outputs->items[i]; +			arrange_layers(output);  		}  		return;  	} @@ -814,9 +786,9 @@ void seat_set_exclusive_client(struct sway_seat *seat,  		}  	}  	if (seat->has_focus) { -		struct sway_container *focus = seat_get_focus(seat); -		if (focus->type == C_VIEW && wl_resource_get_client( -					focus->sway_view->surface->resource) != client) { +		struct sway_node *focus = seat_get_focus(seat); +		if (node_is_view(focus) && wl_resource_get_client( +					focus->sway_container->view->surface->resource) != client) {  			seat_set_focus(seat, NULL);  		}  	} @@ -837,79 +809,101 @@ void seat_set_exclusive_client(struct sway_seat *seat,  	seat->exclusive_client = client;  } -struct sway_container *seat_get_focus_inactive(struct sway_seat *seat, -		struct sway_container *con) { -	if (con->type == C_WORKSPACE && !con->children->length && -			!con->sway_workspace->floating->length) { -		return con; -	} -	if (con->type == C_VIEW) { -		return con; +struct sway_node *seat_get_focus_inactive(struct sway_seat *seat, +		struct sway_node *node) { +	if (node_is_view(node)) { +		return node;  	} -	struct sway_seat_container *current; +	struct sway_seat_node *current;  	wl_list_for_each(current, &seat->focus_stack, link) { -		if (container_has_ancestor(current->container, con)) { -			return current->container; +		if (node_has_ancestor(current->node, node)) { +			return current->node;  		}  	} +	if (node->type == N_WORKSPACE) { +		return node; +	}  	return NULL;  }  struct sway_container *seat_get_focus_inactive_tiling(struct sway_seat *seat, -		struct sway_container *ancestor) { -	if (ancestor->type == C_WORKSPACE && !ancestor->children->length) { -		return ancestor; +		struct sway_workspace *workspace) { +	if (!workspace->tiling->length) { +		return NULL;  	} -	struct sway_seat_container *current; +	struct sway_seat_node *current;  	wl_list_for_each(current, &seat->focus_stack, link) { -		struct sway_container *con = current->container; -		if (!container_is_floating_or_child(con) && -				container_has_ancestor(current->container, ancestor)) { -			return con; +		struct sway_node *node = current->node; +		if (node->type == N_CONTAINER && +				!container_is_floating_or_child(node->sway_container) && +				node->sway_container->workspace == workspace) { +			return node->sway_container;  		}  	}  	return NULL;  }  struct sway_container *seat_get_focus_inactive_floating(struct sway_seat *seat, -		struct sway_container *ancestor) { -	if (ancestor->type == C_WORKSPACE && -			!ancestor->sway_workspace->floating->length) { +		struct sway_workspace *workspace) { +	if (!workspace->floating->length) {  		return NULL;  	} -	struct sway_seat_container *current; +	struct sway_seat_node *current;  	wl_list_for_each(current, &seat->focus_stack, link) { -		struct sway_container *con = current->container; -		if (container_is_floating_or_child(con) && -				container_has_ancestor(current->container, ancestor)) { -			return con; +		struct sway_node *node = current->node; +		if (node->type == N_CONTAINER && +				container_is_floating_or_child(node->sway_container) && +				node->sway_container->workspace == workspace) { +			return node->sway_container;  		}  	}  	return NULL;  } -struct sway_container *seat_get_active_child(struct sway_seat *seat, -		struct sway_container *parent) { -	if (parent->type == C_VIEW) { +struct sway_node *seat_get_active_child(struct sway_seat *seat, +		struct sway_node *parent) { +	if (node_is_view(parent)) {  		return parent;  	} -	struct sway_seat_container *current; +	struct sway_seat_node *current;  	wl_list_for_each(current, &seat->focus_stack, link) { -		struct sway_container *con = current->container; -		if (con->parent == parent) { -			return con; +		struct sway_node *node = current->node; +		if (node_get_parent(node) == parent) { +			return node;  		}  	}  	return NULL;  } -struct sway_container *seat_get_focus(struct sway_seat *seat) { +struct sway_node *seat_get_focus(struct sway_seat *seat) {  	if (!seat->has_focus) {  		return NULL;  	} -	struct sway_seat_container *current = +	struct sway_seat_node *current =  		wl_container_of(seat->focus_stack.next, current, link); -	return current->container; +	return current->node; +} + +struct sway_workspace *seat_get_focused_workspace(struct sway_seat *seat) { +	struct sway_node *focus = seat_get_focus(seat); +	if (!focus) { +		return NULL; +	} +	if (focus->type == N_CONTAINER) { +		return focus->sway_container->workspace; +	} +	if (focus->type == N_WORKSPACE) { +		return focus->sway_workspace; +	} +	return NULL; // unreachable +} + +struct sway_container *seat_get_focused_container(struct sway_seat *seat) { +	struct sway_node *focus = seat_get_focus(seat); +	if (focus && focus->type == N_CONTAINER) { +		return focus->sway_container; +	} +	return NULL;  }  void seat_apply_config(struct sway_seat *seat, | 
