blob: dcab9bf7d3ee0bad683e4fbac02b117c56ae1a49 [file] [log] [blame]
Skyler Grey5d6fe4d2022-06-16 20:56:02 +01001From e8a5fe93ef657399fa98bd69be71dbfbc14aa6d2 Mon Sep 17 00:00:00 2001
2From: Ford Smith <ford.smith@case.edu> and Skyler Grey
3<skyler3665@gmail.com>
4Date: Sat, 2 Apr 2022 20:21:47 -0400
5Subject: [PATCH] Add maximize support to sway & fix for latest version
6
7---
8 include/sway/commands.h | 1 +
9 include/sway/tree/container.h | 4 +
10 include/sway/tree/view.h | 1 +
11 sway/commands.c | 2 +
12 sway/commands/maximize.c | 59 ++++++++++
13 sway/desktop/xdg_shell.c | 8 ++
14 sway/meson.build | 1 +
15 sway/tree/container.c | 201 ++++++++++++++++++++++++++++++++++
16 8 files changed, 277 insertions(+)
17 create mode 100644 sway/commands/maximize.c
18
19diff --git a/include/sway/commands.h b/include/sway/commands.h
20index 2746ef28f1..7948be6823 100644
21--- a/include/sway/commands.h
22+++ b/include/sway/commands.h
23@@ -150,6 +150,7 @@ sway_cmd cmd_kill;
24 sway_cmd cmd_layout;
25 sway_cmd cmd_log_colors;
26 sway_cmd cmd_mark;
27+sway_cmd cmd_maximize;
28 sway_cmd cmd_max_render_time;
29 sway_cmd cmd_mode;
30 sway_cmd cmd_mouse_warping;
31diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h
32index 751612e2c3..0a3404157b 100644
33--- a/include/sway/tree/container.h
34+++ b/include/sway/tree/container.h
35@@ -257,6 +257,10 @@ void container_end_mouse_operation(struct sway_container *container);
36 void container_set_fullscreen(struct sway_container *con,
37 enum sway_fullscreen_mode mode);
38
39+void container_set_maximize(struct sway_container *con,
40+ enum sway_fullscreen_mode mode);
41+
42+
43 /**
44 * Convenience function.
45 */
46diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h
47index 95708a049c..fd186c7386 100644
48--- a/include/sway/tree/view.h
49+++ b/include/sway/tree/view.h
50@@ -43,6 +43,7 @@ struct sway_view_impl {
51 void (*set_activated)(struct sway_view *view, bool activated);
52 void (*set_tiled)(struct sway_view *view, bool tiled);
53 void (*set_fullscreen)(struct sway_view *view, bool fullscreen);
54+ void (*set_maximized)(struct sway_view *view, bool maximized);
55 void (*set_resizing)(struct sway_view *view, bool resizing);
56 bool (*wants_floating)(struct sway_view *view);
57 void (*for_each_surface)(struct sway_view *view,
58diff --git a/sway/commands.c b/sway/commands.c
59index 5a1fd32ef9..b33788db17 100644
60--- a/sway/commands.c
61+++ b/sway/commands.c
62@@ -74,6 +74,7 @@ static const struct cmd_handler handlers[] = {
63 { "gaps", cmd_gaps },
64 { "hide_edge_borders", cmd_hide_edge_borders },
65 { "input", cmd_input },
66+ { "maximize", cmd_maximize },
67 { "mode", cmd_mode },
68 { "mouse_warping", cmd_mouse_warping },
69 { "new_float", cmd_new_float },
70@@ -119,6 +120,7 @@ static const struct cmd_handler command_handlers[] = {
71 { "kill", cmd_kill },
72 { "layout", cmd_layout },
73 { "mark", cmd_mark },
74+ { "maximize", cmd_maximize },
75 { "max_render_time", cmd_max_render_time },
76 { "move", cmd_move },
77 { "nop", cmd_nop },
78diff --git a/sway/commands/maximize.c b/sway/commands/maximize.c
79new file mode 100644
80index 0000000000..5fa29f79c1
81--- /dev/null
82+++ b/sway/commands/maximize.c
83@@ -0,0 +1,59 @@
84+#include <strings.h>
85+#include "log.h"
86+#include "sway/commands.h"
87+#include "sway/config.h"
88+#include "sway/tree/arrange.h"
89+#include "sway/tree/container.h"
90+#include "sway/tree/view.h"
91+#include "sway/tree/workspace.h"
92+#include "util.h"
93+
94+// maximize [enable|disable|toggle] [global]
95+struct cmd_results *cmd_maximize(int argc, char **argv) {
96+ struct cmd_results *error = NULL;
97+ if ((error = checkarg(argc, "maximize", EXPECTED_AT_MOST, 2))) {
98+ return error;
99+ }
100+ if (!root->outputs->length) {
101+ return cmd_results_new(CMD_FAILURE,
102+ "Can't run this command while there's no outputs connected.");
103+ }
104+ struct sway_container *container = config->handler_context.container;
105+
106+ if (!container) {
107+ // If the focus is not a container, do nothing successfully
108+ return cmd_results_new(CMD_SUCCESS, NULL);
109+ } else if (!container->pending.workspace) {
110+ // If in the scratchpad, operate on the highest container
111+ while (container->pending.parent) {
112+ container = container->pending.parent;
113+ }
114+ }
115+
116+ bool is_fullscreen = container->pending.fullscreen_mode != FULLSCREEN_NONE;
117+ bool global = false;
118+ bool enable = !is_fullscreen;
119+
120+ if (argc >= 1) {
121+ if (strcasecmp(argv[0], "global") == 0) {
122+ global = true;
123+ } else {
124+ enable = parse_boolean(argv[0], is_fullscreen);
125+ }
126+ }
127+
128+ if (argc >= 2) {
129+ global = strcasecmp(argv[1], "global") == 0;
130+ }
131+
132+ enum sway_fullscreen_mode mode = FULLSCREEN_NONE;
133+ if (enable) {
134+ mode = global ? FULLSCREEN_GLOBAL : FULLSCREEN_WORKSPACE;
135+ }
136+
137+ container_set_maximize(container, mode);
138+ arrange_root();
139+
140+ return cmd_results_new(CMD_SUCCESS, NULL);
141+}
142+
143diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c
144index 51168f4c61..f54db21930 100644
145--- a/sway/desktop/xdg_shell.c
146+++ b/sway/desktop/xdg_shell.c
147@@ -178,6 +178,13 @@ static void set_fullscreen(struct sway_view *view, bool fullscreen) {
148 wlr_xdg_toplevel_set_fullscreen(view->wlr_xdg_toplevel, fullscreen);
149 }
150
151+static void set_maximized(struct sway_view *view, bool maximized) {
152+ if (xdg_shell_view_from_view(view) == NULL) {
153+ return;
154+ }
155+ wlr_xdg_toplevel_set_maximized(view->wlr_xdg_surface, maximized);
156+}
157+
158 static void set_resizing(struct sway_view *view, bool resizing) {
159 if (xdg_shell_view_from_view(view) == NULL) {
160 return;
161@@ -257,6 +264,7 @@ static const struct sway_view_impl view_impl = {
162 .set_activated = set_activated,
163 .set_tiled = set_tiled,
164 .set_fullscreen = set_fullscreen,
165+ .set_maximized = set_maximized,
166 .set_resizing = set_resizing,
167 .wants_floating = wants_floating,
168 .for_each_surface = for_each_surface,
169diff --git a/sway/meson.build b/sway/meson.build
170index 5f34ce6b01..05f302f49e 100644
171--- a/sway/meson.build
172+++ b/sway/meson.build
173@@ -69,6 +69,7 @@ sway_sources = files(
174 'commands/inhibit_idle.c',
175 'commands/kill.c',
176 'commands/mark.c',
177+ 'commands/maximize.c',
178 'commands/max_render_time.c',
179 'commands/opacity.c',
180 'commands/include.c',
181diff --git a/sway/tree/container.c b/sway/tree/container.c
182index 09766ce5cc..57f65aadb6 100644
183--- a/sway/tree/container.c
184+++ b/sway/tree/container.c
185@@ -1266,6 +1266,207 @@ void container_fullscreen_disable(struct sway_container *con) {
186 }
187 }
188
189+static void set_maximized(struct sway_container *con, bool enable) {
190+ if (!con->view) {
191+ return;
192+ }
193+ if (con->view->impl->set_maximized) {
194+ con->view->impl->set_maximized(con->view, enable);
195+ if (con->view->foreign_toplevel) {
196+ wlr_foreign_toplevel_handle_v1_set_fullscreen(
197+ con->view->foreign_toplevel, enable);
198+ }
199+ }
200+
201+ if (!server.linux_dmabuf_v1 || !con->view->surface) {
202+ return;
203+ }
204+ if (!enable) {
205+ wlr_linux_dmabuf_v1_set_surface_feedback(server.linux_dmabuf_v1,
206+ con->view->surface, NULL);
207+ return;
208+ }
209+
210+ if (!con->pending.workspace || !con->pending.workspace->output) {
211+ return;
212+ }
213+
214+ struct sway_output *output = con->pending.workspace->output;
215+ struct wlr_output *wlr_output = output->wlr_output;
216+
217+ // TODO: add wlroots helpers for all of this stuff
218+
219+ const struct wlr_drm_format_set *renderer_formats =
220+ wlr_renderer_get_dmabuf_texture_formats(server.renderer);
221+ assert(renderer_formats);
222+
223+ int renderer_drm_fd = wlr_renderer_get_drm_fd(server.renderer);
224+ int backend_drm_fd = wlr_backend_get_drm_fd(wlr_output->backend);
225+ if (renderer_drm_fd < 0 || backend_drm_fd < 0) {
226+ return;
227+ }
228+
229+ dev_t render_dev, scanout_dev;
230+ if (!devid_from_fd(renderer_drm_fd, &render_dev) ||
231+ !devid_from_fd(backend_drm_fd, &scanout_dev)) {
232+ return;
233+ }
234+
235+ const struct wlr_drm_format_set *output_formats =
236+ wlr_output_get_primary_formats(output->wlr_output,
237+ WLR_BUFFER_CAP_DMABUF);
238+ if (!output_formats) {
239+ return;
240+ }
241+
242+ struct wlr_drm_format_set scanout_formats = {0};
243+ if (!wlr_drm_format_set_intersect(&scanout_formats,
244+ output_formats, renderer_formats)) {
245+ return;
246+ }
247+
248+ struct wlr_linux_dmabuf_feedback_v1_tranche tranches[] = {
249+ {
250+ .target_device = scanout_dev,
251+ .flags = ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SCANOUT,
252+ .formats = &scanout_formats,
253+ },
254+ {
255+ .target_device = render_dev,
256+ .formats = renderer_formats,
257+ },
258+ };
259+
260+ const struct wlr_linux_dmabuf_feedback_v1 feedback = {
261+ .main_device = render_dev,
262+ .tranches = tranches,
263+ .tranches_len = sizeof(tranches) / sizeof(tranches[0]),
264+ };
265+ wlr_linux_dmabuf_v1_set_surface_feedback(server.linux_dmabuf_v1,
266+ con->view->surface, &feedback);
267+
268+ wlr_drm_format_set_finish(&scanout_formats);
269+}
270+
271+static void container_maximize_workspace(struct sway_container *con) {
272+ if (!sway_assert(con->pending.fullscreen_mode == FULLSCREEN_NONE,
273+ "Expected a non-fullscreen container")) {
274+ return;
275+ }
276+ set_maximized(con, true);
277+ con->pending.fullscreen_mode = FULLSCREEN_WORKSPACE;
278+
279+ con->saved_x = con->pending.x;
280+ con->saved_y = con->pending.y;
281+ con->saved_width = con->pending.width;
282+ con->saved_height = con->pending.height;
283+
284+ if (con->pending.workspace) {
285+ con->pending.workspace->fullscreen = con;
286+ struct sway_seat *seat;
287+ struct sway_workspace *focus_ws;
288+ wl_list_for_each(seat, &server.input->seats, link) {
289+ focus_ws = seat_get_focused_workspace(seat);
290+ if (focus_ws == con->pending.workspace) {
291+ seat_set_focus_container(seat, con);
292+ } else {
293+ struct sway_node *focus =
294+ seat_get_focus_inactive(seat, &root->node);
295+ seat_set_raw_focus(seat, &con->node);
296+ seat_set_raw_focus(seat, focus);
297+ }
298+ }
299+ }
300+
301+ container_end_mouse_operation(con);
302+ ipc_event_window(con, "fullscreen_mode");
303+}
304+
305+void container_maximize_disable(struct sway_container *con) {
306+ if (!sway_assert(con->pending.fullscreen_mode != FULLSCREEN_NONE,
307+ "Expected a fullscreen container")) {
308+ return;
309+ }
310+ set_maximized(con, false);
311+
312+ if (container_is_floating(con)) {
313+ con->pending.x = con->saved_x;
314+ con->pending.y = con->saved_y;
315+ con->pending.width = con->saved_width;
316+ con->pending.height = con->saved_height;
317+ }
318+
319+ if (con->pending.fullscreen_mode == FULLSCREEN_WORKSPACE) {
320+ if (con->pending.workspace) {
321+ con->pending.workspace->fullscreen = NULL;
322+ if (container_is_floating(con)) {
323+ struct sway_output *output =
324+ container_floating_find_output(con);
325+ if (con->pending.workspace->output != output) {
326+ container_floating_move_to_center(con);
327+ }
328+ }
329+ }
330+ } else {
331+ root->fullscreen_global = NULL;
332+ }
333+
334+ // If the container was mapped as fullscreen and set as floating by
335+ // criteria, it needs to be reinitialized as floating to get the proper
336+ // size and location
337+ if (container_is_floating(con) && (con->pending.width == 0 || con->pending.height == 0)) {
338+ container_floating_resize_and_center(con);
339+ }
340+
341+ con->pending.fullscreen_mode = FULLSCREEN_NONE;
342+ container_end_mouse_operation(con);
343+ ipc_event_window(con, "fullscreen_mode");
344+
345+ if (con->scratchpad) {
346+ struct sway_seat *seat;
347+ wl_list_for_each(seat, &server.input->seats, link) {
348+ struct sway_container *focus = seat_get_focused_container(seat);
349+ if (focus == con || container_has_ancestor(focus, con)) {
350+ seat_set_focus(seat,
351+ seat_get_focus_inactive(seat, &root->node));
352+ }
353+ }
354+ }
355+}
356+
357+void container_set_maximize(struct sway_container *con,
358+ enum sway_fullscreen_mode mode) {
359+ if (con->pending.fullscreen_mode == mode) {
360+ return;
361+ }
362+
363+ switch (mode) {
364+ case FULLSCREEN_NONE:
365+ container_maximize_disable(con);
366+ break;
367+ case FULLSCREEN_WORKSPACE:
368+ if (root->fullscreen_global) {
369+ container_maximize_disable(root->fullscreen_global);
370+ }
371+ if (con->pending.workspace && con->pending.workspace->fullscreen) {
372+ container_maximize_disable(con->pending.workspace->fullscreen);
373+ }
374+ container_maximize_workspace(con);
375+ break;
376+ case FULLSCREEN_GLOBAL:
377+ //TODO:
378+ assert(false);
379+ // if (root->fullscreen_global) {
380+ // container_maximize_disable(root->fullscreen_global);
381+ // }
382+ // if (con->pending.fullscreen_mode == FULLSCREEN_WORKSPACE) {
383+ // container_maximize_disable(con);
384+ // }
385+ // container_fullscreen_global(con);
386+ // break;
387+ }
388+}
389+
390 void container_set_fullscreen(struct sway_container *con,
391 enum sway_fullscreen_mode mode) {
392 if (con->pending.fullscreen_mode == mode) {