diff options
| author | Drew DeVault <sir@cmpwn.com> | 2018-07-24 14:44:01 -0400 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-07-24 14:44:01 -0400 | 
| commit | 817d37c95032946a2e508fcc33cfa5c7ed65cc0d (patch) | |
| tree | 69fb79348eaff481fabaee4c2bb25991487d438b /sway | |
| parent | 347f7cb4c1edb3c4a6c38ffb3f9dcdd98f37e475 (diff) | |
| parent | c80258c3b394781c42cd4f2c161c705b2558c485 (diff) | |
| download | sway-817d37c95032946a2e508fcc33cfa5c7ed65cc0d.tar.xz | |
Merge pull request #2165 from swaywm/pid-workspaces
Implement pid->workspace tracking
Diffstat (limited to 'sway')
| -rw-r--r-- | sway/commands/exec_always.c | 2 | ||||
| -rw-r--r-- | sway/config.c | 2 | ||||
| -rw-r--r-- | sway/desktop/xdg_shell.c | 3 | ||||
| -rw-r--r-- | sway/desktop/xdg_shell_v6.c | 3 | ||||
| -rw-r--r-- | sway/desktop/xwayland.c | 3 | ||||
| -rw-r--r-- | sway/tree/view.c | 42 | ||||
| -rw-r--r-- | sway/tree/workspace.c | 114 | 
7 files changed, 149 insertions, 20 deletions
| diff --git a/sway/commands/exec_always.c b/sway/commands/exec_always.c index c7727857..9bf2b320 100644 --- a/sway/commands/exec_always.c +++ b/sway/commands/exec_always.c @@ -74,7 +74,7 @@ struct cmd_results *cmd_exec_always(int argc, char **argv) {  	waitpid(pid, NULL, 0);  	if (child > 0) {  		wlr_log(WLR_DEBUG, "Child process created with pid %d", child); -		// TODO: add PID to active workspace +		workspace_record_pid(child);  	} else {  		return cmd_results_new(CMD_FAILURE, "exec_always",  			"Second fork() failed"); diff --git a/sway/config.c b/sway/config.c index c2310ff7..90dfb9a9 100644 --- a/sway/config.c +++ b/sway/config.c @@ -93,7 +93,6 @@ void free_config(struct sway_config *config) {  	}  	list_free(config->cmd_queue);  	list_free(config->workspace_outputs); -	list_free(config->pid_workspaces);  	if (config->output_configs) {  		for (int i = 0; i < config->output_configs->length; i++) {  			free_output_config(config->output_configs->items[i]); @@ -163,7 +162,6 @@ static void config_defaults(struct sway_config *config) {  	if (!(config->modes = create_list())) goto cleanup;  	if (!(config->bars = create_list())) goto cleanup;  	if (!(config->workspace_outputs = create_list())) goto cleanup; -	if (!(config->pid_workspaces = create_list())) goto cleanup;  	if (!(config->criteria = create_list())) goto cleanup;  	if (!(config->no_focus = create_list())) goto cleanup;  	if (!(config->input_configs = create_list())) goto cleanup; diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index 62c3abc8..f3e4fef8 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c @@ -418,9 +418,6 @@ void handle_xdg_shell_surface(struct wl_listener *listener, void *data) {  	view_init(&xdg_shell_view->view, SWAY_VIEW_XDG_SHELL, &view_impl);  	xdg_shell_view->view.wlr_xdg_surface = xdg_surface; -	// TODO: -	// - Look up pid and open on appropriate workspace -  	xdg_shell_view->map.notify = handle_map;  	wl_signal_add(&xdg_surface->events.map, &xdg_shell_view->map); diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index 7fb85410..46fd4769 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c @@ -409,9 +409,6 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) {  	view_init(&xdg_shell_v6_view->view, SWAY_VIEW_XDG_SHELL_V6, &view_impl);  	xdg_shell_v6_view->view.wlr_xdg_surface_v6 = xdg_surface; -	// TODO: -	// - Look up pid and open on appropriate workspace -  	xdg_shell_v6_view->map.notify = handle_map;  	wl_signal_add(&xdg_surface->events.map, &xdg_shell_v6_view->map); diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 2546168b..65d4fcd4 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -514,9 +514,6 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) {  	view_init(&xwayland_view->view, SWAY_VIEW_XWAYLAND, &view_impl);  	xwayland_view->view.wlr_xwayland_surface = xsurface; -	// TODO: -	// - Look up pid and open on appropriate workspace -  	wl_signal_add(&xsurface->events.destroy, &xwayland_view->destroy);  	xwayland_view->destroy.notify = handle_destroy; diff --git a/sway/tree/view.c b/sway/tree/view.c index 9d88d7aa..a55c8a29 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -3,6 +3,7 @@  #include <wayland-server.h>  #include <wlr/render/wlr_renderer.h>  #include <wlr/types/wlr_output_layout.h> +#include <wlr/xwayland.h>  #include "list.h"  #include "log.h"  #include "sway/criteria.h" @@ -561,9 +562,21 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) {  		return;  	} +	pid_t pid; +	if (view->type == SWAY_VIEW_XWAYLAND) { +		struct wlr_xwayland_surface *surf = +			wlr_xwayland_surface_from_wlr_surface(wlr_surface); +		pid = surf->pid; +	} else { +		struct wl_client *client = +			wl_resource_get_client(wlr_surface->resource); +		wl_client_get_credentials(client, &pid, NULL, NULL); +	} +  	struct sway_seat *seat = input_manager_current_seat(input_manager); -	struct sway_container *focus = +	struct sway_container *target_sibling =  		seat_get_focus_inactive(seat, &root_container); +	struct sway_container *prev_focus = target_sibling;  	struct sway_container *cont = NULL;  	// Check if there's any `assign` criteria for the view @@ -577,22 +590,35 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) {  			if (!workspace) {  				workspace = workspace_create(NULL, criteria->target);  			} -			focus = seat_get_focus_inactive(seat, workspace); +			prev_focus = target_sibling; +			target_sibling = seat_get_focus_inactive(seat, workspace);  		} else {  			// CT_ASSIGN_OUTPUT  			struct sway_container *output = output_by_name(criteria->target);  			if (output) { -				focus = seat_get_focus_inactive(seat, output); +				prev_focus = seat_get_focus_inactive(seat, output);  			}  		}  	} +	list_free(criterias); + +	if (!workspace) { +		workspace = workspace_for_pid(pid); +		if (workspace) { +			prev_focus = target_sibling; +			target_sibling = seat_get_focus_inactive(seat, workspace); +		} +	}  	// If we're about to launch the view into the floating container, then  	// launch it as a tiled view in the root of the workspace instead. -	if (container_is_floating(focus)) { -		focus = focus->parent->parent; +	if (container_is_floating(target_sibling)) { +		if (prev_focus == target_sibling) { +			prev_focus = target_sibling->parent->parent; +		} +		target_sibling = target_sibling->parent->parent;  	} -	list_free(criterias); -	cont = container_view_create(focus, view); + +	cont = container_view_create(target_sibling, view);  	view->surface = wlr_surface;  	view->swayc = cont; @@ -615,7 +641,7 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) {  		view_set_tiled(view, true);  	} -	if (should_focus(view)) { +	if (should_focus(view) && prev_focus == target_sibling) {  		input_manager_set_focus(input_manager, cont);  		if (workspace) {  			workspace_switch(workspace); diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index e450b87f..62974cd7 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c @@ -9,6 +9,7 @@  #include "sway/input/input-manager.h"  #include "sway/input/seat.h"  #include "sway/ipc-server.h" +#include "sway/output.h"  #include "sway/tree/arrange.h"  #include "sway/tree/container.h"  #include "sway/tree/view.h" @@ -536,3 +537,116 @@ void workspace_detect_urgent(struct sway_container *workspace) {  		container_damage_whole(workspace);  	}  } + +struct pid_workspace { +	pid_t pid; +	char *workspace; +	struct timespec time_added; + +	struct sway_container *output; +	struct wl_listener output_destroy; + +	struct wl_list link; +}; + +static struct wl_list pid_workspaces; + +struct sway_container *workspace_for_pid(pid_t pid) { +	if (!pid_workspaces.prev && !pid_workspaces.next) { +		wl_list_init(&pid_workspaces); +		return NULL; +	} + +	struct sway_container *ws = NULL; +	struct pid_workspace *pw = NULL; + +	wlr_log(WLR_DEBUG, "Looking up workspace for pid %d", pid); + +	do { +		struct pid_workspace *_pw = NULL; +		wl_list_for_each(_pw, &pid_workspaces, link) { +			if (pid == _pw->pid) { +				pw = _pw; +				wlr_log(WLR_DEBUG, +						"found pid_workspace for pid %d, workspace %s", +						pid, pw->workspace); +				goto found; +			} +		} +		pid = get_parent_pid(pid); +	} while (pid > 1); +found: + +	if (pw && pw->workspace) { +		ws = workspace_by_name(pw->workspace); + +		if (!ws) { +			wlr_log(WLR_DEBUG, +					"Creating workspace %s for pid %d because it disappeared", +					pw->workspace, pid); +			ws = workspace_create(pw->output, pw->workspace); +		} + +		wl_list_remove(&pw->output_destroy.link); +		wl_list_remove(&pw->link); +		free(pw->workspace); +		free(pw); +	} + +	return ws; +} + +static void pw_handle_output_destroy(struct wl_listener *listener, void *data) { +	struct pid_workspace *pw = wl_container_of(listener, pw, output_destroy); +	pw->output = NULL; +	wl_list_remove(&pw->output_destroy.link); +	wl_list_init(&pw->output_destroy.link); +} + +void workspace_record_pid(pid_t pid) { +	wlr_log(WLR_DEBUG, "Recording workspace for process %d", pid); +	if (!pid_workspaces.prev && !pid_workspaces.next) { +		wl_list_init(&pid_workspaces); +	} + +	struct sway_seat *seat = input_manager_current_seat(input_manager); +	struct sway_container *ws = +		seat_get_focus_inactive(seat, &root_container); +	if (ws && ws->type != C_WORKSPACE) { +		ws = container_parent(ws, C_WORKSPACE); +	} +	if (!ws) { +		wlr_log(WLR_DEBUG, "Bailing out, no workspace"); +		return; +	} +	struct sway_container *output = ws->parent; +	if (!output) { +		wlr_log(WLR_DEBUG, "Bailing out, no output"); +		return; +	} + +	struct timespec now; +	clock_gettime(CLOCK_MONOTONIC, &now); + +	// Remove expired entries +	static const int timeout = 60; +	struct pid_workspace *old, *_old; +	wl_list_for_each_safe(old, _old, &pid_workspaces, link) { +		if (now.tv_sec - old->time_added.tv_sec >= timeout) { +			wl_list_remove(&old->output_destroy.link); +			wl_list_remove(&old->link); +			free(old->workspace); +			free(old); +		} +	} + +	struct pid_workspace *pw = calloc(1, sizeof(struct pid_workspace)); +	pw->workspace = strdup(ws->name); +	pw->output = output; +	pw->pid = pid; +	memcpy(&pw->time_added, &now, sizeof(struct timespec)); +	pw->output_destroy.notify = pw_handle_output_destroy; +	wl_signal_add(&output->sway_output->wlr_output->events.destroy, +			&pw->output_destroy); +	wl_list_insert(&pid_workspaces, &pw->link); +} | 
