summaryrefslogtreecommitdiffstats
path: root/sway/desktop/xdg_shell_v6.c
diff options
context:
space:
mode:
Diffstat (limited to 'sway/desktop/xdg_shell_v6.c')
-rw-r--r--sway/desktop/xdg_shell_v6.c249
1 files changed, 249 insertions, 0 deletions
diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c
new file mode 100644
index 00000000..e4703040
--- /dev/null
+++ b/sway/desktop/xdg_shell_v6.c
@@ -0,0 +1,249 @@
1#define _POSIX_C_SOURCE 199309L
2#include <stdbool.h>
3#include <stdlib.h>
4#include <wayland-server.h>
5#include <wlr/types/wlr_xdg_shell_v6.h>
6#include "sway/tree/container.h"
7#include "sway/tree/layout.h"
8#include "sway/server.h"
9#include "sway/tree/view.h"
10#include "sway/input/seat.h"
11#include "sway/input/input-manager.h"
12#include "log.h"
13
14static const struct sway_view_child_impl popup_impl;
15
16static void popup_destroy(struct sway_view_child *child) {
17 if (!sway_assert(child->impl == &popup_impl,
18 "Expected an xdg_shell_v6 popup")) {
19 return;
20 }
21 struct sway_xdg_popup_v6 *popup = (struct sway_xdg_popup_v6 *)child;
22 wl_list_remove(&popup->new_popup.link);
23 wl_list_remove(&popup->unmap.link);
24 wl_list_remove(&popup->destroy.link);
25 free(popup);
26}
27
28static const struct sway_view_child_impl popup_impl = {
29 .destroy = popup_destroy,
30};
31
32static struct sway_xdg_popup_v6 *popup_create(
33 struct wlr_xdg_popup_v6 *wlr_popup, struct sway_view *view);
34
35static void popup_handle_new_popup(struct wl_listener *listener, void *data) {
36 struct sway_xdg_popup_v6 *popup =
37 wl_container_of(listener, popup, new_popup);
38 struct wlr_xdg_popup_v6 *wlr_popup = data;
39 popup_create(wlr_popup, popup->child.view);
40}
41
42static void popup_handle_unmap(struct wl_listener *listener, void *data) {
43 struct sway_xdg_popup_v6 *popup = wl_container_of(listener, popup, unmap);
44 view_child_destroy(&popup->child);
45}
46
47static void popup_handle_destroy(struct wl_listener *listener, void *data) {
48 struct sway_xdg_popup_v6 *popup = wl_container_of(listener, popup, destroy);
49 view_child_destroy(&popup->child);
50}
51
52static struct sway_xdg_popup_v6 *popup_create(
53 struct wlr_xdg_popup_v6 *wlr_popup, struct sway_view *view) {
54 struct wlr_xdg_surface_v6 *xdg_surface = wlr_popup->base;
55
56 struct sway_xdg_popup_v6 *popup =
57 calloc(1, sizeof(struct sway_xdg_popup_v6));
58 if (popup == NULL) {
59 return NULL;
60 }
61 view_child_init(&popup->child, &popup_impl, view, xdg_surface->surface);
62
63 wl_signal_add(&xdg_surface->events.new_popup, &popup->new_popup);
64 popup->new_popup.notify = popup_handle_new_popup;
65 wl_signal_add(&xdg_surface->events.unmap, &popup->unmap);
66 popup->unmap.notify = popup_handle_unmap;
67 wl_signal_add(&xdg_surface->events.destroy, &popup->destroy);
68 popup->destroy.notify = popup_handle_destroy;
69
70 return popup;
71}
72
73
74static struct sway_xdg_shell_v6_view *xdg_shell_v6_view_from_view(
75 struct sway_view *view) {
76 if (!sway_assert(view->type == SWAY_VIEW_XDG_SHELL_V6,
77 "Expected xdg_shell_v6 view")) {
78 return NULL;
79 }
80 return (struct sway_xdg_shell_v6_view *)view;
81}
82
83static const char *get_prop(struct sway_view *view, enum sway_view_prop prop) {
84 if (xdg_shell_v6_view_from_view(view) == NULL) {
85 return NULL;
86 }
87 switch (prop) {
88 case VIEW_PROP_TITLE:
89 return view->wlr_xdg_surface_v6->toplevel->title;
90 case VIEW_PROP_APP_ID:
91 return view->wlr_xdg_surface_v6->toplevel->app_id;
92 default:
93 return NULL;
94 }
95}
96
97static void configure(struct sway_view *view, double ox, double oy, int width,
98 int height) {
99 struct sway_xdg_shell_v6_view *xdg_shell_v6_view =
100 xdg_shell_v6_view_from_view(view);
101 if (xdg_shell_v6_view == NULL) {
102 return;
103 }
104
105 view_update_position(view, ox, oy);
106 xdg_shell_v6_view->pending_width = width;
107 xdg_shell_v6_view->pending_height = height;
108 wlr_xdg_toplevel_v6_set_size(view->wlr_xdg_surface_v6, width, height);
109}
110
111static void set_activated(struct sway_view *view, bool activated) {
112 if (xdg_shell_v6_view_from_view(view) == NULL) {
113 return;
114 }
115 struct wlr_xdg_surface_v6 *surface = view->wlr_xdg_surface_v6;
116 if (surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL) {
117 wlr_xdg_toplevel_v6_set_activated(surface, activated);
118 }
119}
120
121static void for_each_surface(struct sway_view *view,
122 wlr_surface_iterator_func_t iterator, void *user_data) {
123 if (xdg_shell_v6_view_from_view(view) == NULL) {
124 return;
125 }
126 wlr_xdg_surface_v6_for_each_surface(view->wlr_xdg_surface_v6, iterator,
127 user_data);
128}
129
130static void _close(struct sway_view *view) {
131 if (xdg_shell_v6_view_from_view(view) == NULL) {
132 return;
133 }
134 struct wlr_xdg_surface_v6 *surface = view->wlr_xdg_surface_v6;
135 if (surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL) {
136 wlr_xdg_surface_v6_send_close(surface);
137 }
138}
139
140static void destroy(struct sway_view *view) {
141 struct sway_xdg_shell_v6_view *xdg_shell_v6_view =
142 xdg_shell_v6_view_from_view(view);
143 if (xdg_shell_v6_view == NULL) {
144 return;
145 }
146 wl_list_remove(&xdg_shell_v6_view->destroy.link);
147 wl_list_remove(&xdg_shell_v6_view->map.link);
148 wl_list_remove(&xdg_shell_v6_view->unmap.link);
149 free(xdg_shell_v6_view);
150}
151
152static const struct sway_view_impl view_impl = {
153 .get_prop = get_prop,
154 .configure = configure,
155 .set_activated = set_activated,
156 .for_each_surface = for_each_surface,
157 .close = _close,
158 .destroy = destroy,
159};
160
161static void handle_commit(struct wl_listener *listener, void *data) {
162 struct sway_xdg_shell_v6_view *xdg_shell_v6_view =
163 wl_container_of(listener, xdg_shell_v6_view, commit);
164 struct sway_view *view = &xdg_shell_v6_view->view;
165 // NOTE: We intentionally discard the view's desired width here
166 // TODO: Store this for restoration when moving to floating plane
167 // TODO: Let floating views do whatever
168 view_update_size(view, xdg_shell_v6_view->pending_width,
169 xdg_shell_v6_view->pending_height);
170 view_damage(view, false);
171}
172
173static void handle_new_popup(struct wl_listener *listener, void *data) {
174 struct sway_xdg_shell_v6_view *xdg_shell_v6_view =
175 wl_container_of(listener, xdg_shell_v6_view, new_popup);
176 struct wlr_xdg_popup_v6 *wlr_popup = data;
177 popup_create(wlr_popup, &xdg_shell_v6_view->view);
178}
179
180static void handle_unmap(struct wl_listener *listener, void *data) {
181 struct sway_xdg_shell_v6_view *xdg_shell_v6_view =
182 wl_container_of(listener, xdg_shell_v6_view, unmap);
183
184 view_unmap(&xdg_shell_v6_view->view);
185
186 wl_list_remove(&xdg_shell_v6_view->commit.link);
187 wl_list_remove(&xdg_shell_v6_view->new_popup.link);
188}
189
190static void handle_map(struct wl_listener *listener, void *data) {
191 struct sway_xdg_shell_v6_view *xdg_shell_v6_view =
192 wl_container_of(listener, xdg_shell_v6_view, map);
193 struct sway_view *view = &xdg_shell_v6_view->view;
194 struct wlr_xdg_surface_v6 *xdg_surface = view->wlr_xdg_surface_v6;
195
196 view_map(view, view->wlr_xdg_surface_v6->surface);
197
198 xdg_shell_v6_view->commit.notify = handle_commit;
199 wl_signal_add(&xdg_surface->surface->events.commit,
200 &xdg_shell_v6_view->commit);
201
202 xdg_shell_v6_view->new_popup.notify = handle_new_popup;
203 wl_signal_add(&xdg_surface->events.new_popup,
204 &xdg_shell_v6_view->new_popup);
205}
206
207static void handle_destroy(struct wl_listener *listener, void *data) {
208 struct sway_xdg_shell_v6_view *xdg_shell_v6_view =
209 wl_container_of(listener, xdg_shell_v6_view, destroy);
210 view_destroy(&xdg_shell_v6_view->view);
211}
212
213void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) {
214 struct sway_server *server = wl_container_of(listener, server,
215 xdg_shell_v6_surface);
216 struct wlr_xdg_surface_v6 *xdg_surface = data;
217
218 if (xdg_surface->role == WLR_XDG_SURFACE_V6_ROLE_POPUP) {
219 wlr_log(L_DEBUG, "New xdg_shell_v6 popup");
220 return;
221 }
222
223 wlr_log(L_DEBUG, "New xdg_shell_v6 toplevel title='%s' app_id='%s'",
224 xdg_surface->toplevel->title, xdg_surface->toplevel->app_id);
225 wlr_xdg_surface_v6_ping(xdg_surface);
226 wlr_xdg_toplevel_v6_set_maximized(xdg_surface, true);
227
228 struct sway_xdg_shell_v6_view *xdg_shell_v6_view =
229 calloc(1, sizeof(struct sway_xdg_shell_v6_view));
230 if (!sway_assert(xdg_shell_v6_view, "Failed to allocate view")) {
231 return;
232 }
233
234 view_init(&xdg_shell_v6_view->view, SWAY_VIEW_XDG_SHELL_V6, &view_impl);
235 xdg_shell_v6_view->view.wlr_xdg_surface_v6 = xdg_surface;
236
237 // TODO:
238 // - Look up pid and open on appropriate workspace
239 // - Criteria
240
241 xdg_shell_v6_view->map.notify = handle_map;
242 wl_signal_add(&xdg_surface->events.map, &xdg_shell_v6_view->map);
243
244 xdg_shell_v6_view->unmap.notify = handle_unmap;
245 wl_signal_add(&xdg_surface->events.unmap, &xdg_shell_v6_view->unmap);
246
247 xdg_shell_v6_view->destroy.notify = handle_destroy;
248 wl_signal_add(&xdg_surface->events.destroy, &xdg_shell_v6_view->destroy);
249}