aboutsummaryrefslogtreecommitdiffstats
path: root/sway/tree/workspace.c
diff options
context:
space:
mode:
authorLibravatar Drew DeVault <sir@cmpwn.com>2018-06-26 20:32:09 -0400
committerLibravatar Drew DeVault <sir@cmpwn.com>2018-07-01 09:58:18 -0400
commitacd79e1505c06089e4fb9fb6c0c6e1d351ba9176 (patch)
tree9f677ebac9604075e3138788fb72d6db423e1f17 /sway/tree/workspace.c
parentMerge pull request #2180 from martinetd/xdg_fullscreen (diff)
downloadsway-acd79e1505c06089e4fb9fb6c0c6e1d351ba9176.tar.gz
sway-acd79e1505c06089e4fb9fb6c0c6e1d351ba9176.tar.zst
sway-acd79e1505c06089e4fb9fb6c0c6e1d351ba9176.zip
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.
Diffstat (limited to 'sway/tree/workspace.c')
-rw-r--r--sway/tree/workspace.c112
1 files changed, 112 insertions, 0 deletions
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 @@
9#include "sway/input/input-manager.h" 9#include "sway/input/input-manager.h"
10#include "sway/input/seat.h" 10#include "sway/input/seat.h"
11#include "sway/ipc-server.h" 11#include "sway/ipc-server.h"
12#include "sway/output.h"
12#include "sway/tree/arrange.h" 13#include "sway/tree/arrange.h"
13#include "sway/tree/container.h" 14#include "sway/tree/container.h"
14#include "sway/tree/workspace.h" 15#include "sway/tree/workspace.h"
@@ -516,3 +517,114 @@ struct sway_container *workspace_output_get_highest_available(
516 517
517 return NULL; 518 return NULL;
518} 519}
520
521struct pid_workspace {
522 pid_t pid;
523 char *workspace;
524 struct timespec time_added;
525
526 struct sway_container *output;
527 struct wl_listener output_destroy;
528
529 struct wl_list link;
530};
531
532static struct wl_list pid_workspaces;
533
534struct sway_container *workspace_for_pid(pid_t pid) {
535 if (!pid_workspaces.prev && !pid_workspaces.next) {
536 wl_list_init(&pid_workspaces);
537 return NULL;
538 }
539
540 struct sway_container *ws = NULL;
541 struct pid_workspace *pw = NULL;
542
543 wlr_log(L_DEBUG, "Looking up workspace for pid %d", pid);
544
545 do {
546 struct pid_workspace *_pw = NULL;
547 wl_list_for_each(_pw, &pid_workspaces, link) {
548 if (pid == _pw->pid) {
549 pw = _pw;
550 wlr_log(L_DEBUG,
551 "found pid_workspace for pid %d, workspace %s",
552 pid, pw->workspace);
553 goto found;
554 }
555 }
556 pid = get_parent_pid(pid);
557 } while (pid > 1);
558found:
559
560 if (pw && pw->workspace) {
561 ws = workspace_by_name(pw->workspace);
562
563 if (!ws) {
564 wlr_log(L_DEBUG,
565 "Creating workspace %s for pid %d because it disappeared",
566 pw->workspace, pid);
567 ws = workspace_create(pw->output, pw->workspace);
568 }
569
570 wl_list_remove(&pw->output_destroy.link);
571 wl_list_remove(&pw->link);
572 free(pw->workspace);
573 free(pw);
574 }
575
576 return ws;
577}
578
579static void pw_handle_output_destroy(struct wl_listener *listener, void *data) {
580 struct pid_workspace *pw = wl_container_of(listener, pw, output_destroy);
581 pw->output = NULL;
582}
583
584void workspace_record_pid(pid_t pid) {
585 wlr_log(L_DEBUG, "Recording workspace for process %d", pid);
586 if (!pid_workspaces.prev && !pid_workspaces.next) {
587 wl_list_init(&pid_workspaces);
588 }
589
590 struct sway_seat *seat = input_manager_current_seat(input_manager);
591 struct sway_container *ws =
592 seat_get_focus_inactive(seat, &root_container);
593 if (ws && ws->type != C_WORKSPACE) {
594 ws = container_parent(ws, C_WORKSPACE);
595 }
596 if (!ws) {
597 wlr_log(L_DEBUG, "Bailing out, no workspace");
598 return;
599 }
600 struct sway_container *output = ws->parent;
601 if (!output) {
602 wlr_log(L_DEBUG, "Bailing out, no output");
603 return;
604 }
605
606 struct timespec now;
607 clock_gettime(CLOCK_MONOTONIC, &now);
608
609 // Remove expired entries
610 static const int timeout = 60;
611 struct pid_workspace *old, *_old;
612 wl_list_for_each_safe(old, _old, &pid_workspaces, link) {
613 if (now.tv_sec - old->time_added.tv_sec >= timeout) {
614 wl_list_remove(&old->output_destroy.link);
615 wl_list_remove(&old->link);
616 free(old->workspace);
617 free(old);
618 }
619 }
620
621 struct pid_workspace *pw = calloc(1, sizeof(struct pid_workspace));
622 pw->workspace = strdup(ws->name);
623 pw->output = output;
624 pw->pid = pid;
625 memcpy(&pw->time_added, &now, sizeof(struct timespec));
626 pw->output_destroy.notify = pw_handle_output_destroy;
627 wl_signal_add(&output->sway_output->wlr_output->events.destroy,
628 &pw->output_destroy);
629 wl_list_insert(&pid_workspaces, &pw->link);
630}