summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar emersion <contact@emersion.fr>2018-08-04 20:41:45 +0100
committerLibravatar GitHub <noreply@github.com>2018-08-04 20:41:45 +0100
commit0016f774407cdb96e6fe3b1b9235119d9b398f8b (patch)
treebc82fb73e33446c5ec0b50c1bae73658e3eeb6b4
parentMerge pull request #2419 from RedSoxFan/fix-2416 (diff)
parentMove workspace pid code to root.c (diff)
downloadsway-0016f774407cdb96e6fe3b1b9235119d9b398f8b.tar.gz
sway-0016f774407cdb96e6fe3b1b9235119d9b398f8b.tar.zst
sway-0016f774407cdb96e6fe3b1b9235119d9b398f8b.zip
Merge pull request #2418 from RyanDwyer/separate-root
Separate root-related code
-rw-r--r--include/sway/scratchpad.h26
-rw-r--r--include/sway/tree/layout.h23
-rw-r--r--include/sway/tree/root.h61
-rw-r--r--include/sway/tree/workspace.h4
-rw-r--r--sway/commands/exec_always.c2
-rw-r--r--sway/commands/move.c5
-rw-r--r--sway/commands/scratchpad.c81
-rw-r--r--sway/main.c3
-rw-r--r--sway/meson.build2
-rw-r--r--sway/scratchpad.c181
-rw-r--r--sway/tree/arrange.c2
-rw-r--r--sway/tree/container.c6
-rw-r--r--sway/tree/layout.c34
-rw-r--r--sway/tree/root.c262
-rw-r--r--sway/tree/view.c2
-rw-r--r--sway/tree/workspace.c113
16 files changed, 413 insertions, 394 deletions
diff --git a/include/sway/scratchpad.h b/include/sway/scratchpad.h
deleted file mode 100644
index 5af5256f..00000000
--- a/include/sway/scratchpad.h
+++ /dev/null
@@ -1,26 +0,0 @@
1#ifndef _SWAY_SCRATCHPAD_H
2#define _SWAY_SCRATCHPAD_H
3
4#include "tree/container.h"
5
6/**
7 * Move a container to the scratchpad.
8 */
9void scratchpad_add_container(struct sway_container *con);
10
11/**
12 * Remove a container from the scratchpad.
13 */
14void scratchpad_remove_container(struct sway_container *con);
15
16/**
17 * Show or hide the next container on the scratchpad.
18 */
19void scratchpad_toggle_auto(void);
20
21/**
22 * Show or hide a specific container on the scratchpad.
23 */
24void scratchpad_toggle_container(struct sway_container *con);
25
26#endif
diff --git a/include/sway/tree/layout.h b/include/sway/tree/layout.h
index a4c31bf6..77cd954b 100644
--- a/include/sway/tree/layout.h
+++ b/include/sway/tree/layout.h
@@ -3,6 +3,7 @@
3#include <wlr/types/wlr_output_layout.h> 3#include <wlr/types/wlr_output_layout.h>
4#include <wlr/render/wlr_texture.h> 4#include <wlr/render/wlr_texture.h>
5#include "sway/tree/container.h" 5#include "sway/tree/container.h"
6#include "sway/tree/root.h"
6#include "config.h" 7#include "config.h"
7 8
8enum movement_direction { 9enum movement_direction {
@@ -24,28 +25,6 @@ enum resize_edge {
24 25
25struct sway_container; 26struct sway_container;
26 27
27struct sway_root {
28 struct wlr_output_layout *output_layout;
29
30 struct wl_listener output_layout_change;
31#ifdef HAVE_XWAYLAND
32 struct wl_list xwayland_unmanaged; // sway_xwayland_unmanaged::link
33#endif
34 struct wl_list drag_icons; // sway_drag_icon::link
35
36 struct wlr_texture *debug_tree;
37
38 struct wl_list outputs; // sway_output::link
39
40 list_t *scratchpad; // struct sway_container
41
42 struct {
43 struct wl_signal new_container;
44 } events;
45};
46
47void layout_init(void);
48
49void container_add_child(struct sway_container *parent, 28void container_add_child(struct sway_container *parent,
50 struct sway_container *child); 29 struct sway_container *child);
51 30
diff --git a/include/sway/tree/root.h b/include/sway/tree/root.h
new file mode 100644
index 00000000..edb7c817
--- /dev/null
+++ b/include/sway/tree/root.h
@@ -0,0 +1,61 @@
1#ifndef _SWAY_ROOT_H
2#define _SWAY_ROOT_H
3#include <wayland-server-core.h>
4#include <wayland-util.h>
5#include <wlr/types/wlr_output_layout.h>
6#include <wlr/render/wlr_texture.h>
7#include "sway/tree/container.h"
8#include "config.h"
9#include "list.h"
10
11extern struct sway_container root_container;
12
13struct sway_root {
14 struct wlr_output_layout *output_layout;
15
16 struct wl_listener output_layout_change;
17#ifdef HAVE_XWAYLAND
18 struct wl_list xwayland_unmanaged; // sway_xwayland_unmanaged::link
19#endif
20 struct wl_list drag_icons; // sway_drag_icon::link
21
22 struct wlr_texture *debug_tree;
23
24 struct wl_list outputs; // sway_output::link
25
26 list_t *scratchpad; // struct sway_container
27
28 struct {
29 struct wl_signal new_container;
30 } events;
31};
32
33void root_create(void);
34
35void root_destroy(void);
36
37/**
38 * Move a container to the scratchpad.
39 */
40void root_scratchpad_add_container(struct sway_container *con);
41
42/**
43 * Remove a container from the scratchpad.
44 */
45void root_scratchpad_remove_container(struct sway_container *con);
46
47/**
48 * Show a single scratchpad container.
49 */
50void root_scratchpad_show(struct sway_container *con);
51
52/**
53 * Hide a single scratchpad container.
54 */
55void root_scratchpad_hide(struct sway_container *con);
56
57struct sway_container *root_workspace_for_pid(pid_t pid);
58
59void root_record_workspace_pid(pid_t pid);
60
61#endif
diff --git a/include/sway/tree/workspace.h b/include/sway/tree/workspace.h
index 5ae0ae3a..3337f2c8 100644
--- a/include/sway/tree/workspace.h
+++ b/include/sway/tree/workspace.h
@@ -44,10 +44,6 @@ void workspace_output_add_priority(struct sway_container *workspace,
44struct sway_container *workspace_output_get_highest_available( 44struct sway_container *workspace_output_get_highest_available(
45 struct sway_container *ws, struct sway_container *exclude); 45 struct sway_container *ws, struct sway_container *exclude);
46 46
47struct sway_container *workspace_for_pid(pid_t pid);
48
49void workspace_record_pid(pid_t pid);
50
51void workspace_detect_urgent(struct sway_container *workspace); 47void workspace_detect_urgent(struct sway_container *workspace);
52 48
53#endif 49#endif
diff --git a/sway/commands/exec_always.c b/sway/commands/exec_always.c
index c730cb8b..00e39ae7 100644
--- a/sway/commands/exec_always.c
+++ b/sway/commands/exec_always.c
@@ -78,7 +78,7 @@ struct cmd_results *cmd_exec_always(int argc, char **argv) {
78 waitpid(pid, NULL, 0); 78 waitpid(pid, NULL, 0);
79 if (child > 0) { 79 if (child > 0) {
80 wlr_log(WLR_DEBUG, "Child process created with pid %d", child); 80 wlr_log(WLR_DEBUG, "Child process created with pid %d", child);
81 workspace_record_pid(child); 81 root_record_workspace_pid(child);
82 } else { 82 } else {
83 return cmd_results_new(CMD_FAILURE, "exec_always", 83 return cmd_results_new(CMD_FAILURE, "exec_always",
84 "Second fork() failed"); 84 "Second fork() failed");
diff --git a/sway/commands/move.c b/sway/commands/move.c
index 1e8b76f9..841da4c4 100644
--- a/sway/commands/move.c
+++ b/sway/commands/move.c
@@ -9,10 +9,9 @@
9#include "sway/input/cursor.h" 9#include "sway/input/cursor.h"
10#include "sway/input/seat.h" 10#include "sway/input/seat.h"
11#include "sway/output.h" 11#include "sway/output.h"
12#include "sway/scratchpad.h"
13#include "sway/tree/arrange.h" 12#include "sway/tree/arrange.h"
14#include "sway/tree/container.h" 13#include "sway/tree/container.h"
15#include "sway/tree/layout.h" 14#include "sway/tree/root.h"
16#include "sway/tree/workspace.h" 15#include "sway/tree/workspace.h"
17#include "stringop.h" 16#include "stringop.h"
18#include "list.h" 17#include "list.h"
@@ -324,7 +323,7 @@ static struct cmd_results *move_to_scratchpad(struct sway_container *con) {
324 return cmd_results_new(CMD_INVALID, "move", 323 return cmd_results_new(CMD_INVALID, "move",
325 "Container is already in the scratchpad"); 324 "Container is already in the scratchpad");
326 } 325 }
327 scratchpad_add_container(con); 326 root_scratchpad_add_container(con);
328 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 327 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
329} 328}
330 329
diff --git a/sway/commands/scratchpad.c b/sway/commands/scratchpad.c
index 01a91d65..0e573aeb 100644
--- a/sway/commands/scratchpad.c
+++ b/sway/commands/scratchpad.c
@@ -1,8 +1,87 @@
1#include "log.h" 1#include "log.h"
2#include "sway/commands.h" 2#include "sway/commands.h"
3#include "sway/config.h" 3#include "sway/config.h"
4#include "sway/scratchpad.h" 4#include "sway/input/input-manager.h"
5#include "sway/input/seat.h"
5#include "sway/tree/container.h" 6#include "sway/tree/container.h"
7#include "sway/tree/root.h"
8#include "sway/tree/workspace.h"
9
10static void scratchpad_toggle_auto(void) {
11 struct sway_seat *seat = input_manager_current_seat(input_manager);
12 struct sway_container *focus = seat_get_focus(seat);
13 struct sway_container *ws = focus->type == C_WORKSPACE ?
14 focus : container_parent(focus, C_WORKSPACE);
15
16 // If the focus is in a floating split container,
17 // operate on the split container instead of the child.
18 if (container_is_floating_or_child(focus)) {
19 while (focus->parent->layout != L_FLOATING) {
20 focus = focus->parent;
21 }
22 }
23
24
25 // Check if the currently focused window is a scratchpad window and should
26 // be hidden again.
27 if (focus->scratchpad) {
28 wlr_log(WLR_DEBUG, "Focus is a scratchpad window - hiding %s",
29 focus->name);
30 root_scratchpad_hide(focus);
31 return;
32 }
33
34 // Check if there is an unfocused scratchpad window on the current workspace
35 // and focus it.
36 for (int i = 0; i < ws->sway_workspace->floating->children->length; ++i) {
37 struct sway_container *floater =
38 ws->sway_workspace->floating->children->items[i];
39 if (floater->scratchpad && focus != floater) {
40 wlr_log(WLR_DEBUG,
41 "Focusing other scratchpad window (%s) in this workspace",
42 floater->name);
43 root_scratchpad_show(floater);
44 return;
45 }
46 }
47
48 // Check if there is a visible scratchpad window on another workspace.
49 // In this case we move it to the current workspace.
50 for (int i = 0; i < root_container.sway_root->scratchpad->length; ++i) {
51 struct sway_container *con =
52 root_container.sway_root->scratchpad->items[i];
53 if (con->parent) {
54 wlr_log(WLR_DEBUG,
55 "Moving a visible scratchpad window (%s) to this workspace",
56 con->name);
57 root_scratchpad_show(con);
58 return;
59 }
60 }
61
62 // Take the container at the bottom of the scratchpad list
63 if (!sway_assert(root_container.sway_root->scratchpad->length,
64 "Scratchpad is empty")) {
65 return;
66 }
67 struct sway_container *con = root_container.sway_root->scratchpad->items[0];
68 wlr_log(WLR_DEBUG, "Showing %s from list", con->name);
69 root_scratchpad_show(con);
70}
71
72static void scratchpad_toggle_container(struct sway_container *con) {
73 if (!sway_assert(con->scratchpad, "Container isn't in the scratchpad")) {
74 return;
75 }
76
77 // Check if it matches a currently visible scratchpad window and hide it.
78 if (con->parent) {
79 root_scratchpad_hide(con);
80 return;
81 }
82
83 root_scratchpad_show(con);
84}
6 85
7struct cmd_results *cmd_scratchpad(int argc, char **argv) { 86struct cmd_results *cmd_scratchpad(int argc, char **argv) {
8 struct cmd_results *error = NULL; 87 struct cmd_results *error = NULL;
diff --git a/sway/main.c b/sway/main.c
index c02caf42..d433368b 100644
--- a/sway/main.c
+++ b/sway/main.c
@@ -407,7 +407,7 @@ int main(int argc, char **argv) {
407 407
408 wlr_log(WLR_INFO, "Starting sway version " SWAY_VERSION); 408 wlr_log(WLR_INFO, "Starting sway version " SWAY_VERSION);
409 409
410 layout_init(); 410 root_create();
411 411
412 if (!server_init(&server)) { 412 if (!server_init(&server)) {
413 return 1; 413 return 1;
@@ -464,6 +464,7 @@ int main(int argc, char **argv) {
464 wlr_log(WLR_INFO, "Shutting down sway"); 464 wlr_log(WLR_INFO, "Shutting down sway");
465 465
466 server_fini(&server); 466 server_fini(&server);
467 root_destroy();
467 468
468 if (config) { 469 if (config) {
469 free_config(config); 470 free_config(config);
diff --git a/sway/meson.build b/sway/meson.build
index 17406f6b..c18fb6e2 100644
--- a/sway/meson.build
+++ b/sway/meson.build
@@ -7,7 +7,6 @@ sway_sources = files(
7 'debug-tree.c', 7 'debug-tree.c',
8 'ipc-json.c', 8 'ipc-json.c',
9 'ipc-server.c', 9 'ipc-server.c',
10 'scratchpad.c',
11 'security.c', 10 'security.c',
12 'swaynag.c', 11 'swaynag.c',
13 12
@@ -150,6 +149,7 @@ sway_sources = files(
150 'tree/arrange.c', 149 'tree/arrange.c',
151 'tree/container.c', 150 'tree/container.c',
152 'tree/layout.c', 151 'tree/layout.c',
152 'tree/root.c',
153 'tree/view.c', 153 'tree/view.c',
154 'tree/workspace.c', 154 'tree/workspace.c',
155 'tree/output.c', 155 'tree/output.c',
diff --git a/sway/scratchpad.c b/sway/scratchpad.c
deleted file mode 100644
index b7d6fd99..00000000
--- a/sway/scratchpad.c
+++ /dev/null
@@ -1,181 +0,0 @@
1#define _XOPEN_SOURCE 700
2#include <stdlib.h>
3#include <stdio.h>
4#include <stdbool.h>
5#include "sway/scratchpad.h"
6#include "sway/input/seat.h"
7#include "sway/tree/arrange.h"
8#include "sway/tree/container.h"
9#include "sway/tree/view.h"
10#include "sway/tree/workspace.h"
11#include "list.h"
12#include "log.h"
13
14void scratchpad_add_container(struct sway_container *con) {
15 if (!sway_assert(!con->scratchpad, "Container is already in scratchpad")) {
16 return;
17 }
18 con->scratchpad = true;
19 list_add(root_container.sway_root->scratchpad, con);
20
21 struct sway_container *parent = con->parent;
22 container_set_floating(con, true);
23 container_remove_child(con);
24 arrange_windows(parent);
25
26 struct sway_seat *seat = input_manager_current_seat(input_manager);
27 seat_set_focus(seat, seat_get_focus_inactive(seat, parent));
28}
29
30void scratchpad_remove_container(struct sway_container *con) {
31 if (!sway_assert(con->scratchpad, "Container is not in scratchpad")) {
32 return;
33 }
34 con->scratchpad = false;
35 for (int i = 0; i < root_container.sway_root->scratchpad->length; ++i) {
36 if (root_container.sway_root->scratchpad->items[i] == con) {
37 list_del(root_container.sway_root->scratchpad, i);
38 break;
39 }
40 }
41}
42
43/**
44 * Show a single scratchpad container.
45 * The container might be visible on another workspace already.
46 */
47static void scratchpad_show(struct sway_container *con) {
48 struct sway_seat *seat = input_manager_current_seat(input_manager);
49 struct sway_container *ws = seat_get_focus(seat);
50 if (ws->type != C_WORKSPACE) {
51 ws = container_parent(ws, C_WORKSPACE);
52 }
53
54 // If the current con or any of its parents are in fullscreen mode, we
55 // first need to disable it before showing the scratchpad con.
56 if (ws->sway_workspace->fullscreen) {
57 container_set_fullscreen(ws->sway_workspace->fullscreen, false);
58 }
59
60 // Show the container
61 if (con->parent) {
62 container_remove_child(con);
63 }
64 container_add_child(ws->sway_workspace->floating, con);
65
66 // Make sure the container's center point overlaps this workspace
67 double center_lx = con->x + con->width / 2;
68 double center_ly = con->y + con->height / 2;
69
70 struct wlr_box workspace_box;
71 container_get_box(ws, &workspace_box);
72 if (!wlr_box_contains_point(&workspace_box, center_lx, center_ly)) {
73 // Maybe resize it
74 if (con->width > ws->width || con->height > ws->height) {
75 container_init_floating(con);
76 }
77
78 // Center it
79 double new_lx = ws->x + (ws->width - con->width) / 2;
80 double new_ly = ws->y + (ws->height - con->height) / 2;
81 container_floating_move_to(con, new_lx, new_ly);
82 }
83
84 arrange_windows(ws);
85 seat_set_focus(seat, seat_get_focus_inactive(seat, con));
86
87 container_set_dirty(con->parent);
88}
89
90/**
91 * Hide a single scratchpad container.
92 * The container might not be the focused container (eg. when using criteria).
93 */
94static void scratchpad_hide(struct sway_container *con) {
95 struct sway_seat *seat = input_manager_current_seat(input_manager);
96 struct sway_container *focus = seat_get_focus(seat);
97 struct sway_container *ws = container_parent(con, C_WORKSPACE);
98
99 container_remove_child(con);
100 arrange_windows(ws);
101 if (con == focus) {
102 seat_set_focus(seat, seat_get_focus_inactive(seat, ws));
103 }
104 list_move_to_end(root_container.sway_root->scratchpad, con);
105}
106
107void scratchpad_toggle_auto(void) {
108 struct sway_seat *seat = input_manager_current_seat(input_manager);
109 struct sway_container *focus = seat_get_focus(seat);
110 struct sway_container *ws = focus->type == C_WORKSPACE ?
111 focus : container_parent(focus, C_WORKSPACE);
112
113 // If the focus is in a floating split container,
114 // operate on the split container instead of the child.
115 if (container_is_floating_or_child(focus)) {
116 while (focus->parent->layout != L_FLOATING) {
117 focus = focus->parent;
118 }
119 }
120
121
122 // Check if the currently focused window is a scratchpad window and should
123 // be hidden again.
124 if (focus->scratchpad) {
125 wlr_log(WLR_DEBUG, "Focus is a scratchpad window - hiding %s",
126 focus->name);
127 scratchpad_hide(focus);
128 return;
129 }
130
131 // Check if there is an unfocused scratchpad window on the current workspace
132 // and focus it.
133 for (int i = 0; i < ws->sway_workspace->floating->children->length; ++i) {
134 struct sway_container *floater =
135 ws->sway_workspace->floating->children->items[i];
136 if (floater->scratchpad && focus != floater) {
137 wlr_log(WLR_DEBUG,
138 "Focusing other scratchpad window (%s) in this workspace",
139 floater->name);
140 scratchpad_show(floater);
141 return;
142 }
143 }
144
145 // Check if there is a visible scratchpad window on another workspace.
146 // In this case we move it to the current workspace.
147 for (int i = 0; i < root_container.sway_root->scratchpad->length; ++i) {
148 struct sway_container *con =
149 root_container.sway_root->scratchpad->items[i];
150 if (con->parent) {
151 wlr_log(WLR_DEBUG,
152 "Moving a visible scratchpad window (%s) to this workspace",
153 con->name);
154 scratchpad_show(con);
155 return;
156 }
157 }
158
159 // Take the container at the bottom of the scratchpad list
160 if (!sway_assert(root_container.sway_root->scratchpad->length,
161 "Scratchpad is empty")) {
162 return;
163 }
164 struct sway_container *con = root_container.sway_root->scratchpad->items[0];
165 wlr_log(WLR_DEBUG, "Showing %s from list", con->name);
166 scratchpad_show(con);
167}
168
169void scratchpad_toggle_container(struct sway_container *con) {
170 if (!sway_assert(con->scratchpad, "Container isn't in the scratchpad")) {
171 return;
172 }
173
174 // Check if it matches a currently visible scratchpad window and hide it.
175 if (con->parent) {
176 scratchpad_hide(con);
177 return;
178 }
179
180 scratchpad_show(con);
181}
diff --git a/sway/tree/arrange.c b/sway/tree/arrange.c
index 5452b13c..494a8461 100644
--- a/sway/tree/arrange.c
+++ b/sway/tree/arrange.c
@@ -14,8 +14,6 @@
14#include "list.h" 14#include "list.h"
15#include "log.h" 15#include "log.h"
16 16
17struct sway_container root_container;
18
19static void apply_horiz_layout(struct sway_container *parent) { 17static void apply_horiz_layout(struct sway_container *parent) {
20 size_t num_children = parent->children->length; 18 size_t num_children = parent->children->length;
21 if (!num_children) { 19 if (!num_children) {
diff --git a/sway/tree/container.c b/sway/tree/container.c
index 4a503652..6da5ac3c 100644
--- a/sway/tree/container.c
+++ b/sway/tree/container.c
@@ -17,7 +17,6 @@
17#include "sway/input/seat.h" 17#include "sway/input/seat.h"
18#include "sway/ipc-server.h" 18#include "sway/ipc-server.h"
19#include "sway/output.h" 19#include "sway/output.h"
20#include "sway/scratchpad.h"
21#include "sway/server.h" 20#include "sway/server.h"
22#include "sway/tree/arrange.h" 21#include "sway/tree/arrange.h"
23#include "sway/tree/layout.h" 22#include "sway/tree/layout.h"
@@ -336,7 +335,6 @@ static struct sway_container *container_destroy_noreaping(
336 // Workspaces will refuse to be destroyed if they're the last workspace 335 // Workspaces will refuse to be destroyed if they're the last workspace
337 // on their output. 336 // on their output.
338 if (!container_workspace_destroy(con)) { 337 if (!container_workspace_destroy(con)) {
339 wlr_log(WLR_ERROR, "workspace doesn't want to destroy");
340 return NULL; 338 return NULL;
341 } 339 }
342 } 340 }
@@ -347,7 +345,7 @@ static struct sway_container *container_destroy_noreaping(
347 container_set_dirty(con); 345 container_set_dirty(con);
348 346
349 if (con->scratchpad) { 347 if (con->scratchpad) {
350 scratchpad_remove_container(con); 348 root_scratchpad_remove_container(con);
351 } 349 }
352 350
353 if (!con->parent) { 351 if (!con->parent) {
@@ -1097,7 +1095,7 @@ void container_set_floating(struct sway_container *container, bool enable) {
1097 } else { 1095 } else {
1098 // Returning to tiled 1096 // Returning to tiled
1099 if (container->scratchpad) { 1097 if (container->scratchpad) {
1100 scratchpad_remove_container(container); 1098 root_scratchpad_remove_container(container);
1101 } 1099 }
1102 container_remove_child(container); 1100 container_remove_child(container);
1103 struct sway_container *reference = 1101 struct sway_container *reference =
diff --git a/sway/tree/layout.c b/sway/tree/layout.c
index 1f82e534..07de9664 100644
--- a/sway/tree/layout.c
+++ b/sway/tree/layout.c
@@ -19,40 +19,6 @@
19#include "list.h" 19#include "list.h"
20#include "log.h" 20#include "log.h"
21 21
22struct sway_container root_container;
23
24static void output_layout_handle_change(struct wl_listener *listener,
25 void *data) {
26 arrange_windows(&root_container);
27 transaction_commit_dirty();
28}
29
30void layout_init(void) {
31 root_container.id = 0; // normally assigned in new_swayc()
32 root_container.type = C_ROOT;
33 root_container.layout = L_NONE;
34 root_container.name = strdup("root");
35 root_container.instructions = create_list();
36 root_container.children = create_list();
37 root_container.current.children = create_list();
38 wl_signal_init(&root_container.events.destroy);
39
40 root_container.sway_root = calloc(1, sizeof(*root_container.sway_root));
41 root_container.sway_root->output_layout = wlr_output_layout_create();
42 wl_list_init(&root_container.sway_root->outputs);
43#ifdef HAVE_XWAYLAND
44 wl_list_init(&root_container.sway_root->xwayland_unmanaged);
45#endif
46 wl_list_init(&root_container.sway_root->drag_icons);
47 wl_signal_init(&root_container.sway_root->events.new_container);
48 root_container.sway_root->scratchpad = create_list();
49
50 root_container.sway_root->output_layout_change.notify =
51 output_layout_handle_change;
52 wl_signal_add(&root_container.sway_root->output_layout->events.change,
53 &root_container.sway_root->output_layout_change);
54}
55
56static int index_child(const struct sway_container *child) { 22static int index_child(const struct sway_container *child) {
57 struct sway_container *parent = child->parent; 23 struct sway_container *parent = child->parent;
58 for (int i = 0; i < parent->children->length; ++i) { 24 for (int i = 0; i < parent->children->length; ++i) {
diff --git a/sway/tree/root.c b/sway/tree/root.c
new file mode 100644
index 00000000..79f2194e
--- /dev/null
+++ b/sway/tree/root.c
@@ -0,0 +1,262 @@
1#define _POSIX_C_SOURCE 200809L
2#include <stdbool.h>
3#include <stdlib.h>
4#include <string.h>
5#include <wlr/types/wlr_output_layout.h>
6#include "sway/input/seat.h"
7#include "sway/output.h"
8#include "sway/tree/arrange.h"
9#include "sway/tree/container.h"
10#include "sway/tree/root.h"
11#include "sway/tree/workspace.h"
12#include "list.h"
13#include "log.h"
14#include "util.h"
15
16struct sway_container root_container;
17
18static void output_layout_handle_change(struct wl_listener *listener,
19 void *data) {
20 arrange_windows(&root_container);
21 transaction_commit_dirty();
22}
23
24void root_create(void) {
25 root_container.id = 0; // normally assigned in new_swayc()
26 root_container.type = C_ROOT;
27 root_container.layout = L_NONE;
28 root_container.name = strdup("root");
29 root_container.instructions = create_list();
30 root_container.children = create_list();
31 root_container.current.children = create_list();
32 wl_signal_init(&root_container.events.destroy);
33
34 root_container.sway_root = calloc(1, sizeof(*root_container.sway_root));
35 root_container.sway_root->output_layout = wlr_output_layout_create();
36 wl_list_init(&root_container.sway_root->outputs);
37#ifdef HAVE_XWAYLAND
38 wl_list_init(&root_container.sway_root->xwayland_unmanaged);
39#endif
40 wl_list_init(&root_container.sway_root->drag_icons);
41 wl_signal_init(&root_container.sway_root->events.new_container);
42 root_container.sway_root->scratchpad = create_list();
43
44 root_container.sway_root->output_layout_change.notify =
45 output_layout_handle_change;
46 wl_signal_add(&root_container.sway_root->output_layout->events.change,
47 &root_container.sway_root->output_layout_change);
48}
49
50void root_destroy(void) {
51 // sway_root
52 wl_list_remove(&root_container.sway_root->output_layout_change.link);
53 list_free(root_container.sway_root->scratchpad);
54 wlr_output_layout_destroy(root_container.sway_root->output_layout);
55 free(root_container.sway_root);
56
57 // root_container
58 list_free(root_container.instructions);
59 list_free(root_container.children);
60 list_free(root_container.current.children);
61 free(root_container.name);
62
63 memset(&root_container, 0, sizeof(root_container));
64}
65
66void root_scratchpad_add_container(struct sway_container *con) {
67 if (!sway_assert(!con->scratchpad, "Container is already in scratchpad")) {
68 return;
69 }
70 con->scratchpad = true;
71 list_add(root_container.sway_root->scratchpad, con);
72
73 struct sway_container *parent = con->parent;
74 container_set_floating(con, true);
75 container_remove_child(con);
76 arrange_windows(parent);
77
78 struct sway_seat *seat = input_manager_current_seat(input_manager);
79 seat_set_focus(seat, seat_get_focus_inactive(seat, parent));
80}
81
82void root_scratchpad_remove_container(struct sway_container *con) {
83 if (!sway_assert(con->scratchpad, "Container is not in scratchpad")) {
84 return;
85 }
86 con->scratchpad = false;
87 for (int i = 0; i < root_container.sway_root->scratchpad->length; ++i) {
88 if (root_container.sway_root->scratchpad->items[i] == con) {
89 list_del(root_container.sway_root->scratchpad, i);
90 break;
91 }
92 }
93}
94
95void root_scratchpad_show(struct sway_container *con) {
96 struct sway_seat *seat = input_manager_current_seat(input_manager);
97 struct sway_container *ws = seat_get_focus(seat);
98 if (ws->type != C_WORKSPACE) {
99 ws = container_parent(ws, C_WORKSPACE);
100 }
101
102 // If the current con or any of its parents are in fullscreen mode, we
103 // first need to disable it before showing the scratchpad con.
104 if (ws->sway_workspace->fullscreen) {
105 container_set_fullscreen(ws->sway_workspace->fullscreen, false);
106 }
107
108 // Show the container
109 if (con->parent) {
110 container_remove_child(con);
111 }
112 container_add_child(ws->sway_workspace->floating, con);
113
114 // Make sure the container's center point overlaps this workspace
115 double center_lx = con->x + con->width / 2;
116 double center_ly = con->y + con->height / 2;
117
118 struct wlr_box workspace_box;
119 container_get_box(ws, &workspace_box);
120 if (!wlr_box_contains_point(&workspace_box, center_lx, center_ly)) {
121 // Maybe resize it
122 if (con->width > ws->width || con->height > ws->height) {
123 container_init_floating(con);
124 }
125
126 // Center it
127 double new_lx = ws->x + (ws->width - con->width) / 2;
128 double new_ly = ws->y + (ws->height - con->height) / 2;
129 container_floating_move_to(con, new_lx, new_ly);
130 }
131
132 arrange_windows(ws);
133 seat_set_focus(seat, seat_get_focus_inactive(seat, con));
134
135 container_set_dirty(con->parent);
136}
137
138void root_scratchpad_hide(struct sway_container *con) {
139 struct sway_seat *seat = input_manager_current_seat(input_manager);
140 struct sway_container *focus = seat_get_focus(seat);
141 struct sway_container *ws = container_parent(con, C_WORKSPACE);
142
143 container_remove_child(con);
144 arrange_windows(ws);
145 if (con == focus) {
146 seat_set_focus(seat, seat_get_focus_inactive(seat, ws));
147 }
148 list_move_to_end(root_container.sway_root->scratchpad, con);
149}
150
151struct pid_workspace {
152 pid_t pid;
153 char *workspace;
154 struct timespec time_added;
155
156 struct sway_container *output;
157 struct wl_listener output_destroy;
158
159 struct wl_list link;
160};
161
162static struct wl_list pid_workspaces;
163
164struct sway_container *root_workspace_for_pid(pid_t pid) {
165 if (!pid_workspaces.prev && !pid_workspaces.next) {
166 wl_list_init(&pid_workspaces);
167 return NULL;
168 }
169
170 struct sway_container *ws = NULL;
171 struct pid_workspace *pw = NULL;
172
173 wlr_log(WLR_DEBUG, "Looking up workspace for pid %d", pid);
174
175 do {
176 struct pid_workspace *_pw = NULL;
177 wl_list_for_each(_pw, &pid_workspaces, link) {
178 if (pid == _pw->pid) {
179 pw = _pw;
180 wlr_log(WLR_DEBUG,
181 "found pid_workspace for pid %d, workspace %s",
182 pid, pw->workspace);
183 goto found;
184 }
185 }
186 pid = get_parent_pid(pid);
187 } while (pid > 1);
188found:
189
190 if (pw && pw->workspace) {
191 ws = workspace_by_name(pw->workspace);
192
193 if (!ws) {
194 wlr_log(WLR_DEBUG,
195 "Creating workspace %s for pid %d because it disappeared",
196 pw->workspace, pid);
197 ws = workspace_create(pw->output, pw->workspace);
198 }
199
200 wl_list_remove(&pw->output_destroy.link);
201 wl_list_remove(&pw->link);
202 free(pw->workspace);
203 free(pw);
204 }
205
206 return ws;
207}
208
209static void pw_handle_output_destroy(struct wl_listener *listener, void *data) {
210 struct pid_workspace *pw = wl_container_of(listener, pw, output_destroy);
211 pw->output = NULL;
212 wl_list_remove(&pw->output_destroy.link);
213 wl_list_init(&pw->output_destroy.link);
214}
215
216void root_record_workspace_pid(pid_t pid) {
217 wlr_log(WLR_DEBUG, "Recording workspace for process %d", pid);
218 if (!pid_workspaces.prev && !pid_workspaces.next) {
219 wl_list_init(&pid_workspaces);
220 }
221
222 struct sway_seat *seat = input_manager_current_seat(input_manager);
223 struct sway_container *ws =
224 seat_get_focus_inactive(seat, &root_container);
225 if (ws && ws->type != C_WORKSPACE) {
226 ws = container_parent(ws, C_WORKSPACE);
227 }
228 if (!ws) {
229 wlr_log(WLR_DEBUG, "Bailing out, no workspace");
230 return;
231 }
232 struct sway_container *output = ws->parent;
233 if (!output) {
234 wlr_log(WLR_DEBUG, "Bailing out, no output");
235 return;
236 }
237
238 struct timespec now;
239 clock_gettime(CLOCK_MONOTONIC, &now);
240
241 // Remove expired entries
242 static const int timeout = 60;
243 struct pid_workspace *old, *_old;
244 wl_list_for_each_safe(old, _old, &pid_workspaces, link) {
245 if (now.tv_sec - old->time_added.tv_sec >= timeout) {
246 wl_list_remove(&old->output_destroy.link);
247 wl_list_remove(&old->link);
248 free(old->workspace);
249 free(old);
250 }
251 }
252
253 struct pid_workspace *pw = calloc(1, sizeof(struct pid_workspace));
254 pw->workspace = strdup(ws->name);
255 pw->output = output;
256 pw->pid = pid;
257 memcpy(&pw->time_added, &now, sizeof(struct timespec));
258 pw->output_destroy.notify = pw_handle_output_destroy;
259 wl_signal_add(&output->sway_output->wlr_output->events.destroy,
260 &pw->output_destroy);
261 wl_list_insert(&pid_workspaces, &pw->link);
262}
diff --git a/sway/tree/view.c b/sway/tree/view.c
index 78baa705..9465b3a1 100644
--- a/sway/tree/view.c
+++ b/sway/tree/view.c
@@ -490,7 +490,7 @@ static struct sway_container *select_workspace(struct sway_view *view) {
490 wl_resource_get_client(view->surface->resource); 490 wl_resource_get_client(view->surface->resource);
491 wl_client_get_credentials(client, &pid, NULL, NULL); 491 wl_client_get_credentials(client, &pid, NULL, NULL);
492#endif 492#endif
493 ws = workspace_for_pid(pid); 493 ws = root_workspace_for_pid(pid);
494 if (ws) { 494 if (ws) {
495 return ws; 495 return ws;
496 } 496 }
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c
index 687d9c95..cc225e79 100644
--- a/sway/tree/workspace.c
+++ b/sway/tree/workspace.c
@@ -539,116 +539,3 @@ void workspace_detect_urgent(struct sway_container *workspace) {
539 container_damage_whole(workspace); 539 container_damage_whole(workspace);
540 } 540 }
541} 541}
542
543struct pid_workspace {
544 pid_t pid;
545 char *workspace;
546 struct timespec time_added;
547
548 struct sway_container *output;
549 struct wl_listener output_destroy;
550
551 struct wl_list link;
552};
553
554static struct wl_list pid_workspaces;
555
556struct sway_container *workspace_for_pid(pid_t pid) {
557 if (!pid_workspaces.prev && !pid_workspaces.next) {
558 wl_list_init(&pid_workspaces);
559 return NULL;
560 }
561
562 struct sway_container *ws = NULL;
563 struct pid_workspace *pw = NULL;
564
565 wlr_log(WLR_DEBUG, "Looking up workspace for pid %d", pid);
566
567 do {
568 struct pid_workspace *_pw = NULL;
569 wl_list_for_each(_pw, &pid_workspaces, link) {
570 if (pid == _pw->pid) {
571 pw = _pw;
572 wlr_log(WLR_DEBUG,
573 "found pid_workspace for pid %d, workspace %s",
574 pid, pw->workspace);
575 goto found;
576 }
577 }
578 pid = get_parent_pid(pid);
579 } while (pid > 1);
580found:
581
582 if (pw && pw->workspace) {
583 ws = workspace_by_name(pw->workspace);
584
585 if (!ws) {
586 wlr_log(WLR_DEBUG,
587 "Creating workspace %s for pid %d because it disappeared",
588 pw->workspace, pid);
589 ws = workspace_create(pw->output, pw->workspace);
590 }
591
592 wl_list_remove(&pw->output_destroy.link);
593 wl_list_remove(&pw->link);
594 free(pw->workspace);
595 free(pw);
596 }
597
598 return ws;
599}
600
601static void pw_handle_output_destroy(struct wl_listener *listener, void *data) {
602 struct pid_workspace *pw = wl_container_of(listener, pw, output_destroy);
603 pw->output = NULL;
604 wl_list_remove(&pw->output_destroy.link);
605 wl_list_init(&pw->output_destroy.link);
606}
607
608void workspace_record_pid(pid_t pid) {
609 wlr_log(WLR_DEBUG, "Recording workspace for process %d", pid);
610 if (!pid_workspaces.prev && !pid_workspaces.next) {
611 wl_list_init(&pid_workspaces);
612 }
613
614 struct sway_seat *seat = input_manager_current_seat(input_manager);
615 struct sway_container *ws =
616 seat_get_focus_inactive(seat, &root_container);
617 if (ws && ws->type != C_WORKSPACE) {
618 ws = container_parent(ws, C_WORKSPACE);
619 }
620 if (!ws) {
621 wlr_log(WLR_DEBUG, "Bailing out, no workspace");
622 return;
623 }
624 struct sway_container *output = ws->parent;
625 if (!output) {
626 wlr_log(WLR_DEBUG, "Bailing out, no output");
627 return;
628 }
629
630 struct timespec now;
631 clock_gettime(CLOCK_MONOTONIC, &now);
632
633 // Remove expired entries
634 static const int timeout = 60;
635 struct pid_workspace *old, *_old;
636 wl_list_for_each_safe(old, _old, &pid_workspaces, link) {
637 if (now.tv_sec - old->time_added.tv_sec >= timeout) {
638 wl_list_remove(&old->output_destroy.link);
639 wl_list_remove(&old->link);
640 free(old->workspace);
641 free(old);
642 }
643 }
644
645 struct pid_workspace *pw = calloc(1, sizeof(struct pid_workspace));
646 pw->workspace = strdup(ws->name);
647 pw->output = output;
648 pw->pid = pid;
649 memcpy(&pw->time_added, &now, sizeof(struct timespec));
650 pw->output_destroy.notify = pw_handle_output_destroy;
651 wl_signal_add(&output->sway_output->wlr_output->events.destroy,
652 &pw->output_destroy);
653 wl_list_insert(&pid_workspaces, &pw->link);
654}