aboutsummaryrefslogtreecommitdiffstats
path: root/sway/tree/workspace.c
diff options
context:
space:
mode:
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}