diff --git a/include/sway/desktop/launcher.h b/include/sway/desktop/launcher.h new file mode 100644 index 000000000..cb22eb980 --- /dev/null +++ b/include/sway/desktop/launcher.h @@ -0,0 +1,14 @@ +#ifndef _SWAY_LAUNCHER_H +#define _SWAY_LAUNCHER_H + +#include + +struct sway_workspace *root_workspace_for_pid(pid_t pid); + +void root_record_workspace_pid(pid_t pid); + +void root_remove_workspace_pid(pid_t pid); + +void root_rename_pid_workspaces(const char *old_name, const char *new_name); + +#endif diff --git a/include/sway/tree/root.h b/include/sway/tree/root.h index af4124a18..a2c088e76 100644 --- a/include/sway/tree/root.h +++ b/include/sway/tree/root.h @@ -69,12 +69,6 @@ void root_scratchpad_show(struct sway_container *con); */ void root_scratchpad_hide(struct sway_container *con); -struct sway_workspace *root_workspace_for_pid(pid_t pid); - -void root_record_workspace_pid(pid_t pid); - -void root_remove_workspace_pid(pid_t pid); - void root_for_each_workspace(void (*f)(struct sway_workspace *ws, void *data), void *data); @@ -92,6 +86,4 @@ struct sway_container *root_find_container( void root_get_box(struct sway_root *root, struct wlr_box *box); -void root_rename_pid_workspaces(const char *old_name, const char *new_name); - #endif diff --git a/sway/commands/exec_always.c b/sway/commands/exec_always.c index b35065c12..fab9a4028 100644 --- a/sway/commands/exec_always.c +++ b/sway/commands/exec_always.c @@ -8,6 +8,7 @@ #include "sway/commands.h" #include "sway/config.h" #include "sway/server.h" +#include "sway/desktop/launcher.h" #include "sway/tree/container.h" #include "sway/tree/root.h" #include "sway/tree/workspace.h" diff --git a/sway/commands/rename.c b/sway/commands/rename.c index 3b855fdf7..4656a4109 100644 --- a/sway/commands/rename.c +++ b/sway/commands/rename.c @@ -7,6 +7,7 @@ #include "sway/config.h" #include "sway/ipc-server.h" #include "sway/output.h" +#include "sway/desktop/launcher.h" #include "sway/tree/container.h" #include "sway/tree/workspace.h" #include "sway/tree/root.h" diff --git a/sway/desktop/launcher.c b/sway/desktop/launcher.c new file mode 100644 index 000000000..4e0d9dc1f --- /dev/null +++ b/sway/desktop/launcher.c @@ -0,0 +1,189 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include "sway/input/seat.h" +#include "sway/output.h" +#include "sway/desktop/launcher.h" +#include "sway/tree/container.h" +#include "sway/tree/workspace.h" +#include "log.h" + +static struct wl_list pid_workspaces; + +struct pid_workspace { + pid_t pid; + char *workspace; + struct timespec time_added; + + struct sway_output *output; + struct wl_listener output_destroy; + + struct wl_list link; +}; + +/** + * Get the pid of a parent process given the pid of a child process. + * + * Returns the parent pid or NULL if the parent pid cannot be determined. + */ +static pid_t get_parent_pid(pid_t child) { + pid_t parent = -1; + char file_name[100]; + char *buffer = NULL; + const char *sep = " "; + FILE *stat = NULL; + size_t buf_size = 0; + + snprintf(file_name, sizeof(file_name), "/proc/%d/stat", child); + + if ((stat = fopen(file_name, "r"))) { + if (getline(&buffer, &buf_size, stat) != -1) { + strtok(buffer, sep); // pid + strtok(NULL, sep); // executable name + strtok(NULL, sep); // state + char *token = strtok(NULL, sep); // parent pid + parent = strtol(token, NULL, 10); + } + free(buffer); + fclose(stat); + } + + if (parent) { + return (parent == child) ? -1 : parent; + } + + return -1; +} + +static void pid_workspace_destroy(struct pid_workspace *pw) { + wl_list_remove(&pw->output_destroy.link); + wl_list_remove(&pw->link); + free(pw->workspace); + free(pw); +} + +struct sway_workspace *root_workspace_for_pid(pid_t pid) { + if (!pid_workspaces.prev && !pid_workspaces.next) { + wl_list_init(&pid_workspaces); + return NULL; + } + + struct sway_workspace *ws = NULL; + struct pid_workspace *pw = NULL; + + sway_log(SWAY_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; + sway_log(SWAY_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) { + sway_log(SWAY_DEBUG, + "Creating workspace %s for pid %d because it disappeared", + pw->workspace, pid); + + struct sway_output *output = pw->output; + if (pw->output && !pw->output->enabled) { + sway_log(SWAY_DEBUG, + "Workspace output %s is disabled, trying another one", + pw->output->wlr_output->name); + output = NULL; + } + + ws = workspace_create(output, pw->workspace); + } + + pid_workspace_destroy(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 root_record_workspace_pid(pid_t pid) { + sway_log(SWAY_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(); + struct sway_workspace *ws = seat_get_focused_workspace(seat); + if (!ws) { + sway_log(SWAY_DEBUG, "Bailing out, no workspace"); + return; + } + struct sway_output *output = ws->output; + if (!output) { + sway_log(SWAY_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) { + pid_workspace_destroy(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->wlr_output->events.destroy, &pw->output_destroy); + wl_list_insert(&pid_workspaces, &pw->link); +} + +void root_remove_workspace_pid(pid_t pid) { + if (!pid_workspaces.prev || !pid_workspaces.next) { + return; + } + + struct pid_workspace *pw, *tmp; + wl_list_for_each_safe(pw, tmp, &pid_workspaces, link) { + if (pid == pw->pid) { + pid_workspace_destroy(pw); + return; + } + } +} + +void root_rename_pid_workspaces(const char *old_name, const char *new_name) { + if (!pid_workspaces.prev && !pid_workspaces.next) { + wl_list_init(&pid_workspaces); + } + + struct pid_workspace *pw = NULL; + wl_list_for_each(pw, &pid_workspaces, link) { + if (strcmp(pw->workspace, old_name) == 0) { + free(pw->workspace); + pw->workspace = strdup(new_name); + } + } +} diff --git a/sway/meson.build b/sway/meson.build index bb6bf88c2..8a73cc867 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -21,6 +21,7 @@ sway_sources = files( 'desktop/surface.c', 'desktop/transaction.c', 'desktop/xdg_shell.c', + 'desktop/launcher.c', 'input/input-manager.c', 'input/cursor.c', diff --git a/sway/tree/root.c b/sway/tree/root.c index 7df0b2378..8934721fd 100644 --- a/sway/tree/root.c +++ b/sway/tree/root.c @@ -184,172 +184,6 @@ void root_scratchpad_hide(struct sway_container *con) { ipc_event_window(con, "move"); } -struct pid_workspace { - pid_t pid; - char *workspace; - struct timespec time_added; - - struct sway_output *output; - struct wl_listener output_destroy; - - struct wl_list link; -}; - -static struct wl_list pid_workspaces; - -/** - * Get the pid of a parent process given the pid of a child process. - * - * Returns the parent pid or NULL if the parent pid cannot be determined. - */ -static pid_t get_parent_pid(pid_t child) { - pid_t parent = -1; - char file_name[100]; - char *buffer = NULL; - const char *sep = " "; - FILE *stat = NULL; - size_t buf_size = 0; - - snprintf(file_name, sizeof(file_name), "/proc/%d/stat", child); - - if ((stat = fopen(file_name, "r"))) { - if (getline(&buffer, &buf_size, stat) != -1) { - strtok(buffer, sep); // pid - strtok(NULL, sep); // executable name - strtok(NULL, sep); // state - char *token = strtok(NULL, sep); // parent pid - parent = strtol(token, NULL, 10); - } - free(buffer); - fclose(stat); - } - - if (parent) { - return (parent == child) ? -1 : parent; - } - - return -1; -} - -static void pid_workspace_destroy(struct pid_workspace *pw) { - wl_list_remove(&pw->output_destroy.link); - wl_list_remove(&pw->link); - free(pw->workspace); - free(pw); -} - -struct sway_workspace *root_workspace_for_pid(pid_t pid) { - if (!pid_workspaces.prev && !pid_workspaces.next) { - wl_list_init(&pid_workspaces); - return NULL; - } - - struct sway_workspace *ws = NULL; - struct pid_workspace *pw = NULL; - - sway_log(SWAY_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; - sway_log(SWAY_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) { - sway_log(SWAY_DEBUG, - "Creating workspace %s for pid %d because it disappeared", - pw->workspace, pid); - - struct sway_output *output = pw->output; - if (pw->output && !pw->output->enabled) { - sway_log(SWAY_DEBUG, - "Workspace output %s is disabled, trying another one", - pw->output->wlr_output->name); - output = NULL; - } - - ws = workspace_create(output, pw->workspace); - } - - pid_workspace_destroy(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 root_record_workspace_pid(pid_t pid) { - sway_log(SWAY_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(); - struct sway_workspace *ws = seat_get_focused_workspace(seat); - if (!ws) { - sway_log(SWAY_DEBUG, "Bailing out, no workspace"); - return; - } - struct sway_output *output = ws->output; - if (!output) { - sway_log(SWAY_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) { - pid_workspace_destroy(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->wlr_output->events.destroy, &pw->output_destroy); - wl_list_insert(&pid_workspaces, &pw->link); -} - -void root_remove_workspace_pid(pid_t pid) { - if (!pid_workspaces.prev || !pid_workspaces.next) { - return; - } - - struct pid_workspace *pw, *tmp; - wl_list_for_each_safe(pw, tmp, &pid_workspaces, link) { - if (pid == pw->pid) { - pid_workspace_destroy(pw); - return; - } - } -} - void root_for_each_workspace(void (*f)(struct sway_workspace *ws, void *data), void *data) { for (int i = 0; i < root->outputs->length; ++i) { @@ -444,17 +278,3 @@ void root_get_box(struct sway_root *root, struct wlr_box *box) { box->width = root->width; box->height = root->height; } - -void root_rename_pid_workspaces(const char *old_name, const char *new_name) { - if (!pid_workspaces.prev && !pid_workspaces.next) { - wl_list_init(&pid_workspaces); - } - - struct pid_workspace *pw = NULL; - wl_list_for_each(pw, &pid_workspaces, link) { - if (strcmp(pw->workspace, old_name) == 0) { - free(pw->workspace); - pw->workspace = strdup(new_name); - } - } -} diff --git a/sway/tree/view.c b/sway/tree/view.c index 589a3f7ef..edc3e2af4 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -19,6 +19,7 @@ #include "sway/desktop.h" #include "sway/desktop/transaction.h" #include "sway/desktop/idle_inhibit_v1.h" +#include "sway/desktop/launcher.h" #include "sway/input/cursor.h" #include "sway/ipc-server.h" #include "sway/output.h"