diff options
Diffstat (limited to 'sway')
-rw-r--r-- | sway/commands.c | 1 | ||||
-rw-r--r-- | sway/commands/fullscreen.c | 37 | ||||
-rw-r--r-- | sway/desktop/output.c | 38 | ||||
-rw-r--r-- | sway/desktop/wl_shell.c | 35 | ||||
-rw-r--r-- | sway/desktop/xdg_shell_v6.c | 35 | ||||
-rw-r--r-- | sway/desktop/xwayland.c | 26 | ||||
-rw-r--r-- | sway/input/cursor.c | 11 | ||||
-rw-r--r-- | sway/input/seat.c | 16 | ||||
-rw-r--r-- | sway/meson.build | 1 | ||||
-rw-r--r-- | sway/tree/container.c | 1 | ||||
-rw-r--r-- | sway/tree/layout.c | 116 | ||||
-rw-r--r-- | sway/tree/view.c | 51 | ||||
-rw-r--r-- | sway/tree/workspace.c | 7 |
13 files changed, 342 insertions, 33 deletions
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 | |||
9 | struct 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 | ||
26 | struct sway_container *output_by_name(const char *name) { | 27 | struct 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 | ||
229 | static void render_container(struct sway_output *output, | 230 | static 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 | ||
234 | static struct sway_container *output_get_active_workspace( | 239 | static 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 | ||
288 | renderer_end: | 300 | renderer_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 | ||
69 | static void set_fullscreen(struct sway_view *view, bool fullscreen) { | ||
70 | // TODO | ||
71 | } | ||
72 | |||
67 | static const struct sway_view_impl view_impl = { | 73 | static 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 | ||
74 | static void handle_commit(struct wl_listener *listener, void *data) { | 81 | static 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 | ||
98 | static 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 | |||
104 | static 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 | |||
91 | void handle_wl_shell_surface(struct wl_listener *listener, void *data) { | 115 | void 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 | ||
121 | static 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 | |||
121 | static void for_each_surface(struct sway_view *view, | 129 | static 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 | ||
207 | static void handle_destroy(struct wl_listener *listener, void *data) { | 221 | static 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 | ||
227 | static 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 | |||
213 | void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { | 244 | void 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 | ||
182 | static 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 | |||
182 | static void _close(struct sway_view *view) { | 190 | static 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 | ||
243 | static void handle_destroy(struct wl_listener *listener, void *data) { | 257 | static 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 | ||
280 | static 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 | |||
266 | void handle_xwayland_surface(struct wl_listener *listener, void *data) { | 288 | void 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 | ||
17 | static struct wlr_surface *layer_surface_at(struct sway_output *output, | 18 | static 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 | ||
23 | static void seat_device_destroy(struct sway_seat_device *seat_device) { | 24 | static 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 | ||
85 | static 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 | |||
85 | void container_insert_child(struct sway_container *parent, | 116 | void 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 | ||
122 | struct sway_container *container_remove_child(struct sway_container *child) { | 157 | struct 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 | ||
169 | static bool sway_dir_to_wlr(enum movement_direction dir, | 229 | static 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) { | |||
816 | struct sway_container *container_get_in_direction( | 886 | struct 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 | ||
10 | void view_init(struct sway_view *view, enum sway_view_type type, | 12 | void 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 | ||
78 | void 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 | |||
76 | void view_close(struct sway_view *view) { | 122 | void 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); |