aboutsummaryrefslogtreecommitdiffstats
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
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.
-rw-r--r--config.in3
-rw-r--r--include/sway/config.h11
-rw-r--r--include/sway/tree/workspace.h5
-rw-r--r--sway/commands/exec_always.c2
-rw-r--r--sway/config.c2
-rw-r--r--sway/desktop/xdg_shell.c3
-rw-r--r--sway/desktop/xdg_shell_v6.c3
-rw-r--r--sway/desktop/xwayland.c3
-rw-r--r--sway/tree/view.c43
-rw-r--r--sway/tree/workspace.c112
10 files changed, 154 insertions, 33 deletions
diff --git a/config.in b/config.in
index 4a11762a..41f53461 100644
--- a/config.in
+++ b/config.in
@@ -16,7 +16,8 @@ set $right l
16# Your preferred terminal emulator 16# Your preferred terminal emulator
17set $term urxvt 17set $term urxvt
18# Your preferred application launcher 18# Your preferred application launcher
19set $menu dmenu_run 19# Note: it's recommended that you pass the final command to sway
20set $menu dmenu_path | dmenu | xargs swaymsg exec
20 21
21### Output configuration 22### Output configuration
22# 23#
diff --git a/include/sway/config.h b/include/sway/config.h
index e75b0664..9b583323 100644
--- a/include/sway/config.h
+++ b/include/sway/config.h
@@ -1,6 +1,5 @@
1#ifndef _SWAY_CONFIG_H 1#ifndef _SWAY_CONFIG_H
2#define _SWAY_CONFIG_H 2#define _SWAY_CONFIG_H
3#define PID_WORKSPACE_TIMEOUT 60
4#include <libinput.h> 3#include <libinput.h>
5#include <stdint.h> 4#include <stdint.h>
6#include <string.h> 5#include <string.h>
@@ -143,12 +142,6 @@ struct workspace_output {
143 char *workspace; 142 char *workspace;
144}; 143};
145 144
146struct pid_workspace {
147 pid_t *pid;
148 char *workspace;
149 time_t *time_added;
150};
151
152struct bar_config { 145struct bar_config {
153 /** 146 /**
154 * One of "dock", "hide", "invisible" 147 * One of "dock", "hide", "invisible"
@@ -300,7 +293,6 @@ struct sway_config {
300 list_t *bars; 293 list_t *bars;
301 list_t *cmd_queue; 294 list_t *cmd_queue;
302 list_t *workspace_outputs; 295 list_t *workspace_outputs;
303 list_t *pid_workspaces;
304 list_t *output_configs; 296 list_t *output_configs;
305 list_t *input_configs; 297 list_t *input_configs;
306 list_t *seat_configs; 298 list_t *seat_configs;
@@ -384,9 +376,6 @@ struct sway_config {
384 } handler_context; 376 } handler_context;
385}; 377};
386 378
387void pid_workspace_add(struct pid_workspace *pw);
388void free_pid_workspace(struct pid_workspace *pw);
389
390/** 379/**
391 * Loads the main config from the given path. is_active should be true when 380 * Loads the main config from the given path. is_active should be true when
392 * reloading the config. 381 * reloading the config.
diff --git a/include/sway/tree/workspace.h b/include/sway/tree/workspace.h
index c72a4ac0..d84e4a02 100644
--- a/include/sway/tree/workspace.h
+++ b/include/sway/tree/workspace.h
@@ -42,4 +42,9 @@ void workspace_output_add_priority(struct sway_container *workspace,
42 42
43struct sway_container *workspace_output_get_highest_available( 43struct sway_container *workspace_output_get_highest_available(
44 struct sway_container *ws, struct sway_container *exclude); 44 struct sway_container *ws, struct sway_container *exclude);
45
46struct sway_container *workspace_for_pid(pid_t pid);
47
48void workspace_record_pid(pid_t pid);
49
45#endif 50#endif
diff --git a/sway/commands/exec_always.c b/sway/commands/exec_always.c
index 682d195e..abd52e59 100644
--- a/sway/commands/exec_always.c
+++ b/sway/commands/exec_always.c
@@ -76,7 +76,7 @@ struct cmd_results *cmd_exec_always(int argc, char **argv) {
76 waitpid(pid, NULL, 0); 76 waitpid(pid, NULL, 0);
77 if (*child > 0) { 77 if (*child > 0) {
78 wlr_log(L_DEBUG, "Child process created with pid %d", *child); 78 wlr_log(L_DEBUG, "Child process created with pid %d", *child);
79 // TODO: add PID to active workspace 79 workspace_record_pid(*child);
80 } else { 80 } else {
81 free(child); 81 free(child);
82 } 82 }
diff --git a/sway/config.c b/sway/config.c
index 12a02163..512cab31 100644
--- a/sway/config.c
+++ b/sway/config.c
@@ -86,7 +86,6 @@ void free_config(struct sway_config *config) {
86 } 86 }
87 list_free(config->cmd_queue); 87 list_free(config->cmd_queue);
88 list_free(config->workspace_outputs); 88 list_free(config->workspace_outputs);
89 list_free(config->pid_workspaces);
90 list_free(config->output_configs); 89 list_free(config->output_configs);
91 if (config->input_configs) { 90 if (config->input_configs) {
92 for (int i = 0; i < config->input_configs->length; i++) { 91 for (int i = 0; i < config->input_configs->length; i++) {
@@ -145,7 +144,6 @@ static void config_defaults(struct sway_config *config) {
145 if (!(config->modes = create_list())) goto cleanup; 144 if (!(config->modes = create_list())) goto cleanup;
146 if (!(config->bars = create_list())) goto cleanup; 145 if (!(config->bars = create_list())) goto cleanup;
147 if (!(config->workspace_outputs = create_list())) goto cleanup; 146 if (!(config->workspace_outputs = create_list())) goto cleanup;
148 if (!(config->pid_workspaces = create_list())) goto cleanup;
149 if (!(config->criteria = create_list())) goto cleanup; 147 if (!(config->criteria = create_list())) goto cleanup;
150 if (!(config->no_focus = create_list())) goto cleanup; 148 if (!(config->no_focus = create_list())) goto cleanup;
151 if (!(config->input_configs = create_list())) goto cleanup; 149 if (!(config->input_configs = create_list())) goto cleanup;
diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c
index 82db4076..47604c31 100644
--- a/sway/desktop/xdg_shell.c
+++ b/sway/desktop/xdg_shell.c
@@ -321,9 +321,6 @@ void handle_xdg_shell_surface(struct wl_listener *listener, void *data) {
321 view_init(&xdg_shell_view->view, SWAY_VIEW_XDG_SHELL, &view_impl); 321 view_init(&xdg_shell_view->view, SWAY_VIEW_XDG_SHELL, &view_impl);
322 xdg_shell_view->view.wlr_xdg_surface = xdg_surface; 322 xdg_shell_view->view.wlr_xdg_surface = xdg_surface;
323 323
324 // TODO:
325 // - Look up pid and open on appropriate workspace
326
327 xdg_shell_view->map.notify = handle_map; 324 xdg_shell_view->map.notify = handle_map;
328 wl_signal_add(&xdg_surface->events.map, &xdg_shell_view->map); 325 wl_signal_add(&xdg_surface->events.map, &xdg_shell_view->map);
329 326
diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c
index 0d3c1644..b28c4b9c 100644
--- a/sway/desktop/xdg_shell_v6.c
+++ b/sway/desktop/xdg_shell_v6.c
@@ -312,9 +312,6 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) {
312 view_init(&xdg_shell_v6_view->view, SWAY_VIEW_XDG_SHELL_V6, &view_impl); 312 view_init(&xdg_shell_v6_view->view, SWAY_VIEW_XDG_SHELL_V6, &view_impl);
313 xdg_shell_v6_view->view.wlr_xdg_surface_v6 = xdg_surface; 313 xdg_shell_v6_view->view.wlr_xdg_surface_v6 = xdg_surface;
314 314
315 // TODO:
316 // - Look up pid and open on appropriate workspace
317
318 xdg_shell_v6_view->map.notify = handle_map; 315 xdg_shell_v6_view->map.notify = handle_map;
319 wl_signal_add(&xdg_surface->events.map, &xdg_shell_v6_view->map); 316 wl_signal_add(&xdg_surface->events.map, &xdg_shell_v6_view->map);
320 317
diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c
index 4bb35f60..b3b1473d 100644
--- a/sway/desktop/xwayland.c
+++ b/sway/desktop/xwayland.c
@@ -446,9 +446,6 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) {
446 view_init(&xwayland_view->view, SWAY_VIEW_XWAYLAND, &view_impl); 446 view_init(&xwayland_view->view, SWAY_VIEW_XWAYLAND, &view_impl);
447 xwayland_view->view.wlr_xwayland_surface = xsurface; 447 xwayland_view->view.wlr_xwayland_surface = xsurface;
448 448
449 // TODO:
450 // - Look up pid and open on appropriate workspace
451
452 wl_signal_add(&xsurface->events.destroy, &xwayland_view->destroy); 449 wl_signal_add(&xsurface->events.destroy, &xwayland_view->destroy);
453 xwayland_view->destroy.notify = handle_destroy; 450 xwayland_view->destroy.notify = handle_destroy;
454 451
diff --git a/sway/tree/view.c b/sway/tree/view.c
index 06e9edc5..24fb6864 100644
--- a/sway/tree/view.c
+++ b/sway/tree/view.c
@@ -3,6 +3,7 @@
3#include <wayland-server.h> 3#include <wayland-server.h>
4#include <wlr/render/wlr_renderer.h> 4#include <wlr/render/wlr_renderer.h>
5#include <wlr/types/wlr_output_layout.h> 5#include <wlr/types/wlr_output_layout.h>
6#include <wlr/xwayland.h>
6#include "list.h" 7#include "list.h"
7#include "log.h" 8#include "log.h"
8#include "sway/criteria.h" 9#include "sway/criteria.h"
@@ -492,9 +493,21 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) {
492 return; 493 return;
493 } 494 }
494 495
496 pid_t pid;
497 if (view->type == SWAY_VIEW_XWAYLAND) {
498 struct wlr_xwayland_surface *surf =
499 wlr_xwayland_surface_from_wlr_surface(wlr_surface);
500 pid = surf->pid;
501 } else {
502 struct wl_client *client =
503 wl_resource_get_client(wlr_surface->resource);
504 wl_client_get_credentials(client, &pid, NULL, NULL);
505 }
506
495 struct sway_seat *seat = input_manager_current_seat(input_manager); 507 struct sway_seat *seat = input_manager_current_seat(input_manager);
496 struct sway_container *focus = 508 struct sway_container *target_sibling =
497 seat_get_focus_inactive(seat, &root_container); 509 seat_get_focus_inactive(seat, &root_container);
510 struct sway_container *prev_focus = target_sibling;
498 struct sway_container *cont = NULL; 511 struct sway_container *cont = NULL;
499 512
500 // Check if there's any `assign` criteria for the view 513 // Check if there's any `assign` criteria for the view
@@ -508,18 +521,31 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) {
508 if (!workspace) { 521 if (!workspace) {
509 workspace = workspace_create(NULL, criteria->target); 522 workspace = workspace_create(NULL, criteria->target);
510 } 523 }
511 focus = seat_get_focus_inactive(seat, workspace); 524 prev_focus = target_sibling;
525 target_sibling = seat_get_focus_inactive(seat, workspace);
512 } else { 526 } else {
513 // TODO: CT_ASSIGN_OUTPUT 527 // TODO: CT_ASSIGN_OUTPUT
514 } 528 }
515 } 529 }
530 list_free(criterias);
531
532 if (!workspace) {
533 workspace = workspace_for_pid(pid);
534 if (workspace) {
535 prev_focus = target_sibling;
536 target_sibling = seat_get_focus_inactive(seat, workspace);
537 }
538 }
516 // If we're about to launch the view into the floating container, then 539 // If we're about to launch the view into the floating container, then
517 // launch it as a tiled view in the root of the workspace instead. 540 // launch it as a tiled view in the root of the workspace instead.
518 if (container_is_floating(focus)) { 541 if (container_is_floating(target_sibling)) {
519 focus = focus->parent->parent; 542 if (prev_focus == target_sibling) {
543 prev_focus = target_sibling->parent->parent;
544 }
545 target_sibling = target_sibling->parent->parent;
520 } 546 }
521 free(criterias); 547
522 cont = container_view_create(focus, view); 548 cont = container_view_create(target_sibling, view);
523 549
524 view->surface = wlr_surface; 550 view->surface = wlr_surface;
525 view->swayc = cont; 551 view->swayc = cont;
@@ -538,9 +564,8 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) {
538 container_set_floating(view->swayc, true); 564 container_set_floating(view->swayc, true);
539 } 565 }
540 566
541 input_manager_set_focus(input_manager, cont); 567 if (prev_focus == target_sibling) {
542 if (workspace) { 568 input_manager_set_focus(input_manager, cont);
543 workspace_switch(workspace);
544 } 569 }
545 570
546 view_update_title(view, false); 571 view_update_title(view, false);
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}