aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/sway/ipc-server.h1
-rw-r--r--include/sway/tree/container.h2
-rw-r--r--include/sway/tree/view.h9
-rw-r--r--include/sway/tree/workspace.h7
-rw-r--r--sway/commands.c1
-rw-r--r--sway/commands/fullscreen.c37
-rw-r--r--sway/desktop/output.c38
-rw-r--r--sway/desktop/wl_shell.c35
-rw-r--r--sway/desktop/xdg_shell_v6.c35
-rw-r--r--sway/desktop/xwayland.c26
-rw-r--r--sway/input/cursor.c11
-rw-r--r--sway/input/seat.c16
-rw-r--r--sway/meson.build1
-rw-r--r--sway/tree/container.c1
-rw-r--r--sway/tree/layout.c116
-rw-r--r--sway/tree/view.c51
-rw-r--r--sway/tree/workspace.c7
17 files changed, 361 insertions, 33 deletions
diff --git a/include/sway/ipc-server.h b/include/sway/ipc-server.h
index c3389fe8..dd16a175 100644
--- a/include/sway/ipc-server.h
+++ b/include/sway/ipc-server.h
@@ -1,6 +1,7 @@
1#ifndef _SWAY_IPC_SERVER_H 1#ifndef _SWAY_IPC_SERVER_H
2#define _SWAY_IPC_SERVER_H 2#define _SWAY_IPC_SERVER_H
3#include <sys/socket.h> 3#include <sys/socket.h>
4#include "sway/config.h"
4#include "sway/tree/container.h" 5#include "sway/tree/container.h"
5#include "ipc.h" 6#include "ipc.h"
6 7
diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h
index 2a8b8aba..6efda72f 100644
--- a/include/sway/tree/container.h
+++ b/include/sway/tree/container.h
@@ -45,6 +45,7 @@ enum sway_container_border {
45 45
46struct sway_root; 46struct sway_root;
47struct sway_output; 47struct sway_output;
48struct sway_workspace;
48struct sway_view; 49struct sway_view;
49 50
50struct sway_container { 51struct sway_container {
@@ -52,6 +53,7 @@ struct sway_container {
52 // TODO: Encapsulate state for other node types as well like C_CONTAINER 53 // TODO: Encapsulate state for other node types as well like C_CONTAINER
53 struct sway_root *sway_root; 54 struct sway_root *sway_root;
54 struct sway_output *sway_output; 55 struct sway_output *sway_output;
56 struct sway_workspace *sway_workspace;
55 struct sway_view *sway_view; 57 struct sway_view *sway_view;
56 }; 58 };
57 59
diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h
index b51c54b5..648a74c4 100644
--- a/include/sway/tree/view.h
+++ b/include/sway/tree/view.h
@@ -28,6 +28,7 @@ struct sway_view_impl {
28 void (*configure)(struct sway_view *view, double ox, double oy, int width, 28 void (*configure)(struct sway_view *view, double ox, double oy, int width,
29 int height); 29 int height);
30 void (*set_activated)(struct sway_view *view, bool activated); 30 void (*set_activated)(struct sway_view *view, bool activated);
31 void (*set_fullscreen)(struct sway_view *view, bool fullscreen);
31 void (*for_each_surface)(struct sway_view *view, 32 void (*for_each_surface)(struct sway_view *view,
32 wlr_surface_iterator_func_t iterator, void *user_data); 33 wlr_surface_iterator_func_t iterator, void *user_data);
33 void (*close)(struct sway_view *view); 34 void (*close)(struct sway_view *view);
@@ -41,6 +42,7 @@ struct sway_view {
41 struct sway_container *swayc; // NULL for unmanaged views 42 struct sway_container *swayc; // NULL for unmanaged views
42 struct wlr_surface *surface; // NULL for unmapped views 43 struct wlr_surface *surface; // NULL for unmapped views
43 int width, height; 44 int width, height;
45 bool is_fullscreen;
44 46
45 union { 47 union {
46 struct wlr_xdg_surface_v6 *wlr_xdg_surface_v6; 48 struct wlr_xdg_surface_v6 *wlr_xdg_surface_v6;
@@ -63,6 +65,7 @@ struct sway_xdg_shell_v6_view {
63 struct wl_listener request_move; 65 struct wl_listener request_move;
64 struct wl_listener request_resize; 66 struct wl_listener request_resize;
65 struct wl_listener request_maximize; 67 struct wl_listener request_maximize;
68 struct wl_listener request_fullscreen;
66 struct wl_listener new_popup; 69 struct wl_listener new_popup;
67 struct wl_listener map; 70 struct wl_listener map;
68 struct wl_listener unmap; 71 struct wl_listener unmap;
@@ -79,6 +82,7 @@ struct sway_xwayland_view {
79 struct wl_listener request_resize; 82 struct wl_listener request_resize;
80 struct wl_listener request_maximize; 83 struct wl_listener request_maximize;
81 struct wl_listener request_configure; 84 struct wl_listener request_configure;
85 struct wl_listener request_fullscreen;
82 struct wl_listener map; 86 struct wl_listener map;
83 struct wl_listener unmap; 87 struct wl_listener unmap;
84 struct wl_listener destroy; 88 struct wl_listener destroy;
@@ -93,6 +97,7 @@ struct sway_xwayland_unmanaged {
93 int lx, ly; 97 int lx, ly;
94 98
95 struct wl_listener request_configure; 99 struct wl_listener request_configure;
100 struct wl_listener request_fullscreen;
96 struct wl_listener commit; 101 struct wl_listener commit;
97 struct wl_listener map; 102 struct wl_listener map;
98 struct wl_listener unmap; 103 struct wl_listener unmap;
@@ -106,6 +111,8 @@ struct sway_wl_shell_view {
106 struct wl_listener request_move; 111 struct wl_listener request_move;
107 struct wl_listener request_resize; 112 struct wl_listener request_resize;
108 struct wl_listener request_maximize; 113 struct wl_listener request_maximize;
114 struct wl_listener request_fullscreen;
115 struct wl_listener set_state;
109 struct wl_listener destroy; 116 struct wl_listener destroy;
110 117
111 int pending_width, pending_height; 118 int pending_width, pending_height;
@@ -155,6 +162,8 @@ void view_configure(struct sway_view *view, double ox, double oy, int width,
155 162
156void view_set_activated(struct sway_view *view, bool activated); 163void view_set_activated(struct sway_view *view, bool activated);
157 164
165void view_set_fullscreen(struct sway_view *view, bool fullscreen);
166
158void view_close(struct sway_view *view); 167void view_close(struct sway_view *view);
159 168
160void view_damage(struct sway_view *view, bool whole); 169void view_damage(struct sway_view *view, bool whole);
diff --git a/include/sway/tree/workspace.h b/include/sway/tree/workspace.h
index 8d49fefb..35e1df3b 100644
--- a/include/sway/tree/workspace.h
+++ b/include/sway/tree/workspace.h
@@ -3,6 +3,13 @@
3 3
4#include "sway/tree/container.h" 4#include "sway/tree/container.h"
5 5
6struct sway_view;
7
8struct sway_workspace {
9 struct sway_container *swayc;
10 struct sway_view *fullscreen;
11};
12
6extern char *prev_workspace_name; 13extern char *prev_workspace_name;
7 14
8char *workspace_next_name(const char *output_name); 15char *workspace_next_name(const char *output_name);
diff --git a/sway/commands.c b/sway/commands.c
index fb3eaa75..2115bd8c 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -99,6 +99,7 @@ static struct cmd_handler handlers[] = {
99 { "exec", cmd_exec }, 99 { "exec", cmd_exec },
100 { "exec_always", cmd_exec_always }, 100 { "exec_always", cmd_exec_always },
101 { "focus_follows_mouse", cmd_focus_follows_mouse }, 101 { "focus_follows_mouse", cmd_focus_follows_mouse },
102 { "fullscreen", cmd_fullscreen },
102 { "include", cmd_include }, 103 { "include", cmd_include },
103 { "input", cmd_input }, 104 { "input", cmd_input },
104 { "mode", cmd_mode }, 105 { "mode", cmd_mode },
diff --git a/sway/commands/fullscreen.c b/sway/commands/fullscreen.c
new file mode 100644
index 00000000..8692e92d
--- /dev/null
+++ b/sway/commands/fullscreen.c
@@ -0,0 +1,37 @@
1#include <wlr/types/wlr_wl_shell.h>
2#include "log.h"
3#include "sway/commands.h"
4#include "sway/config.h"
5#include "sway/tree/container.h"
6#include "sway/tree/view.h"
7#include "sway/tree/layout.h"
8
9struct cmd_results *cmd_fullscreen(int argc, char **argv) {
10 struct cmd_results *error = NULL;
11 if ((error = checkarg(argc, "fullscreen", EXPECTED_LESS_THAN, 2))) {
12 return error;
13 }
14 struct sway_container *container =
15 config->handler_context.current_container;
16 if (container->type != C_VIEW) {
17 return cmd_results_new(CMD_INVALID, "fullscreen",
18 "Only views can fullscreen");
19 }
20 struct sway_view *view = container->sway_view;
21 bool wants_fullscreen;
22
23 if (argc == 0 || strcmp(argv[0], "toggle") == 0) {
24 wants_fullscreen = !view->is_fullscreen;
25 } else if (strcmp(argv[0], "enable") == 0) {
26 wants_fullscreen = true;
27 } else if (strcmp(argv[0], "disable") == 0) {
28 wants_fullscreen = false;
29 } else {
30 return cmd_results_new(CMD_INVALID, "fullscreen",
31 "Expected 'fullscreen' or 'fullscreen <enable|disable|toggle>'");
32 }
33
34 view_set_fullscreen(view, wants_fullscreen);
35
36 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
37}
diff --git a/sway/desktop/output.c b/sway/desktop/output.c
index 1b3143d0..8d25caae 100644
--- a/sway/desktop/output.c
+++ b/sway/desktop/output.c
@@ -22,6 +22,7 @@
22#include "sway/tree/container.h" 22#include "sway/tree/container.h"
23#include "sway/tree/layout.h" 23#include "sway/tree/layout.h"
24#include "sway/tree/view.h" 24#include "sway/tree/view.h"
25#include "sway/tree/workspace.h"
25 26
26struct sway_container *output_by_name(const char *name) { 27struct sway_container *output_by_name(const char *name) {
27 for (int i = 0; i < root_container.children->length; ++i) { 28 for (int i = 0; i < root_container.children->length; ++i) {
@@ -228,7 +229,11 @@ static void render_container_iterator(struct sway_container *con,
228 229
229static void render_container(struct sway_output *output, 230static void render_container(struct sway_output *output,
230 struct sway_container *con) { 231 struct sway_container *con) {
231 container_descendants(con, C_VIEW, render_container_iterator, output); 232 if (con->type == C_VIEW) { // Happens if a view is fullscreened
233 render_container_iterator(con, output);
234 } else {
235 container_descendants(con, C_VIEW, render_container_iterator, output);
236 }
232} 237}
233 238
234static struct sway_container *output_get_active_workspace( 239static struct sway_container *output_get_active_workspace(
@@ -270,19 +275,26 @@ static void render_output(struct sway_output *output, struct timespec *when,
270 wlr_output_transformed_resolution(wlr_output, &width, &height); 275 wlr_output_transformed_resolution(wlr_output, &width, &height);
271 pixman_region32_union_rect(damage, damage, 0, 0, width, height); 276 pixman_region32_union_rect(damage, damage, 0, 0, width, height);
272 277
273 float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f}; 278 struct sway_container *workspace = output_get_active_workspace(output);
274 wlr_renderer_clear(renderer, clear_color);
275 279
276 render_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); 280 if (workspace->sway_workspace->fullscreen) {
277 render_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); 281 float clear_color[] = {0.0f, 0.0f, 0.0f, 1.0f};
282 wlr_renderer_clear(renderer, clear_color);
283 // TODO: handle views smaller than the output
284 render_container(output, workspace->sway_workspace->fullscreen->swayc);
285 } else {
286 float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f};
287 wlr_renderer_clear(renderer, clear_color);
278 288
279 struct sway_container *workspace = output_get_active_workspace(output); 289 render_layer(output,
280 render_container(output, workspace); 290 &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]);
291 render_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]);
281 292
282 render_unmanaged(output, &root_container.sway_root->xwayland_unmanaged); 293 render_container(output, workspace);
283 294
284 // TODO: consider revising this when fullscreen windows are supported 295 render_unmanaged(output, &root_container.sway_root->xwayland_unmanaged);
285 render_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); 296 render_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]);
297 }
286 render_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); 298 render_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]);
287 299
288renderer_end: 300renderer_end:
@@ -462,6 +474,12 @@ void output_damage_view(struct sway_output *output, struct sway_view *view,
462 return; 474 return;
463 } 475 }
464 476
477 struct sway_container *workspace = container_parent(view->swayc,
478 C_WORKSPACE);
479 if (workspace->sway_workspace->fullscreen && !view->is_fullscreen) {
480 return;
481 }
482
465 struct damage_data data = { 483 struct damage_data data = {
466 .output = output, 484 .output = output,
467 .whole = whole, 485 .whole = whole,
diff --git a/sway/desktop/wl_shell.c b/sway/desktop/wl_shell.c
index b63c220c..2d666d95 100644
--- a/sway/desktop/wl_shell.c
+++ b/sway/desktop/wl_shell.c
@@ -61,14 +61,21 @@ static void destroy(struct sway_view *view) {
61 } 61 }
62 wl_list_remove(&wl_shell_view->commit.link); 62 wl_list_remove(&wl_shell_view->commit.link);
63 wl_list_remove(&wl_shell_view->destroy.link); 63 wl_list_remove(&wl_shell_view->destroy.link);
64 wl_list_remove(&wl_shell_view->request_fullscreen.link);
65 wl_list_remove(&wl_shell_view->set_state.link);
64 free(wl_shell_view); 66 free(wl_shell_view);
65} 67}
66 68
69static void set_fullscreen(struct sway_view *view, bool fullscreen) {
70 // TODO
71}
72
67static const struct sway_view_impl view_impl = { 73static const struct sway_view_impl view_impl = {
68 .get_prop = get_prop, 74 .get_prop = get_prop,
69 .configure = configure, 75 .configure = configure,
70 .close = _close, 76 .close = _close,
71 .destroy = destroy, 77 .destroy = destroy,
78 .set_fullscreen = set_fullscreen,
72}; 79};
73 80
74static void handle_commit(struct wl_listener *listener, void *data) { 81static void handle_commit(struct wl_listener *listener, void *data) {
@@ -88,6 +95,23 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
88 view_destroy(&wl_shell_view->view); 95 view_destroy(&wl_shell_view->view);
89} 96}
90 97
98static void handle_request_fullscreen(struct wl_listener *listener, void *data) {
99 struct sway_wl_shell_view *wl_shell_view =
100 wl_container_of(listener, wl_shell_view, request_fullscreen);
101 view_set_fullscreen(&wl_shell_view->view, true);
102}
103
104static void handle_set_state(struct wl_listener *listener, void *data) {
105 struct sway_wl_shell_view *wl_shell_view =
106 wl_container_of(listener, wl_shell_view, set_state);
107 struct sway_view *view = &wl_shell_view->view;
108 struct wlr_wl_shell_surface *surface = view->wlr_wl_shell_surface;
109 if (view->is_fullscreen &&
110 surface->state != WLR_WL_SHELL_SURFACE_STATE_FULLSCREEN) {
111 view_set_fullscreen(view, false);
112 }
113}
114
91void handle_wl_shell_surface(struct wl_listener *listener, void *data) { 115void handle_wl_shell_surface(struct wl_listener *listener, void *data) {
92 struct sway_server *server = wl_container_of(listener, server, 116 struct sway_server *server = wl_container_of(listener, server,
93 wl_shell_surface); 117 wl_shell_surface);
@@ -127,5 +151,16 @@ void handle_wl_shell_surface(struct wl_listener *listener, void *data) {
127 wl_shell_view->destroy.notify = handle_destroy; 151 wl_shell_view->destroy.notify = handle_destroy;
128 wl_signal_add(&shell_surface->events.destroy, &wl_shell_view->destroy); 152 wl_signal_add(&shell_surface->events.destroy, &wl_shell_view->destroy);
129 153
154 wl_shell_view->request_fullscreen.notify = handle_request_fullscreen;
155 wl_signal_add(&shell_surface->events.request_fullscreen,
156 &wl_shell_view->request_fullscreen);
157
158 wl_shell_view->set_state.notify = handle_set_state;
159 wl_signal_add(&shell_surface->events.set_state, &wl_shell_view->set_state);
160
130 view_map(&wl_shell_view->view, shell_surface->surface); 161 view_map(&wl_shell_view->view, shell_surface->surface);
162
163 if (shell_surface->state == WLR_WL_SHELL_SURFACE_STATE_FULLSCREEN) {
164 view_set_fullscreen(&wl_shell_view->view, true);
165 }
131} 166}
diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c
index e4703040..fdfb9346 100644
--- a/sway/desktop/xdg_shell_v6.c
+++ b/sway/desktop/xdg_shell_v6.c
@@ -118,6 +118,14 @@ static void set_activated(struct sway_view *view, bool activated) {
118 } 118 }
119} 119}
120 120
121static void set_fullscreen(struct sway_view *view, bool fullscreen) {
122 if (xdg_shell_v6_view_from_view(view) == NULL) {
123 return;
124 }
125 struct wlr_xdg_surface_v6 *surface = view->wlr_xdg_surface_v6;
126 wlr_xdg_toplevel_v6_set_fullscreen(surface, fullscreen);
127}
128
121static void for_each_surface(struct sway_view *view, 129static void for_each_surface(struct sway_view *view,
122 wlr_surface_iterator_func_t iterator, void *user_data) { 130 wlr_surface_iterator_func_t iterator, void *user_data) {
123 if (xdg_shell_v6_view_from_view(view) == NULL) { 131 if (xdg_shell_v6_view_from_view(view) == NULL) {
@@ -146,6 +154,7 @@ static void destroy(struct sway_view *view) {
146 wl_list_remove(&xdg_shell_v6_view->destroy.link); 154 wl_list_remove(&xdg_shell_v6_view->destroy.link);
147 wl_list_remove(&xdg_shell_v6_view->map.link); 155 wl_list_remove(&xdg_shell_v6_view->map.link);
148 wl_list_remove(&xdg_shell_v6_view->unmap.link); 156 wl_list_remove(&xdg_shell_v6_view->unmap.link);
157 wl_list_remove(&xdg_shell_v6_view->request_fullscreen.link);
149 free(xdg_shell_v6_view); 158 free(xdg_shell_v6_view);
150} 159}
151 160
@@ -153,6 +162,7 @@ static const struct sway_view_impl view_impl = {
153 .get_prop = get_prop, 162 .get_prop = get_prop,
154 .configure = configure, 163 .configure = configure,
155 .set_activated = set_activated, 164 .set_activated = set_activated,
165 .set_fullscreen = set_fullscreen,
156 .for_each_surface = for_each_surface, 166 .for_each_surface = for_each_surface,
157 .close = _close, 167 .close = _close,
158 .destroy = destroy, 168 .destroy = destroy,
@@ -202,6 +212,10 @@ static void handle_map(struct wl_listener *listener, void *data) {
202 xdg_shell_v6_view->new_popup.notify = handle_new_popup; 212 xdg_shell_v6_view->new_popup.notify = handle_new_popup;
203 wl_signal_add(&xdg_surface->events.new_popup, 213 wl_signal_add(&xdg_surface->events.new_popup,
204 &xdg_shell_v6_view->new_popup); 214 &xdg_shell_v6_view->new_popup);
215
216 if (xdg_surface->toplevel->client_pending.fullscreen) {
217 view_set_fullscreen(view, true);
218 }
205} 219}
206 220
207static void handle_destroy(struct wl_listener *listener, void *data) { 221static void handle_destroy(struct wl_listener *listener, void *data) {
@@ -210,6 +224,23 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
210 view_destroy(&xdg_shell_v6_view->view); 224 view_destroy(&xdg_shell_v6_view->view);
211} 225}
212 226
227static void handle_request_fullscreen(struct wl_listener *listener, void *data) {
228 struct sway_xdg_shell_v6_view *xdg_shell_v6_view =
229 wl_container_of(listener, xdg_shell_v6_view, request_fullscreen);
230 struct wlr_xdg_toplevel_v6_set_fullscreen_event *e = data;
231
232 if (!sway_assert(xdg_shell_v6_view->view.wlr_xdg_surface_v6->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL,
233 "xdg_shell_v6 requested fullscreen of surface with role %i",
234 xdg_shell_v6_view->view.wlr_xdg_surface_v6->role)) {
235 return;
236 }
237 if (!xdg_shell_v6_view->view.wlr_xdg_surface_v6->mapped) {
238 return;
239 }
240
241 view_set_fullscreen(&xdg_shell_v6_view->view, e->fullscreen);
242}
243
213void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { 244void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) {
214 struct sway_server *server = wl_container_of(listener, server, 245 struct sway_server *server = wl_container_of(listener, server,
215 xdg_shell_v6_surface); 246 xdg_shell_v6_surface);
@@ -246,4 +277,8 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) {
246 277
247 xdg_shell_v6_view->destroy.notify = handle_destroy; 278 xdg_shell_v6_view->destroy.notify = handle_destroy;
248 wl_signal_add(&xdg_surface->events.destroy, &xdg_shell_v6_view->destroy); 279 wl_signal_add(&xdg_surface->events.destroy, &xdg_shell_v6_view->destroy);
280
281 xdg_shell_v6_view->request_fullscreen.notify = handle_request_fullscreen;
282 wl_signal_add(&xdg_surface->toplevel->events.request_fullscreen,
283 &xdg_shell_v6_view->request_fullscreen);
249} 284}
diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c
index 69166af0..46eaa84c 100644
--- a/sway/desktop/xwayland.c
+++ b/sway/desktop/xwayland.c
@@ -179,6 +179,14 @@ static void set_activated(struct sway_view *view, bool activated) {
179 wlr_xwayland_surface_activate(surface, activated); 179 wlr_xwayland_surface_activate(surface, activated);
180} 180}
181 181
182static void set_fullscreen(struct sway_view *view, bool fullscreen) {
183 if (xwayland_view_from_view(view) == NULL) {
184 return;
185 }
186 struct wlr_xwayland_surface *surface = view->wlr_xwayland_surface;
187 wlr_xwayland_surface_set_fullscreen(surface, fullscreen);
188}
189
182static void _close(struct sway_view *view) { 190static void _close(struct sway_view *view) {
183 if (xwayland_view_from_view(view) == NULL) { 191 if (xwayland_view_from_view(view) == NULL) {
184 return; 192 return;
@@ -193,6 +201,7 @@ static void destroy(struct sway_view *view) {
193 } 201 }
194 wl_list_remove(&xwayland_view->destroy.link); 202 wl_list_remove(&xwayland_view->destroy.link);
195 wl_list_remove(&xwayland_view->request_configure.link); 203 wl_list_remove(&xwayland_view->request_configure.link);
204 wl_list_remove(&xwayland_view->request_fullscreen.link);
196 wl_list_remove(&xwayland_view->map.link); 205 wl_list_remove(&xwayland_view->map.link);
197 wl_list_remove(&xwayland_view->unmap.link); 206 wl_list_remove(&xwayland_view->unmap.link);
198 free(xwayland_view); 207 free(xwayland_view);
@@ -202,6 +211,7 @@ static const struct sway_view_impl view_impl = {
202 .get_prop = get_prop, 211 .get_prop = get_prop,
203 .configure = configure, 212 .configure = configure,
204 .set_activated = set_activated, 213 .set_activated = set_activated,
214 .set_fullscreen = set_fullscreen,
205 .close = _close, 215 .close = _close,
206 .destroy = destroy, 216 .destroy = destroy,
207}; 217};
@@ -238,6 +248,10 @@ static void handle_map(struct wl_listener *listener, void *data) {
238 // Put it back into the tree 248 // Put it back into the tree
239 wlr_xwayland_surface_set_maximized(xsurface, true); 249 wlr_xwayland_surface_set_maximized(xsurface, true);
240 view_map(view, xsurface->surface); 250 view_map(view, xsurface->surface);
251
252 if (xsurface->fullscreen) {
253 view_set_fullscreen(view, true);
254 }
241} 255}
242 256
243static void handle_destroy(struct wl_listener *listener, void *data) { 257static void handle_destroy(struct wl_listener *listener, void *data) {
@@ -263,6 +277,14 @@ static void handle_request_configure(struct wl_listener *listener, void *data) {
263 ev->width, ev->height); 277 ev->width, ev->height);
264} 278}
265 279
280static void handle_request_fullscreen(struct wl_listener *listener, void *data) {
281 struct sway_xwayland_view *xwayland_view =
282 wl_container_of(listener, xwayland_view, request_fullscreen);
283 struct sway_view *view = &xwayland_view->view;
284 struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
285 view_set_fullscreen(view, xsurface->fullscreen);
286}
287
266void handle_xwayland_surface(struct wl_listener *listener, void *data) { 288void handle_xwayland_surface(struct wl_listener *listener, void *data) {
267 struct sway_server *server = wl_container_of(listener, server, 289 struct sway_server *server = wl_container_of(listener, server,
268 xwayland_surface); 290 xwayland_surface);
@@ -298,6 +320,10 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) {
298 &xwayland_view->request_configure); 320 &xwayland_view->request_configure);
299 xwayland_view->request_configure.notify = handle_request_configure; 321 xwayland_view->request_configure.notify = handle_request_configure;
300 322
323 wl_signal_add(&xsurface->events.request_fullscreen,
324 &xwayland_view->request_fullscreen);
325 xwayland_view->request_fullscreen.notify = handle_request_fullscreen;
326
301 wl_signal_add(&xsurface->events.unmap, &xwayland_view->unmap); 327 wl_signal_add(&xsurface->events.unmap, &xwayland_view->unmap);
302 xwayland_view->unmap.notify = handle_unmap; 328 xwayland_view->unmap.notify = handle_unmap;
303 329
diff --git a/sway/input/cursor.c b/sway/input/cursor.c
index 15a61cbf..a19f0752 100644
--- a/sway/input/cursor.c
+++ b/sway/input/cursor.c
@@ -12,6 +12,7 @@
12#include "sway/layers.h" 12#include "sway/layers.h"
13#include "sway/output.h" 13#include "sway/output.h"
14#include "sway/tree/view.h" 14#include "sway/tree/view.h"
15#include "sway/tree/workspace.h"
15#include "wlr-layer-shell-unstable-v1-protocol.h" 16#include "wlr-layer-shell-unstable-v1-protocol.h"
16 17
17static struct wlr_surface *layer_surface_at(struct sway_output *output, 18static struct wlr_surface *layer_surface_at(struct sway_output *output,
@@ -83,6 +84,16 @@ static struct sway_container *container_at_cursor(struct sway_cursor *cursor,
83 ox, oy, sx, sy))) { 84 ox, oy, sx, sy))) {
84 return ws; 85 return ws;
85 } 86 }
87 if (ws->sway_workspace->fullscreen) {
88 struct wlr_surface *wlr_surface = ws->sway_workspace->fullscreen->surface;
89 if (wlr_surface_point_accepts_input(wlr_surface, ox, oy)) {
90 *sx = ox;
91 *sy = oy;
92 *surface = wlr_surface;
93 return ws->sway_workspace->fullscreen->swayc;
94 }
95 return NULL;
96 }
86 if ((*surface = layer_surface_at(output, 97 if ((*surface = layer_surface_at(output,
87 &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], 98 &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP],
88 ox, oy, sx, sy))) { 99 ox, oy, sx, sy))) {
diff --git a/sway/input/seat.c b/sway/input/seat.c
index 09927a1a..8bba7d8f 100644
--- a/sway/input/seat.c
+++ b/sway/input/seat.c
@@ -18,6 +18,7 @@
18#include "sway/output.h" 18#include "sway/output.h"
19#include "sway/tree/container.h" 19#include "sway/tree/container.h"
20#include "sway/tree/view.h" 20#include "sway/tree/view.h"
21#include "sway/tree/workspace.h"
21#include "log.h" 22#include "log.h"
22 23
23static void seat_device_destroy(struct sway_seat_device *seat_device) { 24static void seat_device_destroy(struct sway_seat_device *seat_device) {
@@ -448,6 +449,21 @@ void seat_set_focus_warp(struct sway_seat *seat,
448 return; 449 return;
449 } 450 }
450 451
452 struct sway_container *last_workspace = last_focus;
453 if (last_workspace && last_workspace->type != C_WORKSPACE) {
454 last_workspace = container_parent(last_workspace, C_WORKSPACE);
455 }
456 struct sway_container *new_workspace = container;
457 if (new_workspace && new_workspace->type != C_WORKSPACE) {
458 new_workspace = container_parent(new_workspace, C_WORKSPACE);
459 }
460
461 if (last_workspace && last_workspace == new_workspace
462 && last_workspace->sway_workspace->fullscreen
463 && !container->sway_view->is_fullscreen) {
464 return;
465 }
466
451 struct sway_container *last_output = last_focus; 467 struct sway_container *last_output = last_focus;
452 if (last_output && last_output->type != C_OUTPUT) { 468 if (last_output && last_output->type != C_OUTPUT) {
453 last_output = container_parent(last_output, C_OUTPUT); 469 last_output = container_parent(last_output, C_OUTPUT);
diff --git a/sway/meson.build b/sway/meson.build
index 4ceb07b4..67dbe3dd 100644
--- a/sway/meson.build
+++ b/sway/meson.build
@@ -34,6 +34,7 @@ sway_sources = files(
34 'commands/exec_always.c', 34 'commands/exec_always.c',
35 'commands/focus.c', 35 'commands/focus.c',
36 'commands/focus_follows_mouse.c', 36 'commands/focus_follows_mouse.c',
37 'commands/fullscreen.c',
37 'commands/kill.c', 38 'commands/kill.c',
38 'commands/opacity.c', 39 'commands/opacity.c',
39 'commands/include.c', 40 'commands/include.c',
diff --git a/sway/tree/container.c b/sway/tree/container.c
index c0067493..f14e9b9a 100644
--- a/sway/tree/container.c
+++ b/sway/tree/container.c
@@ -197,6 +197,7 @@ static struct sway_container *container_workspace_destroy(
197 } 197 }
198 } 198 }
199 199
200 free(workspace->sway_workspace);
200 _container_destroy(workspace); 201 _container_destroy(workspace);
201 202
202 output_damage_whole(output->sway_output); 203 output_damage_whole(output->sway_output);
diff --git a/sway/tree/layout.c b/sway/tree/layout.c
index 0b637822..7ffc2484 100644
--- a/sway/tree/layout.c
+++ b/sway/tree/layout.c
@@ -82,6 +82,37 @@ static int index_child(const struct sway_container *child) {
82 return i; 82 return i;
83} 83}
84 84
85static void container_handle_fullscreen_reparent(struct sway_container *viewcon,
86 struct sway_container *old_parent) {
87 if (viewcon->type != C_VIEW || !viewcon->sway_view->is_fullscreen) {
88 return;
89 }
90 struct sway_view *view = viewcon->sway_view;
91 struct sway_container *old_workspace = old_parent;
92 if (old_workspace && old_workspace->type != C_WORKSPACE) {
93 old_workspace = container_parent(old_workspace, C_WORKSPACE);
94 }
95 struct sway_container *new_workspace = container_parent(view->swayc,
96 C_WORKSPACE);
97 if (old_workspace == new_workspace) {
98 return;
99 }
100 // Unmark the old workspace as fullscreen
101 if (old_workspace) {
102 old_workspace->sway_workspace->fullscreen = NULL;
103 }
104
105 // Mark the new workspace as fullscreen
106 if (new_workspace->sway_workspace->fullscreen) {
107 view_set_fullscreen(new_workspace->sway_workspace->fullscreen, false);
108 }
109 new_workspace->sway_workspace->fullscreen = view;
110 // Resize view to new output dimensions
111 struct sway_output *output = new_workspace->parent->sway_output;
112 view_configure(view, 0, 0,
113 output->wlr_output->width, output->wlr_output->height);
114}
115
85void container_insert_child(struct sway_container *parent, 116void container_insert_child(struct sway_container *parent,
86 struct sway_container *child, int i) { 117 struct sway_container *child, int i) {
87 struct sway_container *old_parent = child->parent; 118 struct sway_container *old_parent = child->parent;
@@ -91,6 +122,7 @@ void container_insert_child(struct sway_container *parent,
91 wlr_log(L_DEBUG, "Inserting id:%zd at index %d", child->id, i); 122 wlr_log(L_DEBUG, "Inserting id:%zd at index %d", child->id, i);
92 list_insert(parent->children, i, child); 123 list_insert(parent->children, i, child);
93 child->parent = parent; 124 child->parent = parent;
125 container_handle_fullscreen_reparent(child, old_parent);
94 wl_signal_emit(&child->events.reparent, old_parent); 126 wl_signal_emit(&child->events.reparent, old_parent);
95} 127}
96 128
@@ -106,6 +138,7 @@ struct sway_container *container_add_sibling(struct sway_container *fixed,
106 int i = index_child(fixed); 138 int i = index_child(fixed);
107 list_insert(parent->children, i + 1, active); 139 list_insert(parent->children, i + 1, active);
108 active->parent = parent; 140 active->parent = parent;
141 container_handle_fullscreen_reparent(active, old_parent);
109 wl_signal_emit(&active->events.reparent, old_parent); 142 wl_signal_emit(&active->events.reparent, old_parent);
110 return active->parent; 143 return active->parent;
111} 144}
@@ -115,11 +148,18 @@ void container_add_child(struct sway_container *parent,
115 wlr_log(L_DEBUG, "Adding %p (%d, %fx%f) to %p (%d, %fx%f)", 148 wlr_log(L_DEBUG, "Adding %p (%d, %fx%f) to %p (%d, %fx%f)",
116 child, child->type, child->width, child->height, 149 child, child->type, child->width, child->height,
117 parent, parent->type, parent->width, parent->height); 150 parent, parent->type, parent->width, parent->height);
151 struct sway_container *old_parent = child->parent;
118 list_add(parent->children, child); 152 list_add(parent->children, child);
153 container_handle_fullscreen_reparent(child, old_parent);
119 child->parent = parent; 154 child->parent = parent;
120} 155}
121 156
122struct sway_container *container_remove_child(struct sway_container *child) { 157struct sway_container *container_remove_child(struct sway_container *child) {
158 if (child->type == C_VIEW && child->sway_view->is_fullscreen) {
159 struct sway_container *workspace = container_parent(child, C_WORKSPACE);
160 workspace->sway_workspace->fullscreen = NULL;
161 }
162
123 struct sway_container *parent = child->parent; 163 struct sway_container *parent = child->parent;
124 for (int i = 0; i < parent->children->length; ++i) { 164 for (int i = 0; i < parent->children->length; ++i) {
125 if (parent->children->items[i] == child) { 165 if (parent->children->items[i] == child) {
@@ -164,6 +204,26 @@ void container_move_to(struct sway_container *container,
164 arrange_windows(old_parent, -1, -1); 204 arrange_windows(old_parent, -1, -1);
165 } 205 }
166 arrange_windows(new_parent, -1, -1); 206 arrange_windows(new_parent, -1, -1);
207 // If view was moved to a fullscreen workspace, refocus the fullscreen view
208 struct sway_container *new_workspace = container;
209 if (new_workspace->type != C_WORKSPACE) {
210 new_workspace = container_parent(new_workspace, C_WORKSPACE);
211 }
212 if (new_workspace->sway_workspace->fullscreen) {
213 struct sway_seat *seat;
214 struct sway_container *focus, *focus_ws;
215 wl_list_for_each(seat, &input_manager->seats, link) {
216 focus = seat_get_focus(seat);
217 focus_ws = focus;
218 if (focus_ws->type != C_WORKSPACE) {
219 focus_ws = container_parent(focus_ws, C_WORKSPACE);
220 }
221 seat_set_focus(seat, new_workspace->sway_workspace->fullscreen->swayc);
222 if (focus_ws != new_workspace) {
223 seat_set_focus(seat, focus);
224 }
225 }
226 }
167} 227}
168 228
169static bool sway_dir_to_wlr(enum movement_direction dir, 229static bool sway_dir_to_wlr(enum movement_direction dir,
@@ -268,6 +328,11 @@ void container_move(struct sway_container *container,
268 struct sway_container *current = container; 328 struct sway_container *current = container;
269 struct sway_container *parent = current->parent; 329 struct sway_container *parent = current->parent;
270 330
331 // If moving a fullscreen view, only consider outputs
332 if (container->type == C_VIEW && container->sway_view->is_fullscreen) {
333 current = container_parent(container, C_OUTPUT);
334 }
335
271 if (parent != container_flatten(parent)) { 336 if (parent != container_flatten(parent)) {
272 // Special case: we were the last one in this container, so flatten it 337 // Special case: we were the last one in this container, so flatten it
273 // and leave 338 // and leave
@@ -568,6 +633,11 @@ void arrange_windows(struct sway_container *container,
568 container->y = y = area->y; 633 container->y = y = area->y;
569 wlr_log(L_DEBUG, "Arranging workspace '%s' at %f, %f", 634 wlr_log(L_DEBUG, "Arranging workspace '%s' at %f, %f",
570 container->name, container->x, container->y); 635 container->name, container->x, container->y);
636 if (container->sway_workspace->fullscreen) {
637 view_configure(container->sway_workspace->fullscreen, 0, 0,
638 output->width, output->height);
639 return;
640 }
571 } 641 }
572 // children are properly handled below 642 // children are properly handled below
573 break; 643 break;
@@ -816,34 +886,26 @@ static struct sway_container *sway_output_from_wlr(struct wlr_output *output) {
816struct sway_container *container_get_in_direction( 886struct sway_container *container_get_in_direction(
817 struct sway_container *container, struct sway_seat *seat, 887 struct sway_container *container, struct sway_seat *seat,
818 enum movement_direction dir) { 888 enum movement_direction dir) {
819 if (dir == MOVE_CHILD) {
820 return seat_get_focus_inactive(seat, container);
821 }
822
823 struct sway_container *parent = container->parent; 889 struct sway_container *parent = container->parent;
824 if (dir == MOVE_PARENT) { 890
825 if (parent->type == C_OUTPUT) { 891 if (container->type == C_VIEW && container->sway_view->is_fullscreen) {
892 if (dir == MOVE_PARENT || dir == MOVE_CHILD) {
826 return NULL; 893 return NULL;
827 } else {
828 return parent;
829 } 894 }
830 }
831
832 // TODO WLR fullscreen
833 /*
834 if (container->type == C_VIEW && swayc_is_fullscreen(container)) {
835 wlr_log(L_DEBUG, "Moving from fullscreen view, skipping to output");
836 container = container_parent(container, C_OUTPUT); 895 container = container_parent(container, C_OUTPUT);
837 get_layout_center_position(container, &abs_pos); 896 parent = container->parent;
838 struct sway_container *output = 897 } else {
839 swayc_adjacent_output(container, dir, &abs_pos, true); 898 if (dir == MOVE_CHILD) {
840 return get_swayc_in_output_direction(output, dir); 899 return seat_get_focus_inactive(seat, container);
841 } 900 }
842 if (container->type == C_WORKSPACE && container->fullscreen) { 901 if (dir == MOVE_PARENT) {
843 sway_log(L_DEBUG, "Moving to fullscreen view"); 902 if (parent->type == C_OUTPUT) {
844 return container->fullscreen; 903 return NULL;
904 } else {
905 return parent;
906 }
907 }
845 } 908 }
846 */
847 909
848 struct sway_container *wrap_candidate = NULL; 910 struct sway_container *wrap_candidate = NULL;
849 while (true) { 911 while (true) {
@@ -874,6 +936,14 @@ struct sway_container *container_get_in_direction(
874 if (next == NULL) { 936 if (next == NULL) {
875 return NULL; 937 return NULL;
876 } 938 }
939 struct sway_container *next_workspace = next;
940 if (next_workspace->type != C_WORKSPACE) {
941 next_workspace = container_parent(next_workspace, C_WORKSPACE);
942 }
943 sway_assert(next_workspace, "Next container has no workspace");
944 if (next_workspace->sway_workspace->fullscreen) {
945 return next_workspace->sway_workspace->fullscreen->swayc;
946 }
877 if (next->children && next->children->length) { 947 if (next->children && next->children->length) {
878 // TODO consider floating children as well 948 // TODO consider floating children as well
879 return seat_get_focus_inactive_view(seat, next); 949 return seat_get_focus_inactive_view(seat, next);
diff --git a/sway/tree/view.c b/sway/tree/view.c
index 99b44720..b92c7099 100644
--- a/sway/tree/view.c
+++ b/sway/tree/view.c
@@ -2,10 +2,12 @@
2#include <wayland-server.h> 2#include <wayland-server.h>
3#include <wlr/types/wlr_output_layout.h> 3#include <wlr/types/wlr_output_layout.h>
4#include "log.h" 4#include "log.h"
5#include "sway/ipc-server.h"
5#include "sway/output.h" 6#include "sway/output.h"
6#include "sway/tree/container.h" 7#include "sway/tree/container.h"
7#include "sway/tree/layout.h" 8#include "sway/tree/layout.h"
8#include "sway/tree/view.h" 9#include "sway/tree/view.h"
10#include "sway/tree/workspace.h"
9 11
10void view_init(struct sway_view *view, enum sway_view_type type, 12void view_init(struct sway_view *view, enum sway_view_type type,
11 const struct sway_view_impl *impl) { 13 const struct sway_view_impl *impl) {
@@ -73,6 +75,50 @@ void view_set_activated(struct sway_view *view, bool activated) {
73 } 75 }
74} 76}
75 77
78void view_set_fullscreen(struct sway_view *view, bool fullscreen) {
79 if (view->is_fullscreen == fullscreen) {
80 return;
81 }
82
83 struct sway_container *workspace = container_parent(view->swayc, C_WORKSPACE);
84 struct sway_container *container = container_parent(workspace, C_OUTPUT);
85 struct sway_output *output = container->sway_output;
86
87 if (view->impl->set_fullscreen) {
88 view->impl->set_fullscreen(view, fullscreen);
89 }
90
91 view->is_fullscreen = fullscreen;
92
93 if (fullscreen) {
94 if (workspace->sway_workspace->fullscreen) {
95 view_set_fullscreen(workspace->sway_workspace->fullscreen, false);
96 }
97 workspace->sway_workspace->fullscreen = view;
98
99 struct sway_seat *seat;
100 struct sway_container *focus, *focus_ws;
101 wl_list_for_each(seat, &input_manager->seats, link) {
102 focus = seat_get_focus(seat);
103 focus_ws = focus;
104 if (focus_ws->type != C_WORKSPACE) {
105 focus_ws = container_parent(focus_ws, C_WORKSPACE);
106 }
107 seat_set_focus(seat, view->swayc);
108 if (focus_ws != workspace) {
109 seat_set_focus(seat, focus);
110 }
111 }
112 } else {
113 workspace->sway_workspace->fullscreen = NULL;
114 }
115
116 arrange_windows(workspace, -1, -1);
117 output_damage_whole(output);
118
119 ipc_event_window(view->swayc, "fullscreen_mode");
120}
121
76void view_close(struct sway_view *view) { 122void view_close(struct sway_view *view) {
77 if (view->impl->close) { 123 if (view->impl->close) {
78 view->impl->close(view); 124 view->impl->close(view);
@@ -197,6 +243,11 @@ void view_unmap(struct sway_view *view) {
197 243
198 wl_signal_emit(&view->events.unmap, view); 244 wl_signal_emit(&view->events.unmap, view);
199 245
246 if (view->is_fullscreen) {
247 struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
248 ws->sway_workspace->fullscreen = NULL;
249 }
250
200 view_damage(view, true); 251 view_damage(view, true);
201 252
202 wl_list_remove(&view->surface_new_subsurface.link); 253 wl_list_remove(&view->surface_new_subsurface.link);
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c
index 316f01e4..7f3c1903 100644
--- a/sway/tree/workspace.c
+++ b/sway/tree/workspace.c
@@ -59,6 +59,13 @@ struct sway_container *workspace_create(struct sway_container *output,
59 workspace->layout = container_get_default_layout(output); 59 workspace->layout = container_get_default_layout(output);
60 workspace->workspace_layout = workspace->layout; 60 workspace->workspace_layout = workspace->layout;
61 61
62 struct sway_workspace *swayws = calloc(1, sizeof(struct sway_workspace));
63 if (!swayws) {
64 return NULL;
65 }
66 swayws->swayc = workspace;
67 workspace->sway_workspace = swayws;
68
62 container_add_child(output, workspace); 69 container_add_child(output, workspace);
63 container_sort_workspaces(output); 70 container_sort_workspaces(output);
64 container_create_notify(workspace); 71 container_create_notify(workspace);