xdgtoplevel_shmifev_handler(struct comp_surf * surf,struct arcan_event * ev)1 static bool xdgtoplevel_shmifev_handler(
2 struct comp_surf* surf, struct arcan_event* ev)
3 {
4 if (!surf->shell_res)
5 return true;
6
7 if (ev->category == EVENT_TARGET)
8 switch (ev->tgt.kind){
9
10 case TARGET_COMMAND_DISPLAYHINT:{
11 /* update state tracking first */
12 trace(TRACE_SHELL, "xdg-toplevel(%"PRIxPTR"):hint=%d,%d,%d,%d:size=%d,%d",
13 (uintptr_t) surf,
14 ev->tgt.ioevs[0].iv, ev->tgt.ioevs[1].iv,
15 ev->tgt.ioevs[2].iv, ev->tgt.ioevs[3].iv, surf->acon.w, surf->acon.h);
16
17 bool changed = displayhint_handler(surf, &ev->tgt);
18
19 /* and then, if something has changed, send the configure event */
20 int w = ev->tgt.ioevs[0].iv;
21 int h = ev->tgt.ioevs[1].iv;
22 if (!w)
23 w = surf->acon.w;
24 if (!h)
25 h = surf->acon.h;
26
27 bool resized = (w && h && (w != surf->acon.w || h != surf->acon.h));
28 if (!resized){
29 if (surf->geom_w)
30 w = surf->geom_w;
31 if (surf->geom_h)
32 h = surf->geom_h;
33 }
34
35 if (changed || resized){
36 struct wl_array states;
37
38 if (resized){
39 trace(TRACE_SHELL,
40 "resizereq:last=%d,%d:req:=%d,%d",
41 (int) surf->acon.w, (int) surf->acon.h, w, h);
42 }
43
44 wl_array_init(&states);
45 uint32_t* sv;
46 if (surf->states.maximized){
47 sv = wl_array_add(&states, sizeof(uint32_t));
48 *sv = XDG_TOPLEVEL_STATE_MAXIMIZED;
49 trace(TRACE_SHELL, "maximized");
50 }
51
52 if (surf->states.fullscreen){
53 sv = wl_array_add(&states, sizeof(uint32_t));
54 *sv = XDG_TOPLEVEL_STATE_FULLSCREEN;
55 trace(TRACE_SHELL, "fullscreen");
56 }
57
58 if (surf->states.drag_resize){
59 sv = wl_array_add(&states, sizeof(uint32_t));
60 *sv = XDG_TOPLEVEL_STATE_RESIZING;
61 trace(TRACE_SHELL, "resizing");
62 }
63
64 if (!surf->states.unfocused){
65 sv = wl_array_add(&states, sizeof(uint32_t));
66 *sv = XDG_TOPLEVEL_STATE_ACTIVATED;
67 trace(TRACE_SHELL, "focused");
68 }
69 else {
70 release_all_keys(surf->client);
71 }
72
73 if (wl.force_sz){
74 w = wl.init.display_width_px;
75 h = wl.init.display_height_px;
76 }
77
78 w *= (1.0 / surf->scale);
79 h *= (1.0 / surf->scale);
80
81 xdg_toplevel_send_configure(surf->shell_res, w, h, &states);
82 xdg_surface_send_configure(surf->surf_res, STEP_SERIAL());
83
84 /* from zxdg_toplevel_decoration_v1_configure */
85 if (surf->pending_decoration && surf->decor_mgmt){
86 trace(TRACE_SHELL, "decor=%d", surf->pending_decoration);
87 zxdg_toplevel_decoration_v1_send_configure(
88 surf->decor_mgmt, surf->pending_decoration);
89 surf->pending_decoration = 0;
90 }
91
92 wl_array_release(&states);
93 changed = true;
94 }
95
96 if (changed)
97 try_frame_callback(surf);
98 }
99 return true;
100 break;
101
102 /* Previously we flushed callbacks and released buffers here, but afaict
103 * the proper procedure is to let the client do the closing as a response to
104 * send_close. After this all arcan- related calls will fail on the surface, so
105 * chances are that a window could go with something like 'do you really want
106 * to close' and we can't actually draw that anywhere, this is not really
107 * solvable, can only warn the appl- side about the perils of force closing a
108 * wayland surface - unless there is some error we can send to fake it */
109 case TARGET_COMMAND_EXIT:
110 xdg_toplevel_send_close(surf->shell_res);
111 return true;
112 break;
113 default:
114 break;
115 }
116
117 return false;
118 }
119
xdgtop_setparent(struct wl_client * cl,struct wl_resource * res,struct wl_resource * parent)120 static void xdgtop_setparent(
121 struct wl_client* cl, struct wl_resource* res, struct wl_resource* parent)
122 {
123 trace(TRACE_SHELL, "parent: %"PRIxPTR, (uintptr_t) parent);
124 struct comp_surf* surf = wl_resource_get_user_data(res);
125 uint32_t par_token = 0;
126 int8_t order = 0;
127
128 if (parent){
129 struct comp_surf* par = wl_resource_get_user_data(parent);
130 par_token = par->acon.segment_token;
131 order = par->viewport.ext.viewport.order + 1;
132 }
133 surf->viewport.ext.viewport.order = order;
134 surf->viewport.ext.viewport.parent = par_token;
135
136 /* Likely that we need more order tracking for subsurfaces, or shift
137 * the relative assignment to the scripting layer again */
138 arcan_shmif_enqueue(&surf->acon, &(struct arcan_event){
139 .ext.kind = ARCAN_EVENT(VIEWPORT),
140 .ext.viewport.parent = par_token,
141 .ext.viewport.order = order
142 });
143 }
144
xdgtop_title(struct wl_client * cl,struct wl_resource * res,const char * title)145 static void xdgtop_title(
146 struct wl_client* cl, struct wl_resource* res, const char* title)
147 {
148 trace(TRACE_SHELL, "%s", title ? title : "(null)");
149 struct comp_surf* surf = wl_resource_get_user_data(res);
150
151 arcan_event ev = {
152 .ext.kind = ARCAN_EVENT(IDENT)
153 };
154 size_t lim = sizeof(ev.ext.message.data)/sizeof(ev.ext.message.data[1]);
155 snprintf((char*)ev.ext.message.data, lim, "%s", title);
156 arcan_shmif_enqueue(&surf->acon, &ev);
157 }
158
xdgtop_appid(struct wl_client * cl,struct wl_resource * res,const char * app_id)159 static void xdgtop_appid(
160 struct wl_client* cl, struct wl_resource* res, const char* app_id)
161 {
162 trace(TRACE_SHELL, "xdgtop_app_id");
163 /* I wondered how long it would take for D-Bus to rear its ugly
164 * face along with the .desktop clusterfuck. I wonder no more.
165 * we can wrap this around some _message call and leave it to
166 * the appl to determine if the crap should be bridged or not. */
167 }
168
xdgtop_wndmenu(struct wl_client * cl,struct wl_resource * res,struct wl_resource * seat,uint32_t serial,int32_t x,int32_t y)169 static void xdgtop_wndmenu(struct wl_client* cl, struct wl_resource* res,
170 struct wl_resource* seat, uint32_t serial, int32_t x, int32_t y)
171 {
172 trace(TRACE_SHELL, "@x,y: %"PRId32", %"PRId32"", x, y);
173 }
174
175 /*
176 * "The server may ignore move requests depending on the state of
177 * the surface (e.g. fullscreen or maximized), or if the passed
178 * serial is no longer valid."
179 *
180 * i.e. the state can be such that it never needs to drag-move..
181 *
182 * "If triggered, the surface will lose the focus of the device
183 * (wl_pointer, wl_touch, etc) used for the move. It is up to the
184 * compositor to visually indicate that the move is taking place,
185 * such as updating a pointer cursor, during the move. There is no
186 * guarantee that the device focus will return when the move is
187 * completed."
188 *
189 * so this implies that the compositor actually needs to have
190 * state cursors.
191 * => _CURSORHINT
192 */
xdgtop_move(struct wl_client * cl,struct wl_resource * res,struct wl_resource * seat,uint32_t serial)193 static void xdgtop_move(struct wl_client* cl,
194 struct wl_resource* res, struct wl_resource* seat, uint32_t serial)
195 {
196 trace(TRACE_SHELL, "%"PRIxPTR", serial: %"PRIu32, (uintptr_t) seat, serial);
197 struct comp_surf* surf = wl_resource_get_user_data(res);
198 arcan_shmif_enqueue(&surf->acon, &(struct arcan_event){
199 .ext.kind = ARCAN_EVENT(MESSAGE),
200 .ext.message.data = {"shell:xdg_top:move"}
201 });
202 }
203
xdg_edge_to_mask(uint32_t edges,int * dx,int * dy)204 static void xdg_edge_to_mask(uint32_t edges, int* dx, int* dy)
205 {
206 switch (edges){
207 case XDG_TOPLEVEL_RESIZE_EDGE_TOP:
208 *dx = 0; *dy = -1;
209 break;
210 case XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM:
211 *dx = 0; *dy = 1;
212 break;
213 case XDG_TOPLEVEL_RESIZE_EDGE_LEFT:
214 *dx = -1; *dy = 0;
215 break;
216 case XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT:
217 *dx = -1; *dy = -1;
218 break;
219 case XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT:
220 *dx = -1; *dy = 1;
221 break;
222 case XDG_TOPLEVEL_RESIZE_EDGE_RIGHT:
223 *dx = 1; *dy = 0;
224 break;
225 case XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT:
226 *dx = 1; *dy = -1;
227 break;
228 case XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT:
229 *dx = 1; *dy = 1;
230 break;
231 default:
232 *dx = *dy = 0;
233 }
234 }
235
xdgtop_resize(struct wl_client * cl,struct wl_resource * res,struct wl_resource * seat,uint32_t serial,uint32_t edges)236 static void xdgtop_resize(struct wl_client* cl, struct wl_resource* res,
237 struct wl_resource* seat, uint32_t serial, uint32_t edges)
238 {
239 trace(TRACE_SHELL, "serial: %"PRIu32", edges: %"PRIu32, serial, edges);
240 struct comp_surf* surf = wl_resource_get_user_data(res);
241 struct arcan_event ev = {
242 .ext.kind = ARCAN_EVENT(MESSAGE)
243 };
244
245 int dx, dy;
246 xdg_edge_to_mask(edges, &dx, &dy);
247 size_t lim = sizeof(ev.ext.message.data)/sizeof(ev.ext.message.data[1]);
248 snprintf((char*)ev.ext.message.data, lim, "shell:xdg_top:resize:%d:%d", dx, dy);
249 arcan_shmif_enqueue(&surf->acon, &ev);
250 }
251
252 /*
253 * => We need to track this in the client structure so that the
254 * reconfigure done in reaction to DISPLAYHINT constrain this.
255 *
256 * All these comes for the reason that the titlebar lives in the
257 * client as part of the toplevel surface.
258 */
xdgtop_set_max(struct wl_client * cl,struct wl_resource * res,int32_t width,int32_t height)259 static void xdgtop_set_max(struct wl_client* cl,
260 struct wl_resource* res, int32_t width, int32_t height)
261 {
262 trace(TRACE_SHELL, "xdgtop_set_max (%"PRId32", %"PRId32")");
263 struct comp_surf* surf = wl_resource_get_user_data(res);
264 surf->max_w = width * (1.0 / surf->scale);
265 surf->max_h = height * (1.0 / surf->scale);
266 }
267
268 /*
269 * Same as with _max
270 */
xdgtop_set_min(struct wl_client * cl,struct wl_resource * res,int32_t width,int32_t height)271 static void xdgtop_set_min(struct wl_client* cl,
272 struct wl_resource* res, int32_t width, int32_t height)
273 {
274 trace(TRACE_SHELL, "xdgtop_set_min (%"PRId32", %"PRId32")", width, height);
275 struct comp_surf* surf = wl_resource_get_user_data(res);
276 surf->min_w = width * (1.0 / surf->scale);
277 surf->min_h = height * (1.0 / surf->scale);
278 }
279
280 /*
281 * Hmm, this actually has implications for the presence of shadow
282 */
xdgtop_maximize(struct wl_client * cl,struct wl_resource * res)283 static void xdgtop_maximize(
284 struct wl_client* cl, struct wl_resource* res)
285 {
286 trace(TRACE_SHELL, "xdgtop_maximize");
287 struct comp_surf* surf = wl_resource_get_user_data(res);
288 arcan_shmif_enqueue(&surf->acon, &(struct arcan_event){
289 .ext.kind = ARCAN_EVENT(MESSAGE),
290 .ext.message.data = {"shell:xdg_top:maximize"}
291 });
292 }
293
xdgtop_demaximize(struct wl_client * cl,struct wl_resource * res)294 static void xdgtop_demaximize(
295 struct wl_client* cl, struct wl_resource* res)
296 {
297 trace(TRACE_SHELL, "xdgtop_demaximize");
298 struct comp_surf* surf = wl_resource_get_user_data(res);
299 arcan_shmif_enqueue(&surf->acon, &(struct arcan_event){
300 .ext.kind = ARCAN_EVENT(MESSAGE),
301 .ext.message.data = {"shell:xdg_top:demaximize"}
302 });
303 }
304
xdgtop_fullscreen(struct wl_client * cl,struct wl_resource * res,struct wl_resource * output)305 static void xdgtop_fullscreen(
306 struct wl_client* cl, struct wl_resource* res, struct wl_resource* output)
307 {
308 trace(TRACE_SHELL, "xdgtop_fullscreen");
309 struct comp_surf* surf = wl_resource_get_user_data(res);
310 arcan_shmif_enqueue(&surf->acon, &(struct arcan_event){
311 .ext.kind = ARCAN_EVENT(MESSAGE),
312 .ext.message.data = {"shell:xdg_top:fullscreen"}
313 });
314 }
315
xdgtop_unset_fullscreen(struct wl_client * cl,struct wl_resource * res)316 static void xdgtop_unset_fullscreen(
317 struct wl_client* cl, struct wl_resource* res)
318 {
319 trace(TRACE_SHELL, "xdgtop_unset_fullscreen");
320 struct comp_surf* surf = wl_resource_get_user_data(res);
321 arcan_shmif_enqueue(&surf->acon, &(struct arcan_event){
322 .ext.kind = ARCAN_EVENT(MESSAGE),
323 .ext.message.data = {"shell:xdg_top:defullscreen"}
324 });
325 }
326
xdgtop_minimize(struct wl_client * cl,struct wl_resource * res)327 static void xdgtop_minimize(
328 struct wl_client* cl, struct wl_resource* res)
329 {
330 trace(TRACE_SHELL, "xdgtop_minimize");
331 struct comp_surf* surf = wl_resource_get_user_data(res);
332 arcan_shmif_enqueue(&surf->acon, &(struct arcan_event){
333 .ext.kind = ARCAN_EVENT(MESSAGE),
334 .ext.message.data = {"shell:xdg_top:minimize"}
335 });
336 }
337
xdgtop_destroy(struct wl_client * cl,struct wl_resource * res)338 static void xdgtop_destroy(
339 struct wl_client* cl, struct wl_resource* res)
340 {
341 trace(TRACE_ALLOC, "%"PRIxPTR, (uintptr_t)res);
342 struct comp_surf* surf = wl_resource_get_user_data(res);
343
344 /* so we don't send a _leave to a dangling surface */
345 if (surf && surf->client){
346 if (surf->client->last_cursor == res)
347 surf->client->last_cursor = NULL;
348 }
349 }
350
xdgtop_internal(struct comp_surf * surf,int cmd)351 static void xdgtop_internal(struct comp_surf* surf, int cmd)
352 {
353 try_frame_callback(surf);
354 }
355