xdgpop_defer_handler(struct surface_request * req,struct arcan_shmif_cont * con)1 static bool xdgpop_defer_handler(
2 struct surface_request* req, struct arcan_shmif_cont* con)
3 {
4 if (!con){
5 trace(TRACE_SHELL, "reqfail");
6 wl_resource_post_no_memory(req->target);
7 return false;
8 }
9
10 /*
11 * PROTOCOL NOTE:
12 * positioner needs to be validated: non-zero size, non-zero anchor is needed,
13 * else send: ZXDG_SHELL_V6_ERROR_INVALID_POSITIONER
14 *
15 * parent needs to be validated,
16 * else send ZXDG_SHELL_V6_ERROR_POPUP_PARENT
17 *
18 * + destroy- rules that are a bit clunky
19 */
20 struct wl_resource* popup = wl_resource_create(req->client->client,
21 &xdg_popup_interface, wl_resource_get_version(req->target), req->id);
22
23 if (!popup){
24 wl_resource_post_no_memory(req->target);
25 return false;
26 }
27
28 struct comp_surf* surf = wl_resource_get_user_data(req->target);
29 wl_resource_set_implementation(popup, &xdgpop_if, surf, NULL);
30 surf->acon = *con;
31 surf->cookie = 0xfeedface;
32 surf->shell_res = popup;
33 surf->dispatch = xdgpopup_shmifev_handler;
34
35 snprintf(surf->tracetag, SURF_TAGLEN, "xdg_popup");
36 arcan_shmif_enqueue(&surf->acon, &(struct arcan_event){
37 .ext.kind = ARCAN_EVENT(MESSAGE),
38 .ext.message.data = {"shell:xdg_popup"}
39 });
40
41 /* update the viewport hint and send that event */
42 bool upd_view = false;
43 if (req->positioner){
44 struct positioner* pos = wl_resource_get_user_data(req->positioner);
45 apply_positioner(pos, &surf->viewport);
46 upd_view = true;
47 }
48
49 if (req->parent){
50 struct comp_surf* psurf = wl_resource_get_user_data(req->parent);
51 if (!psurf->acon.addr){
52 trace(TRACE_ALLOC, "bad popup, broken parent");
53 return false;
54 }
55 surf->viewport.ext.viewport.parent = psurf->acon.segment_token;
56 upd_view = true;
57 }
58
59 /* likely that if this is not true, we have a protocol error */
60 if (upd_view){
61 arcan_shmif_enqueue(&surf->acon, &surf->viewport);
62 xdg_popup_send_configure(popup,
63 surf->viewport.ext.viewport.x, surf->viewport.ext.viewport.y,
64 surf->viewport.ext.viewport.w, surf->viewport.ext.viewport.h);
65 xdg_surface_send_configure(surf->surf_res, STEP_SERIAL());
66 }
67
68 surf->internal = xdgpop_internal;
69 return true;
70 }
71
xdgtop_defer_handler(struct surface_request * req,struct arcan_shmif_cont * con)72 static bool xdgtop_defer_handler(
73 struct surface_request* req, struct arcan_shmif_cont* con)
74 {
75 if (!con){
76 trace(TRACE_SHELL, "xdgsurf:reqfail");
77 wl_resource_post_no_memory(req->target);
78 return false;
79 }
80
81 struct wl_resource* toplevel = wl_resource_create(req->client->client,
82 &xdg_toplevel_interface, wl_resource_get_version(req->target), req->id);
83
84 if (!toplevel){
85 wl_resource_post_no_memory(req->target);
86 return false;
87 }
88
89 struct comp_surf* surf = wl_resource_get_user_data(req->target);
90 wl_resource_set_implementation(toplevel, &xdgtop_if, surf, NULL);
91 surf->acon = *con;
92 surf->cookie = 0xfeedface;
93 surf->shell_res = toplevel;
94 surf->dispatch = xdgtoplevel_shmifev_handler;
95 snprintf(surf->tracetag, SURF_TAGLEN, "xdg_toplevel");
96
97 /* propagate this so the scripts have a chance of following the restrictions
98 * indicated by the protocol */
99 arcan_shmif_enqueue(&surf->acon, &(struct arcan_event){
100 .ext.kind = ARCAN_EVENT(MESSAGE),
101 .ext.message.data = {"shell:xdg_top"}
102 });
103
104 struct wl_array states;
105 wl_array_init(&states);
106
107 size_t w = surf->acon.w;
108 size_t h = surf->acon.h;
109 if (wl.force_sz){
110 w = wl.init.display_width_px * (1.0 / surf->scale);
111 h = wl.init.display_height_px * (1.0 / surf->scale);
112 }
113
114 xdg_toplevel_send_configure(toplevel, w, h, &states);
115 xdg_surface_send_configure(surf->surf_res, STEP_SERIAL());
116 surf->internal = xdgtop_internal;
117 wl_array_release(&states);
118 return true;
119 }
120
xdgsurf_toplevel(struct wl_client * cl,struct wl_resource * res,uint32_t id)121 static void xdgsurf_toplevel(
122 struct wl_client* cl, struct wl_resource* res, uint32_t id)
123 {
124 trace(TRACE_SHELL, "%"PRIu32, id);
125 struct comp_surf* surf = wl_resource_get_user_data(res);
126
127 /* though it is marked as 'defered' here, chances are that the request
128 * function will just return with the surface immediately */
129 request_surface(surf->client, &(struct surface_request){
130 .segid = SEGID_APPLICATION,
131 .target = res,
132 .id = id,
133 .trace = "xdg toplevel",
134 .dispatch = xdgtop_defer_handler,
135 .client = surf->client,
136 .source = surf
137 }, 't');
138 }
139
xdgsurf_getpopup(struct wl_client * cl,struct wl_resource * res,uint32_t id,struct wl_resource * parent,struct wl_resource * positioner)140 static void xdgsurf_getpopup(struct wl_client* cl, struct wl_resource* res,
141 uint32_t id, struct wl_resource* parent, struct wl_resource* positioner)
142 {
143 trace(TRACE_SHELL, "xdgsurf_getpopup");
144 struct comp_surf* surf = wl_resource_get_user_data(res);
145 request_surface(surf->client, &(struct surface_request ){
146 .segid = SEGID_POPUP,
147 .target = res,
148 .id = id,
149 .trace = "xdg popup",
150 .dispatch = xdgpop_defer_handler,
151 .client = surf->client,
152 .source = surf,
153 .parent = parent,
154 .positioner = positioner
155 }, 'p');
156 }
157
158 /* Hints about the window visible size sans dropshadows and things like that,
159 * but since it doesn't carry information about decorations (titlebar, ...)
160 * we can't actually use this for a full viewport hint. Still better than
161 * nothing and since we WM script need to take 'special ed' considerations
162 * for xdg- clients anyhow, go with that. */
xdgsurf_set_geometry(struct wl_client * cl,struct wl_resource * res,int32_t x,int32_t y,int32_t width,int32_t height)163 static void xdgsurf_set_geometry(struct wl_client* cl,
164 struct wl_resource* res, int32_t x, int32_t y, int32_t width, int32_t height)
165 {
166 struct comp_surf* surf = wl_resource_get_user_data(res);
167 if (!surf)
168 return;
169
170 trace(TRACE_SHELL, "xdgsurf_setgeom("
171 "%"PRIu32"+%"PRIu32", %"PRIu32"+%"PRIu32")", x, y, width, height);
172
173 /* the better way is to use the tldr[] from the VIEWPORT hint,
174 * we just need a 'dirty- viewport' and a cache of the properties first */
175 struct arcan_event ev = {
176 .ext.kind = ARCAN_EVENT(MESSAGE)
177 };
178 snprintf((char*)ev.ext.message.data,
179 COUNT_OF(ev.ext.message.data),
180 "geom:%"PRIu32":%"PRIu32":%"PRIu32":%"PRIu32, x, y, width, height
181 );
182
183 surf->geom_x = x;
184 surf->geom_y = y;
185 surf->geom_w = width;
186 surf->geom_h = height;
187 arcan_shmif_enqueue(&surf->acon, &ev);
188 }
189
xdgsurf_ackcfg(struct wl_client * cl,struct wl_resource * res,uint32_t serial)190 static void xdgsurf_ackcfg(
191 struct wl_client* cl, struct wl_resource* res, uint32_t serial)
192 {
193 trace(TRACE_SHELL, "%"PRIu32, serial);
194 /* reading the spec for this makes it seem like there can be many
195 * 'in flight' cfgs and you need to send ack individually and thus
196 * track pending cfgs that lacks an acq */
197 }
198
xdgsurf_destroy(struct wl_client * cl,struct wl_resource * res)199 static void xdgsurf_destroy(
200 struct wl_client* cl, struct wl_resource* res)
201 {
202 trace(TRACE_ALLOC, "%"PRIxPTR, res);
203 struct comp_surf* surf = wl_resource_get_user_data(res);
204 if (surf){
205 surf->shell_res = NULL;
206 surf->internal = NULL;
207 }
208 wl_resource_destroy(res);
209 }
210