diff options
Diffstat (limited to 'sway')
| -rw-r--r-- | sway/commands.c | 1 | ||||
| -rw-r--r-- | sway/commands/default_orientation.c | 21 | ||||
| -rw-r--r-- | sway/desktop/layer_shell.c | 26 | ||||
| -rw-r--r-- | sway/desktop/output.c | 167 | ||||
| -rw-r--r-- | sway/desktop/wl_shell.c | 1 | ||||
| -rw-r--r-- | sway/desktop/xdg_shell_v6.c | 52 | ||||
| -rw-r--r-- | sway/desktop/xwayland.c | 92 | ||||
| -rw-r--r-- | sway/input/cursor.c | 99 | ||||
| -rw-r--r-- | sway/input/seat.c | 4 | ||||
| -rw-r--r-- | sway/ipc-json.c | 69 | ||||
| -rw-r--r-- | sway/ipc-server.c | 10 | ||||
| -rw-r--r-- | sway/meson.build | 2 | ||||
| -rw-r--r-- | sway/server.c | 18 | ||||
| -rw-r--r-- | sway/tree/container.c | 78 | ||||
| -rw-r--r-- | sway/tree/layout.c | 58 | ||||
| -rw-r--r-- | sway/tree/output.c | 39 | ||||
| -rw-r--r-- | sway/tree/view.c | 27 | ||||
| -rw-r--r-- | sway/tree/workspace.c | 56 | 
18 files changed, 539 insertions, 281 deletions
diff --git a/sway/commands.c b/sway/commands.c index bcc777ed..eee7f254 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -149,6 +149,7 @@ static struct cmd_handler bar_colors_handlers[] = {  /* Config-time only commands. Keep alphabetized */  static struct cmd_handler config_handlers[] = { +	{ "default_orientation", cmd_default_orientation },  	{ "set", cmd_set },  	{ "swaybg_command", cmd_swaybg_command },  }; diff --git a/sway/commands/default_orientation.c b/sway/commands/default_orientation.c new file mode 100644 index 00000000..a5347ce2 --- /dev/null +++ b/sway/commands/default_orientation.c @@ -0,0 +1,21 @@ +#include <string.h> +#include <strings.h> +#include "sway/commands.h" + +struct cmd_results *cmd_default_orientation(int argc, char **argv) { +	struct cmd_results *error = NULL; +	if ((error = checkarg(argc, "default_orientation", EXPECTED_EQUAL_TO, 1))) { +		return error; +	} +	if (strcasecmp(argv[0], "horizontal") == 0) { +		config->default_orientation = L_HORIZ; +	} else if (strcasecmp(argv[0], "vertical") == 0) { +		config->default_orientation = L_VERT; +	} else if (strcasecmp(argv[0], "auto") == 0) { +		// Do nothing +	} else { +		return cmd_results_new(CMD_INVALID, "default_orientation", +				"Expected 'orientation <horizontal|vertical|auto>'"); +	} +	return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c index f7e5d19c..5c96659a 100644 --- a/sway/desktop/layer_shell.c +++ b/sway/desktop/layer_shell.c @@ -4,12 +4,13 @@  #include <wayland-server.h>  #include <wlr/types/wlr_box.h>  #include <wlr/types/wlr_layer_shell.h> +#include <wlr/types/wlr_output_damage.h>  #include <wlr/types/wlr_output.h>  #include <wlr/util/log.h>  #include "sway/layers.h" -#include "sway/tree/layout.h"  #include "sway/output.h"  #include "sway/server.h" +#include "sway/tree/layout.h"  static void apply_exclusive(struct wlr_box *usable_area,  		uint32_t anchor, int32_t exclusive, @@ -210,20 +211,26 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) {  		} else {  			// TODO DAMAGE from surface damage  		} +		wlr_output_damage_add_box(output->damage, &old_geo); +		wlr_output_damage_add_box(output->damage, &layer->geo);  	}  } -static void unmap(struct wlr_layer_surface *layer_surface) { -	// TODO DAMAGE +static void unmap(struct sway_layer_surface *sway_layer) { +	struct wlr_output *wlr_output = sway_layer->layer_surface->output; +	if (wlr_output != NULL) { +		struct sway_output *output = wlr_output->data; +		wlr_output_damage_add_box(output->damage, &sway_layer->geo); +	}  }  static void handle_destroy(struct wl_listener *listener, void *data) { -	struct sway_layer_surface *sway_layer = wl_container_of( -			listener, sway_layer, destroy); +	struct sway_layer_surface *sway_layer = wl_container_of(listener, +			sway_layer, destroy);  	wlr_log(L_DEBUG, "Layer surface destroyed (%s)",  			sway_layer->layer_surface->namespace);  	if (sway_layer->layer_surface->mapped) { -		unmap(sway_layer->layer_surface); +		unmap(sway_layer);  	}  	wl_list_remove(&sway_layer->link);  	wl_list_remove(&sway_layer->destroy.link); @@ -239,13 +246,16 @@ static void handle_destroy(struct wl_listener *listener, void *data) {  }  static void handle_map(struct wl_listener *listener, void *data) { -	// TODO DAMAGE +	struct sway_layer_surface *sway_layer = wl_container_of(listener, +			sway_layer, map); +	struct sway_output *output = sway_layer->layer_surface->output->data; +	wlr_output_damage_add_box(output->damage, &sway_layer->geo);  }  static void handle_unmap(struct wl_listener *listener, void *data) {  	struct sway_layer_surface *sway_layer = wl_container_of(  			listener, sway_layer, unmap); -	unmap(sway_layer->layer_surface); +	unmap(sway_layer);  }  void handle_layer_shell_surface(struct wl_listener *listener, void *data) { diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 87eb80fe..c248b29e 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -6,18 +6,19 @@  #include <wlr/render/wlr_renderer.h>  #include <wlr/types/wlr_box.h>  #include <wlr/types/wlr_matrix.h> -#include <wlr/types/wlr_output.h> +#include <wlr/types/wlr_output_damage.h>  #include <wlr/types/wlr_output_layout.h> +#include <wlr/types/wlr_output.h>  #include <wlr/types/wlr_surface.h>  #include <wlr/types/wlr_wl_shell.h>  #include "log.h" -#include "sway/tree/container.h"  #include "sway/input/input-manager.h"  #include "sway/input/seat.h"  #include "sway/layers.h" -#include "sway/tree/layout.h"  #include "sway/output.h"  #include "sway/server.h" +#include "sway/tree/container.h" +#include "sway/tree/layout.h"  #include "sway/tree/view.h"  /** @@ -41,6 +42,9 @@ static void rotate_child_position(double *sx, double *sy, double sw, double sh,  static void render_surface(struct wlr_surface *surface,  		struct wlr_output *wlr_output, struct timespec *when,  		double lx, double ly, float rotation) { +	struct wlr_renderer *renderer = +		wlr_backend_get_renderer(wlr_output->backend); +  	if (!wlr_surface_has_buffer(surface)) {  		return;  	} @@ -65,8 +69,8 @@ static void render_surface(struct wlr_surface *surface,  		float matrix[9];  		wlr_matrix_project_box(matrix, &render_box, surface->current->transform,  			0, wlr_output->transform_matrix); -		wlr_render_texture_with_matrix(server.renderer, surface->texture, -			matrix, 1.0f); // TODO: configurable alpha +		wlr_render_texture_with_matrix(renderer, surface->texture, matrix, +			1.0f); // TODO: configurable alpha  		wlr_surface_send_frame_done(surface, when);  	} @@ -142,13 +146,13 @@ static void render_wl_shell_surface(struct wlr_wl_shell_surface *surface,  struct render_data {  	struct sway_output *output; -	struct timespec *now; +	struct timespec *when;  }; -static void output_frame_view(struct sway_container *view, void *data) { +static void render_view(struct sway_container *view, void *data) {  	struct render_data *rdata = data;  	struct sway_output *output = rdata->output; -	struct timespec *now = rdata->now; +	struct timespec *when = rdata->when;  	struct wlr_output *wlr_output = output->wlr_output;  	struct sway_view *sway_view = view->sway_view;  	struct wlr_surface *surface = sway_view->surface; @@ -161,18 +165,18 @@ static void output_frame_view(struct sway_container *view, void *data) {  	case SWAY_XDG_SHELL_V6_VIEW: {  		int window_offset_x = view->sway_view->wlr_xdg_surface_v6->geometry.x;  		int window_offset_y = view->sway_view->wlr_xdg_surface_v6->geometry.y; -		render_surface(surface, wlr_output, now, +		render_surface(surface, wlr_output, when,  			view->x - window_offset_x, view->y - window_offset_y, 0);  		render_xdg_v6_popups(sway_view->wlr_xdg_surface_v6, wlr_output, -			now, view->x - window_offset_x, view->y - window_offset_y, 0); +			when, view->x - window_offset_x, view->y - window_offset_y, 0);  		break;  	}  	case SWAY_WL_SHELL_VIEW:  		render_wl_shell_surface(sway_view->wlr_wl_shell_surface, wlr_output, -			now, view->x, view->y, 0, false); +			when, view->x, view->y, 0, false);  		break;  	case SWAY_XWAYLAND_VIEW: -		render_surface(surface, wlr_output, now, view->x, view->y, 0); +		render_surface(surface, wlr_output, when, view->x, view->y, 0);  		break;  	default:  		break; @@ -192,82 +196,132 @@ static void render_layer(struct sway_output *output,  	}  } -static void output_frame_notify(struct wl_listener *listener, void *data) { -	struct sway_output *soutput = wl_container_of(listener, soutput, frame); -	struct wlr_output *wlr_output = data; -	struct sway_server *server = soutput->server; -	struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend); +static void render_output(struct sway_output *output, struct timespec *when, +		pixman_region32_t *damage) { +	struct wlr_output *wlr_output = output->wlr_output; +	struct wlr_renderer *renderer = +		wlr_backend_get_renderer(wlr_output->backend); + +	wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height); + +	if (!pixman_region32_not_empty(damage)) { +		// Output isn't damaged but needs buffer swap +		goto renderer_end; +	} -	int buffer_age = -1; -	wlr_output_make_current(wlr_output, &buffer_age); -	wlr_renderer_begin(server->renderer, wlr_output->width, wlr_output->height); +	// TODO: don't damage the whole output here +	int width, height; +	wlr_output_transformed_resolution(wlr_output, &width, &height); +	pixman_region32_union_rect(damage, damage, 0, 0, width, height);  	float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f};  	wlr_renderer_clear(renderer, clear_color); -	struct timespec now; -	clock_gettime(CLOCK_MONOTONIC, &now); -  	struct wlr_output_layout *layout = root_container.sway_root->output_layout; -	const struct wlr_box *output_box = wlr_output_layout_get_box( -			layout, wlr_output); +	const struct wlr_box *output_box = +			wlr_output_layout_get_box(layout, wlr_output); -	render_layer(soutput, output_box, &now, -			&soutput->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); -	render_layer(soutput, output_box, &now, -			&soutput->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); +	render_layer(output, output_box, when, +			&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); +	render_layer(output, output_box, when, +			&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]);  	struct sway_seat *seat = input_manager_current_seat(input_manager); -	struct sway_container *focus = sway_seat_get_focus_inactive(seat, soutput->swayc); +	struct sway_container *focus = +		sway_seat_get_focus_inactive(seat, output->swayc);  	struct sway_container *workspace = (focus->type == C_WORKSPACE ?  			focus :  			container_parent(focus, C_WORKSPACE));  	struct render_data rdata = { -		.output = soutput, -		.now = &now, +		.output = output, +		.when = when,  	}; -	container_descendants(workspace, C_VIEW, output_frame_view, &rdata); +	container_descendants(workspace, C_VIEW, render_view, &rdata);  	// render unmanaged views on top  	struct sway_view *view;  	wl_list_for_each(view, &root_container.sway_root->unmanaged_views,  			unmanaged_view_link) {  		if (view->type == SWAY_XWAYLAND_VIEW) { -			// the only kind of unamanged view right now is xwayland override redirect +			// the only kind of unamanged view right now is xwayland override +			// redirect  			int view_x = view->wlr_xwayland_surface->x;  			int view_y = view->wlr_xwayland_surface->y; -			render_surface(view->surface, wlr_output, &soutput->last_frame, +			render_surface(view->surface, wlr_output, &output->last_frame,  					view_x, view_y, 0);  		}  	}  	// TODO: Consider revising this when fullscreen windows are supported -	render_layer(soutput, output_box, &now, -			&soutput->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); -	render_layer(soutput, output_box, &now, -			&soutput->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); - -	wlr_renderer_end(server->renderer); -	wlr_output_swap_buffers(wlr_output, &now, NULL); -	soutput->last_frame = now; +	render_layer(output, output_box, when, +			&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); +	render_layer(output, output_box, when, +			&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); + +renderer_end: +	wlr_renderer_end(renderer); +	if (!wlr_output_damage_swap_buffers(output->damage, when, damage)) { +		return; +	} +	output->last_frame = *when;  } -static void handle_output_destroy(struct wl_listener *listener, void *data) { -	struct sway_output *output = wl_container_of(listener, output, destroy); -	struct wlr_output *wlr_output = data; -	wlr_log(L_DEBUG, "Output %p %s removed", wlr_output, wlr_output->name); +static void damage_handle_frame(struct wl_listener *listener, void *data) { +	struct sway_output *output = +		wl_container_of(listener, output, damage_frame); + +	if (!output->wlr_output->enabled) { +		return; +	} +	struct timespec now; +	clock_gettime(CLOCK_MONOTONIC, &now); + +	bool needs_swap; +	pixman_region32_t damage; +	pixman_region32_init(&damage); +	if (!wlr_output_damage_make_current(output->damage, &needs_swap, &damage)) { +		return; +	} + +	if (needs_swap) { +		render_output(output, &now, &damage); +	} + +	pixman_region32_fini(&damage); + +	// TODO: send frame done events here instead of inside render_surface +} + +void output_damage_whole(struct sway_output *output) { +	wlr_output_damage_add_whole(output->damage); +} + +void output_damage_whole_view(struct sway_output *output, +		struct sway_view *view) { +	// TODO +	output_damage_whole(output); +} + +static void damage_handle_destroy(struct wl_listener *listener, void *data) { +	struct sway_output *output = +		wl_container_of(listener, output, damage_destroy); +	container_output_destroy(output->swayc); +} + +static void handle_destroy(struct wl_listener *listener, void *data) { +	struct sway_output *output = wl_container_of(listener, output, destroy);  	container_output_destroy(output->swayc);  } -static void handle_output_mode(struct wl_listener *listener, void *data) { +static void handle_mode(struct wl_listener *listener, void *data) {  	struct sway_output *output = wl_container_of(listener, output, mode);  	arrange_layers(output);  	arrange_windows(output->swayc, -1, -1);  } -static void handle_output_transform(struct wl_listener *listener, void *data) { +static void handle_transform(struct wl_listener *listener, void *data) {  	struct sway_output *output = wl_container_of(listener, output, transform);  	arrange_layers(output);  	arrange_windows(output->swayc, -1, -1); @@ -292,6 +346,8 @@ void handle_new_output(struct wl_listener *listener, void *data) {  		wlr_output_set_mode(wlr_output, mode);  	} +	output->damage = wlr_output_damage_create(wlr_output); +  	output->swayc = container_output_create(output);  	if (!output->swayc) {  		free(output); @@ -305,14 +361,17 @@ void handle_new_output(struct wl_listener *listener, void *data) {  	sway_input_manager_configure_xcursor(input_manager); -	wl_signal_add(&wlr_output->events.frame, &output->frame); -	output->frame.notify = output_frame_notify;  	wl_signal_add(&wlr_output->events.destroy, &output->destroy); -	output->destroy.notify = handle_output_destroy; +	output->destroy.notify = handle_destroy;  	wl_signal_add(&wlr_output->events.mode, &output->mode); -	output->mode.notify = handle_output_mode; +	output->mode.notify = handle_mode;  	wl_signal_add(&wlr_output->events.transform, &output->transform); -	output->transform.notify = handle_output_transform; +	output->transform.notify = handle_transform; + +	wl_signal_add(&output->damage->events.frame, &output->damage_frame); +	output->damage_frame.notify = damage_handle_frame; +	wl_signal_add(&output->damage->events.destroy, &output->damage_destroy); +	output->damage_destroy.notify = damage_handle_destroy;  	arrange_layers(output);  	arrange_windows(&root_container, -1, -1); diff --git a/sway/desktop/wl_shell.c b/sway/desktop/wl_shell.c index 4d4d1ed7..4fcc6317 100644 --- a/sway/desktop/wl_shell.c +++ b/sway/desktop/wl_shell.c @@ -67,6 +67,7 @@ static void handle_commit(struct wl_listener *listener, void *data) {  	// TODO: Let floating views do whatever  	view->width = sway_surface->pending_width;  	view->height = sway_surface->pending_height; +	view_damage_from(view);  }  static void handle_destroy(struct wl_listener *listener, void *data) { diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index 25c0cbca..713437f2 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c @@ -76,6 +76,35 @@ static void handle_commit(struct wl_listener *listener, void *data) {  	// TODO: Let floating views do whatever  	view->width = sway_surface->pending_width;  	view->height = sway_surface->pending_height; +	view_damage_from(view); +} + +static void handle_unmap(struct wl_listener *listener, void *data) { +	struct sway_xdg_surface_v6 *sway_surface = +		wl_container_of(listener, sway_surface, unmap); +	view_damage_whole(sway_surface->view); +	container_view_destroy(sway_surface->view->swayc); +	sway_surface->view->swayc = NULL; +	sway_surface->view->surface = NULL; +} + +static void handle_map(struct wl_listener *listener, void *data) { +	struct sway_xdg_surface_v6 *sway_surface = +		wl_container_of(listener, sway_surface, map); +	struct sway_view *view = sway_surface->view; + +	sway_surface->view->surface = view->wlr_xdg_surface_v6->surface; + +	container_view_destroy(view->swayc); + +	struct sway_seat *seat = input_manager_current_seat(input_manager); +	struct sway_container *focus = sway_seat_get_focus_inactive(seat, &root_container); +	struct sway_container *cont = container_view_create(focus, view); +	view->swayc = cont; +	arrange_windows(cont->parent, -1, -1); +	sway_input_manager_set_focus(input_manager, cont); + +	view_damage_whole(sway_surface->view);  }  static void handle_destroy(struct wl_listener *listener, void *data) { @@ -83,10 +112,9 @@ static void handle_destroy(struct wl_listener *listener, void *data) {  		wl_container_of(listener, sway_xdg_surface, destroy);  	wl_list_remove(&sway_xdg_surface->commit.link);  	wl_list_remove(&sway_xdg_surface->destroy.link); -	struct sway_container *parent = container_view_destroy(sway_xdg_surface->view->swayc); +	container_view_destroy(sway_xdg_surface->view->swayc);  	free(sway_xdg_surface->view);  	free(sway_xdg_surface); -	arrange_windows(parent, -1, -1);  }  void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { @@ -122,26 +150,22 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) {  	sway_view->iface.close = close;  	sway_view->wlr_xdg_surface_v6 = xdg_surface;  	sway_view->sway_xdg_surface_v6 = sway_surface; -	sway_view->surface = xdg_surface->surface;  	sway_surface->view = sway_view; -	 +  	// TODO:  	// - Look up pid and open on appropriate workspace  	// - Set new view to maximized so it behaves nicely  	// - Criteria -	 +  	sway_surface->commit.notify = handle_commit;  	wl_signal_add(&xdg_surface->surface->events.commit, &sway_surface->commit); -	sway_surface->destroy.notify = handle_destroy; -	wl_signal_add(&xdg_surface->events.destroy, &sway_surface->destroy); +	sway_surface->map.notify = handle_map; +	wl_signal_add(&xdg_surface->events.map, &sway_surface->map); -	struct sway_seat *seat = input_manager_current_seat(input_manager); -	struct sway_container *focus = sway_seat_get_focus_inactive(seat, &root_container); -	struct sway_container *cont = container_view_create(focus, sway_view); -	sway_view->swayc = cont; - -	arrange_windows(cont->parent, -1, -1); +	sway_surface->unmap.notify = handle_unmap; +	wl_signal_add(&xdg_surface->events.unmap, &sway_surface->unmap); -	sway_input_manager_set_focus(input_manager, cont); +	sway_surface->destroy.notify = handle_destroy; +	wl_signal_add(&xdg_surface->events.destroy, &sway_surface->destroy);  } diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 38ee4656..01c993b3 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -14,10 +14,10 @@  #include "sway/input/input-manager.h"  #include "log.h" - static bool assert_xwayland(struct sway_view *view) { -	 return sway_assert(view->type == SWAY_XWAYLAND_VIEW && view->wlr_xwayland_surface, -		 "Expected xwayland view!"); - } +static bool assert_xwayland(struct sway_view *view) { +	return sway_assert(view->type == SWAY_XWAYLAND_VIEW, +		"Expected xwayland view!"); +}  static const char *get_prop(struct sway_view *view, enum sway_view_prop prop) {  	if (!assert_xwayland(view)) { @@ -99,73 +99,59 @@ static void handle_commit(struct wl_listener *listener, void *data) {  	// TODO: Let floating views do whatever  	view->width = sway_surface->pending_width;  	view->height = sway_surface->pending_height; +	view_damage_from(view);  }  static void handle_destroy(struct wl_listener *listener, void *data) {  	struct sway_xwayland_surface *sway_surface =  		wl_container_of(listener, sway_surface, destroy); -	struct wlr_xwayland_surface *xsurface = data; +  	wl_list_remove(&sway_surface->commit.link);  	wl_list_remove(&sway_surface->destroy.link);  	wl_list_remove(&sway_surface->request_configure.link); -	if (xsurface->override_redirect && xsurface->mapped) { -		wl_list_remove(&sway_surface->view->unmanaged_view_link); -		wl_list_init(&sway_surface->view->unmanaged_view_link); -	} - -	struct sway_container *parent = container_view_destroy(sway_surface->view->swayc); -	if (parent) { -		arrange_windows(parent, -1, -1); -	} - -	free(sway_surface->view); -	free(sway_surface); +	wl_list_remove(&sway_surface->view->unmanaged_view_link); +	container_view_destroy(sway_surface->view->swayc); +	sway_surface->view->swayc = NULL; +	sway_surface->view->surface = NULL;  } -static void handle_unmap_notify(struct wl_listener *listener, void *data) { +static void handle_unmap(struct wl_listener *listener, void *data) {  	struct sway_xwayland_surface *sway_surface = -		wl_container_of(listener, sway_surface, unmap_notify); -	struct wlr_xwayland_surface *xsurface = data; -	if (xsurface->override_redirect && xsurface->mapped) { -		wl_list_remove(&sway_surface->view->unmanaged_view_link); -		wl_list_init(&sway_surface->view->unmanaged_view_link); -	} - -	// take it out of the tree -	struct sway_container *parent = container_view_destroy(sway_surface->view->swayc); -	if (parent) { -		arrange_windows(parent, -1, -1); -	} - +		wl_container_of(listener, sway_surface, unmap); +	view_damage_whole(sway_surface->view); +	wl_list_remove(&sway_surface->view->unmanaged_view_link); +	wl_list_init(&sway_surface->view->unmanaged_view_link); +	container_view_destroy(sway_surface->view->swayc);  	sway_surface->view->swayc = NULL;  	sway_surface->view->surface = NULL;  } -static void handle_map_notify(struct wl_listener *listener, void *data) { -	// TODO put the view back into the tree +static void handle_map(struct wl_listener *listener, void *data) {  	struct sway_xwayland_surface *sway_surface = -		wl_container_of(listener, sway_surface, map_notify); +		wl_container_of(listener, sway_surface, map);  	struct wlr_xwayland_surface *xsurface = data;  	sway_surface->view->surface = xsurface->surface;  	// put it back into the tree -	if (xsurface->override_redirect) { +	if (wlr_xwayland_surface_is_unmanaged(xsurface) || +			xsurface->override_redirect) { +		wl_list_remove(&sway_surface->view->unmanaged_view_link);  		wl_list_insert(&root_container.sway_root->unmanaged_views,  			&sway_surface->view->unmanaged_view_link);  	} else {  		struct sway_view *view = sway_surface->view;  		container_view_destroy(view->swayc); -		struct sway_container *parent = root_container.children->items[0]; -		parent = parent->children->items[0]; // workspace - -		struct sway_container *cont = container_view_create(parent, view); +		struct sway_seat *seat = input_manager_current_seat(input_manager); +		struct sway_container *focus = sway_seat_get_focus_inactive(seat, &root_container); +		struct sway_container *cont = container_view_create(focus, view);  		view->swayc = cont; -  		arrange_windows(cont->parent, -1, -1);  		sway_input_manager_set_focus(input_manager, cont);  	} + +	view_damage_whole(sway_surface->view);  }  static void handle_configure_request(struct wl_listener *listener, void *data) { @@ -206,9 +192,10 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) {  	sway_view->iface.close = close_view;  	sway_view->wlr_xwayland_surface = xsurface;  	sway_view->sway_xwayland_surface = sway_surface; -	sway_view->surface = xsurface->surface;  	sway_surface->view = sway_view; +	wl_list_init(&sway_view->unmanaged_view_link); +  	// TODO:  	// - Look up pid and open on appropriate workspace  	// - Set new view to maximized so it behaves nicely @@ -224,24 +211,11 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) {  		&sway_surface->request_configure);  	sway_surface->request_configure.notify = handle_configure_request; -	wl_signal_add(&xsurface->events.unmap_notify, &sway_surface->unmap_notify); -	sway_surface->unmap_notify.notify = handle_unmap_notify; - -	wl_signal_add(&xsurface->events.map_notify, &sway_surface->map_notify); -	sway_surface->map_notify.notify = handle_map_notify; - -	if (wlr_xwayland_surface_is_unmanaged(xsurface)) { -		// these don't get a container in the tree -		wl_list_insert(&root_container.sway_root->unmanaged_views, -			&sway_view->unmanaged_view_link); -		return; -	} +	wl_signal_add(&xsurface->events.unmap, &sway_surface->unmap); +	sway_surface->unmap.notify = handle_unmap; -	struct sway_seat *seat = input_manager_current_seat(input_manager); -	struct sway_container *focus = sway_seat_get_focus_inactive(seat, &root_container); -	struct sway_container *cont = container_view_create(focus, sway_view); -	sway_view->swayc = cont; +	wl_signal_add(&xsurface->events.map, &sway_surface->map); +	sway_surface->map.notify = handle_map; -	arrange_windows(cont->parent, -1, -1); -	sway_input_manager_set_focus(input_manager, cont); +	handle_map(&sway_surface->map, xsurface);  } diff --git a/sway/input/cursor.c b/sway/input/cursor.c index cded0005..d814e08e 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -6,10 +6,11 @@  #endif  #include <wlr/types/wlr_cursor.h>  #include <wlr/types/wlr_xcursor_manager.h> -#include "sway/input/cursor.h" -#include "sway/tree/view.h"  #include "list.h"  #include "log.h" +#include "sway/input/cursor.h" +#include "sway/output.h" +#include "sway/tree/view.h"  static void cursor_update_position(struct sway_cursor *cursor) {  	double x = cursor->cursor->x; @@ -19,18 +20,16 @@ static void cursor_update_position(struct sway_cursor *cursor) {  	cursor->y = y;  } -static void cursor_send_pointer_motion(struct sway_cursor *cursor, -		uint32_t time) { -	struct wlr_seat *seat = cursor->seat->wlr_seat; -	struct wlr_surface *surface = NULL; -	double sx, sy; - -	struct sway_container *focus = NULL; - +/** + * Returns the container at the cursor's position. If the container is a view, + * stores the surface at the cursor's position in `*surface`. + */ +static struct sway_container *container_at_cursor(struct sway_cursor *cursor, +		struct wlr_surface **surface, double *sx, double *sy) {  	// check for unmanaged views first +	struct wl_list *unmanaged = &root_container.sway_root->unmanaged_views;  	struct sway_view *view; -	wl_list_for_each_reverse(view, &root_container.sway_root->unmanaged_views, -			unmanaged_view_link) { +	wl_list_for_each_reverse(view, unmanaged, unmanaged_view_link) {  		if (view->type == SWAY_XWAYLAND_VIEW) {  			struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;  			struct wlr_box box = { @@ -41,24 +40,50 @@ static void cursor_send_pointer_motion(struct sway_cursor *cursor,  			};  			if (wlr_box_contains_point(&box, cursor->x, cursor->y)) { -				focus = view->swayc; -				surface = xsurface->surface; -				sx = cursor->x - box.x; -				sy = cursor->y - box.y; -				break; +				*surface = xsurface->surface; +				*sx = cursor->x - box.x; +				*sy = cursor->y - box.y; +				return view->swayc;  			}  		}  	} -	// then check for managed views -	if (focus == NULL) { -		focus = container_at(&root_container, cursor->x, cursor->y, &surface, -			&sx, &sy); +	// 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, cursor->x, cursor->y); +	if (wlr_output == NULL) { +		return NULL; +	} +	struct sway_output *output = wlr_output->data; + +	// find the focused workspace on the output for this seat +	struct sway_container *workspace_cont = +		sway_seat_get_focus_inactive(cursor->seat, output->swayc); +	if (workspace_cont != NULL && workspace_cont->type != C_WORKSPACE) { +		workspace_cont = container_parent(workspace_cont, C_WORKSPACE); +	} +	if (workspace_cont == NULL) { +		return output->swayc;  	} +	struct sway_container *view_cont = container_at(workspace_cont, +		cursor->x, cursor->y, surface, sx, sy); +	return view_cont != NULL ? view_cont : workspace_cont; +} + +static void cursor_send_pointer_motion(struct sway_cursor *cursor, +		uint32_t time) { +	struct wlr_seat *seat = cursor->seat->wlr_seat; +	struct wlr_surface *surface = NULL; +	double sx, sy; +	struct sway_container *cont = +		container_at_cursor(cursor, &surface, &sx, &sy); +  	// reset cursor if switching between clients  	struct wl_client *client = NULL; -	if (focus) { +	if (surface != NULL) {  		client = wl_resource_get_client(surface->resource);  	}  	if (client != cursor->image_client) { @@ -68,7 +93,7 @@ static void cursor_send_pointer_motion(struct sway_cursor *cursor,  	}  	// send pointer enter/leave -	if (focus) { +	if (cont != NULL && surface != NULL) {  		wlr_seat_pointer_notify_enter(seat, surface, sx, sy);  		wlr_seat_pointer_notify_motion(seat, time, sx, sy);  	} else { @@ -77,8 +102,7 @@ static void cursor_send_pointer_motion(struct sway_cursor *cursor,  }  static void handle_cursor_motion(struct wl_listener *listener, void *data) { -	struct sway_cursor *cursor = -		wl_container_of(listener, cursor, motion); +	struct sway_cursor *cursor = wl_container_of(listener, cursor, motion);  	struct wlr_event_pointer_motion *event = data;  	wlr_cursor_move(cursor->cursor, event->device,  		event->delta_x, event->delta_y); @@ -97,17 +121,15 @@ static void handle_cursor_motion_absolute(struct wl_listener *listener,  }  static void handle_cursor_button(struct wl_listener *listener, void *data) { -	struct sway_cursor *cursor = -		wl_container_of(listener, cursor, button); +	struct sway_cursor *cursor = wl_container_of(listener, cursor, button);  	struct wlr_event_pointer_button *event = data;  	if (event->button == BTN_LEFT) {  		struct wlr_surface *surface = NULL;  		double sx, sy; -		struct sway_container *swayc = -			container_at(&root_container, cursor->x, cursor->y, &surface, &sx, &sy); - -		sway_seat_set_focus(cursor->seat, swayc); +		struct sway_container *cont = +			container_at_cursor(cursor, &surface, &sx, &sy); +		sway_seat_set_focus(cursor->seat, cont);  	}  	wlr_seat_pointer_notify_button(cursor->seat->wlr_seat, event->time_msec, @@ -115,23 +137,20 @@ static void handle_cursor_button(struct wl_listener *listener, void *data) {  }  static void handle_cursor_axis(struct wl_listener *listener, void *data) { -	struct sway_cursor *cursor = -		wl_container_of(listener, cursor, axis); +	struct sway_cursor *cursor = wl_container_of(listener, cursor, axis);  	struct wlr_event_pointer_axis *event = data;  	wlr_seat_pointer_notify_axis(cursor->seat->wlr_seat, event->time_msec,  		event->orientation, event->delta);  }  static void handle_touch_down(struct wl_listener *listener, void *data) { -	struct sway_cursor *cursor = -		wl_container_of(listener, cursor, touch_down); +	struct sway_cursor *cursor = wl_container_of(listener, cursor, touch_down);  	struct wlr_event_touch_down *event = data;  	wlr_log(L_DEBUG, "TODO: handle touch down event: %p", event);  }  static void handle_touch_up(struct wl_listener *listener, void *data) { -	struct sway_cursor *cursor = -		wl_container_of(listener, cursor, touch_up); +	struct sway_cursor *cursor = wl_container_of(listener, cursor, touch_up);  	struct wlr_event_touch_up *event = data;  	wlr_log(L_DEBUG, "TODO: handle touch up event: %p", event);  } @@ -144,15 +163,13 @@ static void handle_touch_motion(struct wl_listener *listener, void *data) {  }  static void handle_tool_axis(struct wl_listener *listener, void *data) { -	struct sway_cursor *cursor = -		wl_container_of(listener, cursor, tool_axis); +	struct sway_cursor *cursor = wl_container_of(listener, cursor, tool_axis);  	struct wlr_event_tablet_tool_axis *event = data;  	wlr_log(L_DEBUG, "TODO: handle tool axis event: %p", event);  }  static void handle_tool_tip(struct wl_listener *listener, void *data) { -	struct sway_cursor *cursor = -		wl_container_of(listener, cursor, tool_tip); +	struct sway_cursor *cursor = wl_container_of(listener, cursor, tool_tip);  	struct wlr_event_tablet_tool_tip *event = data;  	wlr_log(L_DEBUG, "TODO: handle tool tip event: %p", event);  } diff --git a/sway/input/seat.c b/sway/input/seat.c index 7cf0dd08..ae536264 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -8,6 +8,7 @@  #include "sway/input/keyboard.h"  #include "sway/ipc-server.h"  #include "sway/output.h" +#include "sway/tree/container.h"  #include "sway/tree/view.h"  #include "log.h" @@ -331,6 +332,9 @@ void sway_seat_set_focus(struct sway_seat *seat, struct sway_container *containe  		if (last_ws) {  			wlr_log(L_DEBUG, "sending workspace event");  			ipc_event_workspace(last_ws, container, "focus"); +			if (last_ws->children->length == 0) { +				container_workspace_destroy(last_ws); +			}  		}  	} diff --git a/sway/ipc-json.c b/sway/ipc-json.c index eab6399f..7c5f7304 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c @@ -66,19 +66,42 @@ static const char *ipc_json_get_output_transform(enum wl_output_transform transf  static void ipc_json_describe_output(struct sway_container *container, json_object *object) {  	struct wlr_output *wlr_output = container->sway_output->wlr_output; -	json_object_object_add(object, "type", json_object_new_string("output")); -	json_object_object_add(object, "active", json_object_new_boolean(true)); -	json_object_object_add(object, "primary", json_object_new_boolean(false)); -	json_object_object_add(object, "layout", json_object_new_string("output")); -	json_object_object_add(object, "make", json_object_new_string(wlr_output->make)); -	json_object_object_add(object, "model", json_object_new_string(wlr_output->model)); -	json_object_object_add(object, "serial", json_object_new_string(wlr_output->serial)); -	json_object_object_add(object, "scale", json_object_new_double(wlr_output->scale)); -	json_object_object_add(object, "refresh", json_object_new_int(wlr_output->refresh)); +	json_object_object_add(object, "type", +			json_object_new_string("output")); +	json_object_object_add(object, "active", +			json_object_new_boolean(true)); +	json_object_object_add(object, "primary", +			json_object_new_boolean(false)); +	json_object_object_add(object, "layout", +			json_object_new_string("output")); +	json_object_object_add(object, "make", +			json_object_new_string(wlr_output->make)); +	json_object_object_add(object, "model", +			json_object_new_string(wlr_output->model)); +	json_object_object_add(object, "serial", +			json_object_new_string(wlr_output->serial)); +	json_object_object_add(object, "scale", +			json_object_new_double(wlr_output->scale)); +	json_object_object_add(object, "refresh", +			json_object_new_int(wlr_output->refresh));  	json_object_object_add(object, "transform", -		json_object_new_string(ipc_json_get_output_transform(wlr_output->transform))); -	// TODO WLR need to set "current_workspace" to the currently focused -	// workspace in a way that makes sense with multiseat +		json_object_new_string( +			ipc_json_get_output_transform(wlr_output->transform))); + +	struct sway_seat *seat = sway_input_manager_get_default_seat(input_manager); +	const char *ws = NULL; +	if (seat) { +		struct sway_container *focus = +			sway_seat_get_focus_inactive(seat, container); +		if (focus && focus->type != C_WORKSPACE) { +			focus = container_parent(focus, C_WORKSPACE); +		} +		if (focus) { +			ws = focus->name; +		} +	} +	json_object_object_add(object, "current_workspace", +			json_object_new_string(ws));  	json_object *modes_array = json_object_new_array();  	struct wlr_output_mode *mode; @@ -95,16 +118,20 @@ static void ipc_json_describe_output(struct sway_container *container, json_obje  	json_object_object_add(object, "modes", modes_array);  } -static void ipc_json_describe_workspace(struct sway_container *workspace, json_object *object) { -	int num = (isdigit(workspace->name[0])) ? atoi(workspace->name) : -1; +static void ipc_json_describe_workspace(struct sway_container *workspace, +		json_object *object) { +	int num = isdigit(workspace->name[0]) ? atoi(workspace->name) : -1;  	json_object_object_add(object, "num", json_object_new_int(num)); -	json_object_object_add(object, "output", (workspace->parent) ? json_object_new_string(workspace->parent->name) : NULL); +	json_object_object_add(object, "output", workspace->parent ? +			json_object_new_string(workspace->parent->name) : NULL);  	json_object_object_add(object, "type", json_object_new_string("workspace")); +	json_object_object_add(object, "urgent", json_object_new_boolean(false));  }  static void ipc_json_describe_view(struct sway_container *c, json_object *object) { -	json_object_object_add(object, "name", (c->name) ? json_object_new_string(c->name) : NULL); +	json_object_object_add(object, "name", +			c->name ? json_object_new_string(c->name) : NULL);  }  json_object *ipc_json_describe_container(struct sway_container *c) { @@ -118,28 +145,26 @@ json_object *ipc_json_describe_container(struct sway_container *c) {  	json_object *object = json_object_new_object();  	json_object_object_add(object, "id", json_object_new_int((int)c->id)); -	json_object_object_add(object, "name", (c->name) ? json_object_new_string(c->name) : NULL); +	json_object_object_add(object, "name", +			c->name ? json_object_new_string(c->name) : NULL);  	json_object_object_add(object, "rect", ipc_json_create_rect(c)); -	json_object_object_add(object, "focused", json_object_new_boolean(focused)); +	json_object_object_add(object, "focused", +			json_object_new_boolean(focused));  	switch (c->type) {  	case C_ROOT:  		ipc_json_describe_root(c, object);  		break; -  	case C_OUTPUT:  		ipc_json_describe_output(c, object);  		break; -  	case C_CONTAINER:  	case C_VIEW:  		ipc_json_describe_view(c, object);  		break; -  	case C_WORKSPACE:  		ipc_json_describe_workspace(c, object);  		break; -  	case C_TYPES:  	default:  		break; diff --git a/sway/ipc-server.c b/sway/ipc-server.c index 394161af..869f1ed0 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c @@ -390,7 +390,7 @@ static void ipc_get_workspaces_callback(struct sway_container *workspace,  	struct sway_seat *seat =  		sway_input_manager_get_default_seat(input_manager);  	struct sway_container *focused_ws = sway_seat_get_focus(seat); -	if (focused_ws->type != C_WORKSPACE) { +	if (focused_ws != NULL && focused_ws->type != C_WORKSPACE) {  		focused_ws = container_parent(focused_ws, C_WORKSPACE);  	}  	bool focused = workspace == focused_ws; @@ -398,6 +398,14 @@ static void ipc_get_workspaces_callback(struct sway_container *workspace,  	json_object_object_add(workspace_json, "focused",  			json_object_new_boolean(focused));  	json_object_array_add((json_object *)data, workspace_json); + +	focused_ws = sway_seat_get_focus_inactive(seat, workspace->parent); +	if (focused_ws->type != C_WORKSPACE) { +		focused_ws = container_parent(focused_ws, C_WORKSPACE); +	} +	bool visible = workspace == focused_ws; +	json_object_object_add(workspace_json, "visible", +			json_object_new_boolean(visible));  }  void ipc_client_handle_command(struct ipc_client *client) { diff --git a/sway/meson.build b/sway/meson.build index 1e7ee7ae..e8a192f0 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -8,6 +8,7 @@ sway_sources = files(  	'input/keyboard.c',  	'commands/bar.c',  	'commands/bind.c', +	'commands/default_orientation.c',  	'commands/exit.c',  	'commands/exec.c',  	'commands/exec_always.c', @@ -81,6 +82,7 @@ sway_sources = files(  	'security.c',  	'tree/container.c',  	'tree/layout.c', +	'tree/output.c',  	'tree/view.c',  	'tree/workspace.c',  ) diff --git a/sway/server.c b/sway/server.c index 3fba019d..728e624e 100644 --- a/sway/server.c +++ b/sway/server.c @@ -1,19 +1,19 @@  #define _POSIX_C_SOURCE 200112L -#include <stdlib.h> +#include <assert.h>  #include <stdbool.h> +#include <stdlib.h>  #include <wayland-server.h>  #include <wlr/backend.h>  #include <wlr/backend/session.h>  #include <wlr/render/wlr_renderer.h> -#include <wlr/render/gles2.h>  #include <wlr/types/wlr_compositor.h> +#include <wlr/types/wlr_gamma_control.h>  #include <wlr/types/wlr_layer_shell.h>  #include <wlr/types/wlr_screenshooter.h> -#include <wlr/types/wlr_gamma_control.h>  #include <wlr/types/wlr_wl_shell.h> +#include <wlr/util/log.h>  // TODO WLR: make Xwayland optional  #include <wlr/xwayland.h> -#include <wlr/util/log.h>  #include "sway/commands.h"  #include "sway/config.h"  #include "sway/server.h" @@ -42,11 +42,12 @@ bool server_init(struct sway_server *server) {  	server->wl_event_loop = wl_display_get_event_loop(server->wl_display);  	server->backend = wlr_backend_autocreate(server->wl_display); -	server->renderer = wlr_gles2_renderer_create(server->backend); +	struct wlr_renderer *renderer = wlr_backend_get_renderer(server->backend); +	assert(renderer); +  	wl_display_init_shm(server->wl_display); -	server->compositor = wlr_compositor_create( -			server->wl_display, server->renderer); +	server->compositor = wlr_compositor_create(server->wl_display, renderer);  	server->data_device_manager =  		wlr_data_device_manager_create(server->wl_display); @@ -95,8 +96,7 @@ bool server_init(struct sway_server *server) {  }  void server_fini(struct sway_server *server) { -	// TODO WLR: tear down more stuff -	wlr_backend_destroy(server->backend); +	// TODO  }  void server_run(struct sway_server *server) { diff --git a/sway/tree/container.c b/sway/tree/container.c index 2eac812e..8705edc7 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -6,16 +6,16 @@  #include <wayland-server.h>  #include <wlr/types/wlr_output_layout.h>  #include <wlr/types/wlr_wl_shell.h> +#include "log.h"  #include "sway/config.h" -#include "sway/tree/container.h"  #include "sway/input/input-manager.h"  #include "sway/input/seat.h" -#include "sway/tree/layout.h" +#include "sway/ipc-server.h"  #include "sway/output.h"  #include "sway/server.h" +#include "sway/tree/layout.h"  #include "sway/tree/view.h"  #include "sway/tree/workspace.h" -#include "sway/ipc-server.h"  #include "log.h"  static list_t *bfs_queue; @@ -58,13 +58,14 @@ static struct sway_container *container_create(enum sway_container_type type) {  	return c;  } -static void container_destroy(struct sway_container *cont) { +struct sway_container *container_destroy(struct sway_container *cont) {  	if (cont == NULL) { -		return; +		return NULL;  	}  	wl_signal_emit(&cont->events.destroy, cont); +	struct sway_container *parent = cont->parent;  	if (cont->children) {  		// remove children until there are no more, container_destroy calls  		// container_remove_child, which removes child from this container @@ -77,13 +78,14 @@ static void container_destroy(struct sway_container *cont) {  		list_foreach(cont->marks, free);  		list_free(cont->marks);  	} -	if (cont->parent) { -		container_remove_child(cont); +	if (parent) { +		parent = container_remove_child(cont);  	}  	if (cont->name) {  		free(cont->name);  	}  	free(cont); +	return parent;  }  struct sway_container *container_output_create( @@ -202,57 +204,6 @@ struct sway_container *container_view_create(struct sway_container *sibling,  	return swayc;  } -struct sway_container *container_output_destroy(struct sway_container *output) { -	if (!sway_assert(output, -				"null output passed to container_output_destroy")) { -		return NULL; -	} - -	if (output->children->length > 0) { -		// TODO save workspaces when there are no outputs. -		// TODO also check if there will ever be no outputs except for exiting -		// program -		if (root_container.children->length > 1) { -			int p = root_container.children->items[0] == output; -			// Move workspace from this output to another output -			while (output->children->length) { -				struct sway_container *child = output->children->items[0]; -				container_remove_child(child); -				container_add_child(root_container.children->items[p], child); -			} -			container_sort_workspaces(root_container.children->items[p]); -			arrange_windows(root_container.children->items[p], -				-1, -1); -		} -	} - -	wl_list_remove(&output->sway_output->frame.link); -	wl_list_remove(&output->sway_output->destroy.link); -	wl_list_remove(&output->sway_output->mode.link); - -	wlr_log(L_DEBUG, "OUTPUT: Destroying output '%s'", output->name); -	container_destroy(output); - -	return &root_container; -} - -struct sway_container *container_view_destroy(struct sway_container *view) { -	if (!view) { -		return NULL; -	} -	wlr_log(L_DEBUG, "Destroying view '%s'", view->name); -	struct sway_container *parent = view->parent; -	container_destroy(view); - -	// TODO WLR: Destroy empty containers -	/* -	if (parent && parent->type == C_CONTAINER) { -		return destroy_container(parent); -	} -	*/ -	return parent; -} -  struct sway_container *container_set_layout(struct sway_container *container,  		enum sway_container_layout layout) {  	if (container->type == C_WORKSPACE) { @@ -438,3 +389,14 @@ void container_for_each_descendant_bfs(struct sway_container *con,  		list_cat(queue, current->children);  	}  } + +bool container_has_anscestor(struct sway_container *descendant, +		struct sway_container *anscestor) { +	while (descendant->type != C_ROOT) { +		descendant = descendant->parent; +		if (descendant == anscestor) { +			return true; +		} +	} +	return false; +} diff --git a/sway/tree/layout.c b/sway/tree/layout.c index dc0ee5b4..588ceb2d 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c @@ -9,8 +9,10 @@  #include "sway/tree/container.h"  #include "sway/tree/layout.h"  #include "sway/output.h" +#include "sway/tree/workspace.h"  #include "sway/tree/view.h"  #include "sway/input/seat.h" +#include "sway/ipc-server.h"  #include "list.h"  #include "log.h" @@ -98,37 +100,67 @@ void container_add_child(struct sway_container *parent,  			parent, parent->type, parent->width, parent->height);  	list_add(parent->children, child);  	child->parent = parent; -	// set focus for this container -	/* TODO WLR -	if (parent->type == C_WORKSPACE && child->type == C_VIEW && -	(parent->workspace_layout == L_TABBED || parent->workspace_layout == -	L_STACKED)) { -		child = new_container(child, parent->workspace_layout); +} + +struct sway_container *container_reap_empty(struct sway_container *container) { +	if (!sway_assert(container, "reaping null container")) { +		return NULL;  	} -	*/ +	wlr_log(L_DEBUG, "reaping %p %s", container, container->name); +	while (container->children->length == 0) { +		if (container->type == C_WORKSPACE) { +			if (!workspace_is_visible(container)) { +				struct sway_container *parent = container->parent; +				container_workspace_destroy(container); +				return parent; +			} +			return container; +		} else if (container->type == C_CONTAINER) { +			struct sway_container *parent = container->parent; +			container_destroy(container); +			container = parent; +		} else { +			container = container->parent; +		} +	} +	return container;  }  struct sway_container *container_remove_child(struct sway_container *child) { -	int i;  	struct sway_container *parent = child->parent; -	for (i = 0; i < parent->children->length; ++i) { +	for (int i = 0; i < parent->children->length; ++i) {  		if (parent->children->items[i] == child) {  			list_del(parent->children, i);  			break;  		}  	}  	child->parent = NULL; -	return parent; +	return container_reap_empty(parent); +} + +void container_move_to(struct sway_container* container, +		struct sway_container* destination) { +	if (container == destination +			|| container_has_anscestor(container, destination)) { +		return; +	} +	struct sway_container *old_parent = container_remove_child(container); +	container->width = container->height = 0; +	struct sway_container *new_parent = +		container_add_sibling(destination, container); +	if (old_parent) { +		arrange_windows(old_parent, -1, -1); +	} +	arrange_windows(new_parent, -1, -1);  }  enum sway_container_layout container_get_default_layout(  		struct sway_container *output) { -	/* TODO WLR  	if (config->default_layout != L_NONE) { -		//return config->default_layout; +		return config->default_layout;  	} else if (config->default_orientation != L_NONE) {  		return config->default_orientation; -	} else */if (output->width >= output->height) { +	} else if (output->width >= output->height) {  		return L_HORIZ;  	} else {  		return L_VERT; diff --git a/sway/tree/output.c b/sway/tree/output.c new file mode 100644 index 00000000..7248fd00 --- /dev/null +++ b/sway/tree/output.c @@ -0,0 +1,39 @@ +#include "sway/tree/container.h" +#include "sway/tree/layout.h" +#include "sway/output.h" +#include "log.h" + +struct sway_container *container_output_destroy(struct sway_container *output) { +	if (!sway_assert(output, "cannot destroy null output")) { +		return NULL; +	} + +	if (output->children->length > 0) { +		// TODO save workspaces when there are no outputs. +		// TODO also check if there will ever be no outputs except for exiting +		// program +		if (root_container.children->length > 1) { +			int p = root_container.children->items[0] == output; +			// Move workspace from this output to another output +			while (output->children->length) { +				struct sway_container *child = output->children->items[0]; +				container_remove_child(child); +				container_add_child(root_container.children->items[p], child); +			} +			container_sort_workspaces(root_container.children->items[p]); +			arrange_windows(root_container.children->items[p], +				-1, -1); +		} +	} + +	wl_list_remove(&output->sway_output->destroy.link); +	wl_list_remove(&output->sway_output->mode.link); +	wl_list_remove(&output->sway_output->transform.link); + +	wl_list_remove(&output->sway_output->damage_destroy.link); +	wl_list_remove(&output->sway_output->damage_frame.link); + +	wlr_log(L_DEBUG, "OUTPUT: Destroying output '%s'", output->name); +	container_destroy(output); +	return &root_container; +} diff --git a/sway/tree/view.c b/sway/tree/view.c index d5325c31..b7d1a41b 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -1,5 +1,7 @@  #include <wayland-server.h>  #include <wlr/types/wlr_output_layout.h> +#include "log.h" +#include "sway/output.h"  #include "sway/tree/container.h"  #include "sway/tree/layout.h"  #include "sway/tree/view.h" @@ -94,3 +96,28 @@ void view_update_outputs(struct sway_view *view, const struct wlr_box *before) {  		}  	}  } + +struct sway_container *container_view_destroy(struct sway_container *view) { +	if (!view) { +		return NULL; +	} +	wlr_log(L_DEBUG, "Destroying view '%s'", view->name); +	struct sway_container *parent = container_destroy(view); +	arrange_windows(parent, -1, -1); +	return parent; +} + +void view_damage_whole(struct sway_view *view) { +	struct sway_container *cont = NULL; +	for (int i = 0; i < root_container.children->length; ++i) { +		cont = root_container.children->items[i]; +		if (cont->type == C_OUTPUT) { +			output_damage_whole_view(cont->sway_output, view); +		} +	} +} + +void view_damage_from(struct sway_view *view) { +	// TODO +	view_damage_whole(view); +} diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index 5800ea09..c629f1f1 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c @@ -6,9 +6,10 @@  #include <stdio.h>  #include <strings.h>  #include "stringop.h" -#include "sway/tree/container.h"  #include "sway/input/input-manager.h"  #include "sway/input/seat.h" +#include "sway/ipc-server.h" +#include "sway/tree/container.h"  #include "sway/tree/workspace.h"  #include "log.h"  #include "util.h" @@ -202,7 +203,48 @@ struct sway_container *workspace_create(const char *name) {  		sway_seat_get_focus_inactive(seat, &root_container);  	parent = focus;  	parent = container_parent(parent, C_OUTPUT); -	return container_workspace_create(parent, name); +	struct sway_container *new_ws = container_workspace_create(parent, name); +	ipc_event_workspace(NULL, new_ws, "init"); +	return new_ws; +} + +struct sway_container *container_workspace_destroy( +		struct sway_container *workspace) { +	if (!sway_assert(workspace, "cannot destroy null workspace")) { +		return NULL; +	} + +	// Do not destroy this if it's the last workspace on this output +	struct sway_container *output = container_parent(workspace, C_OUTPUT); +	if (output && output->children->length == 1) { +		return NULL; +	} + +	struct sway_container *parent = workspace->parent; +	if (workspace->children->length == 0) { +		// destroy the WS if there are no children (TODO check for floating) +		wlr_log(L_DEBUG, "destroying workspace '%s'", workspace->name); +		ipc_event_workspace(workspace, NULL, "empty"); +	} else { +		// Move children to a different workspace on this output +		struct sway_container *new_workspace = NULL; +		// TODO move floating +		for (int i = 0; i < output->children->length; i++) { +			if (output->children->items[i] != workspace) { +				new_workspace = output->children->items[i]; +				break; +			} +		} + +		wlr_log(L_DEBUG, "moving children to different workspace '%s' -> '%s'", +			workspace->name, new_workspace->name); +		for (int i = 0; i < workspace->children->length; i++) { +			container_move_to(workspace->children->items[i], new_workspace); +		} +	} + +	container_destroy(workspace); +	return parent;  }  /** @@ -343,3 +385,13 @@ bool workspace_switch(struct sway_container *workspace) {  	arrange_windows(output, -1, -1);  	return true;  } + +bool workspace_is_visible(struct sway_container *ws) { +	struct sway_container *output = container_parent(ws, C_OUTPUT); +	struct sway_seat *seat = input_manager_current_seat(input_manager); +	struct sway_container *focus = sway_seat_get_focus_inactive(seat, output); +	if (focus->type != C_WORKSPACE) { +		focus = container_parent(focus, C_WORKSPACE); +	} +	return focus == ws; +}  | 
