From acd79e1505c06089e4fb9fb6c0c6e1d351ba9176 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Tue, 26 Jun 2018 20:32:09 -0400 Subject: Implement pid->workspace tracking When you spawn a process with the exec command, sway now notes the workspace you had focused and the pid of the child process, then assigns that workspace to the child when its window appears. Some of this is carried over from sway 0.15, but with some major refactoring and centralization of state. --- sway/tree/workspace.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) (limited to 'sway/tree/workspace.c') diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index 5eb4be0f..651cc011 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/workspace.h" @@ -516,3 +517,114 @@ struct sway_container *workspace_output_get_highest_available( return NULL; } + +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(L_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(L_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(L_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; +} + +void workspace_record_pid(pid_t pid) { + wlr_log(L_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(L_DEBUG, "Bailing out, no workspace"); + return; + } + struct sway_container *output = ws->parent; + if (!output) { + wlr_log(L_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); +} -- cgit v1.2.3 From ab0efebc3e74aeae529cfdf085ea0b7ea33dbfab Mon Sep 17 00:00:00 2001 From: frsfnrrg Date: Sun, 15 Jul 2018 10:35:56 -0400 Subject: Also extract first workspace name from bindcodes --- sway/tree/workspace.c | 159 ++++++++++++++++++++++++++------------------------ 1 file changed, 83 insertions(+), 76 deletions(-) (limited to 'sway/tree/workspace.c') diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index 622f01ec..e450b87f 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c @@ -107,96 +107,103 @@ static bool workspace_valid_on_output(const char *output_name, return true; } -char *workspace_next_name(const char *output_name) { - wlr_log(WLR_DEBUG, "Workspace: Generating new workspace name for output %s", - output_name); - // Scan all workspace bindings to find the next available workspace name, - // if none are found/available then default to a number - struct sway_mode *mode = config->current_mode; - - // TODO: iterate over keycode bindings too - int order = INT_MAX; - char *target = NULL; - for (int i = 0; i < mode->keysym_bindings->length; ++i) { - struct sway_binding *binding = mode->keysym_bindings->items[i]; - char *cmdlist = strdup(binding->command); - char *dup = cmdlist; - char *name = NULL; - - // workspace n - char *cmd = argsep(&cmdlist, " "); - if (cmdlist) { - name = argsep(&cmdlist, ",;"); +static void workspace_name_from_binding(const struct sway_binding * binding, + const char* output_name, int *min_order, char **earliest_name) { + char *cmdlist = strdup(binding->command); + char *dup = cmdlist; + char *name = NULL; + + // workspace n + char *cmd = argsep(&cmdlist, " "); + if (cmdlist) { + name = argsep(&cmdlist, ",;"); + } + + if (strcmp("workspace", cmd) == 0 && name) { + char *_target = strdup(name); + _target = do_var_replacement(_target); + strip_quotes(_target); + while (isspace(*_target)) { + memmove(_target, _target+1, strlen(_target+1)); } + wlr_log(WLR_DEBUG, "Got valid workspace command for target: '%s'", + _target); - if (strcmp("workspace", cmd) == 0 && name) { - char *_target = strdup(name); - _target = do_var_replacement(_target); - strip_quotes(_target); - while (isspace(*_target)) { - memmove(_target, _target+1, strlen(_target+1)); - } - wlr_log(WLR_DEBUG, "Got valid workspace command for target: '%s'", - _target); - - // Make sure that the command references an actual workspace - // not a command about workspaces - if (strcmp(_target, "next") == 0 || + // Make sure that the command references an actual workspace + // not a command about workspaces + if (strcmp(_target, "next") == 0 || strcmp(_target, "prev") == 0 || strcmp(_target, "next_on_output") == 0 || strcmp(_target, "prev_on_output") == 0 || strcmp(_target, "number") == 0 || strcmp(_target, "back_and_forth") == 0 || - strcmp(_target, "current") == 0) - { - free(_target); - free(dup); - continue; - } - - // If the command is workspace number , isolate the name - if (strncmp(_target, "number ", strlen("number ")) == 0) { - size_t length = strlen(_target) - strlen("number ") + 1; - char *temp = malloc(length); - strncpy(temp, _target + strlen("number "), length - 1); - temp[length - 1] = '\0'; - free(_target); - _target = temp; - wlr_log(WLR_DEBUG, "Isolated name from workspace number: '%s'", _target); - - // Make sure the workspace number doesn't already exist - if (workspace_by_number(_target)) { - free(_target); - free(dup); - continue; - } - } + strcmp(_target, "current") == 0) { + free(_target); + free(dup); + return; + } - // Make sure that the workspace doesn't already exist - if (workspace_by_name(_target)) { + // If the command is workspace number , isolate the name + if (strncmp(_target, "number ", strlen("number ")) == 0) { + size_t length = strlen(_target) - strlen("number ") + 1; + char *temp = malloc(length); + strncpy(temp, _target + strlen("number "), length - 1); + temp[length - 1] = '\0'; + free(_target); + _target = temp; + wlr_log(WLR_DEBUG, "Isolated name from workspace number: '%s'", _target); + + // Make sure the workspace number doesn't already exist + if (workspace_by_number(_target)) { free(_target); free(dup); - continue; + return; } + } - // make sure that the workspace can appear on the given - // output - if (!workspace_valid_on_output(output_name, _target)) { - free(_target); - free(dup); - continue; - } + // Make sure that the workspace doesn't already exist + if (workspace_by_name(_target)) { + free(_target); + free(dup); + return; + } - if (binding->order < order) { - order = binding->order; - free(target); - target = _target; - wlr_log(WLR_DEBUG, "Workspace: Found free name %s", _target); - } else { - free(_target); - } + // make sure that the workspace can appear on the given + // output + if (!workspace_valid_on_output(output_name, _target)) { + free(_target); + free(dup); + return; } - free(dup); + + if (binding->order < *min_order) { + *min_order = binding->order; + free(*earliest_name); + *earliest_name = _target; + wlr_log(WLR_DEBUG, "Workspace: Found free name %s", _target); + } else { + free(_target); + } + } + free(dup); +} + +char *workspace_next_name(const char *output_name) { + wlr_log(WLR_DEBUG, "Workspace: Generating new workspace name for output %s", + output_name); + // Scan all workspace bindings to find the next available workspace name, + // if none are found/available then default to a number + struct sway_mode *mode = config->current_mode; + + int order = INT_MAX; + char *target = NULL; + for (int i = 0; i < mode->keysym_bindings->length; ++i) { + workspace_name_from_binding(mode->keysym_bindings->items[i], + output_name, &order, &target); + } + for (int i = 0; i < mode->keycode_bindings->length; ++i) { + workspace_name_from_binding(mode->keycode_bindings->items[i], + output_name, &order, &target); } if (target != NULL) { return target; -- cgit v1.2.3 From c80258c3b394781c42cd4f2c161c705b2558c485 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Tue, 24 Jul 2018 14:31:38 -0400 Subject: Address @emersion's review comments --- sway/tree/workspace.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sway/tree/workspace.c') diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index a93d9f44..b1082e4f 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c @@ -592,6 +592,8 @@ found: 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) { -- cgit v1.2.3 From d37c94d1b666ba92562efbcd4bda2cb0c3ca4916 Mon Sep 17 00:00:00 2001 From: Mihai Coman Date: Sat, 28 Jul 2018 00:18:52 +0000 Subject: Preserve workspace name --- sway/tree/workspace.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'sway/tree/workspace.c') diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index 62974cd7..588e2aae 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c @@ -124,9 +124,6 @@ static void workspace_name_from_binding(const struct sway_binding * binding, char *_target = strdup(name); _target = do_var_replacement(_target); strip_quotes(_target); - while (isspace(*_target)) { - memmove(_target, _target+1, strlen(_target+1)); - } wlr_log(WLR_DEBUG, "Got valid workspace command for target: '%s'", _target); -- cgit v1.2.3