keyrouter: Fix wrong validity check
[platform/core/uifw/libds-tizen.git] / src / libds / xdg_shell / xdg_surface.c
1 #include <assert.h>
2 #include <stdlib.h>
3
4 #include "libds/log.h"
5
6 #include "xdg_shell.h"
7
8 static const struct xdg_surface_interface xdg_surface_impl;
9
10 static void xdg_surface_handle_surface_destroy(struct wl_listener *listener,
11         void *data);
12 static void xdg_surface_handle_surface_commit(struct wl_listener *listener,
13         void *data);
14 static void xdg_surface_handle_resource_destroy(struct wl_resource *resource);
15 static void xdg_surface_configure_destroy(struct ds_xdg_surface_configure *configure);
16 static void surface_send_configure(void *user_data);
17
18 void
19 ds_xdg_surface_add_destroy_listener(struct ds_xdg_surface *surface,
20         struct wl_listener *listener)
21 {
22     wl_signal_add(&surface->events.destroy, listener);
23 }
24
25 WL_EXPORT void
26 ds_xdg_surface_add_map_listener(struct ds_xdg_surface *surface,
27         struct wl_listener *listener)
28 {
29     wl_signal_add(&surface->events.map, listener);
30 }
31
32 WL_EXPORT void
33 ds_xdg_surface_add_unmap_listener(struct ds_xdg_surface *surface,
34         struct wl_listener *listener)
35 {
36     wl_signal_add(&surface->events.unmap, listener);
37 }
38
39 struct ds_surface *
40 ds_xdg_surface_get_surface(struct ds_xdg_surface *surface)
41 {
42     return surface->ds_surface;
43 }
44
45 struct ds_xdg_surface *
46 create_xdg_surface(struct ds_xdg_client *client, struct ds_surface *ds_surface,
47         uint32_t id)
48 {
49     struct ds_xdg_surface *surface;
50
51     surface = calloc(1, sizeof *surface);
52     if (!surface) {
53         wl_client_post_no_memory(client->wl_client);
54         return NULL;
55     }
56
57     surface->client = client;
58     surface->role = DS_XDG_SURFACE_ROLE_NONE;
59     surface->ds_surface = ds_surface;
60     surface->resource = wl_resource_create(client->wl_client,
61             &xdg_surface_interface, wl_resource_get_version(client->resource),
62             id);
63     if (!surface->resource) {
64         free(surface);
65         wl_client_post_no_memory(client->wl_client);
66         return NULL;
67     }
68
69     if (ds_surface_has_buffer(surface->ds_surface)) {
70         wl_resource_destroy(surface->resource);
71         free(surface);
72         wl_resource_post_error(client->resource,
73                 XDG_SURFACE_ERROR_UNCONFIGURED_BUFFER,
74                 "xdg_surface must not have a buffer at creation");
75         return NULL;
76     }
77
78     wl_list_init(&surface->configure_list);
79
80     wl_signal_init(&surface->events.destroy);
81     wl_signal_init(&surface->events.ping_timeout);
82     wl_signal_init(&surface->events.new_popup);
83     wl_signal_init(&surface->events.map);
84     wl_signal_init(&surface->events.unmap);
85     wl_signal_init(&surface->events.configure);
86     wl_signal_init(&surface->events.ack_configure);
87
88     surface->listener.surface_destroy.notify =
89         xdg_surface_handle_surface_destroy;
90     ds_surface_add_destroy_listener(ds_surface,
91             &surface->listener.surface_destroy);
92
93     surface->listener.surface_commit.notify =
94         xdg_surface_handle_surface_commit;
95     ds_surface_add_commit_listener(ds_surface,
96             &surface->listener.surface_commit);
97
98     wl_resource_set_implementation(surface->resource, &xdg_surface_impl,
99             surface, xdg_surface_handle_resource_destroy);
100
101     wl_list_insert(&client->surfaces, &surface->link);
102
103     ds_inf("New xdg_surface %p (res %p)", surface, surface->resource);
104
105     return surface;
106 }
107
108 void
109 unmap_xdg_surface(struct ds_xdg_surface *surface)
110 {
111     struct ds_xdg_surface_configure *configure, *tmp;
112
113     // TODO handle popup
114
115     if (surface->mapped)
116         wl_signal_emit(&surface->events.unmap, surface);
117
118     switch (surface->role) {
119         case DS_XDG_SURFACE_ROLE_TOPLEVEL:
120             if (surface->toplevel->parent) {
121                 wl_list_remove(&surface->toplevel->parent_unmap.link);
122                 surface->toplevel->parent = NULL;
123             }
124             free(surface->toplevel->title);
125             surface->toplevel->title = NULL;
126             free(surface->toplevel->app_id);
127             surface->toplevel->app_id = NULL;
128             break;
129         case DS_XDG_SURFACE_ROLE_POPUP:
130             // TODO
131             break;
132         case DS_XDG_SURFACE_ROLE_NONE:
133             assert(false && "not reached");
134     }
135
136     wl_list_for_each_safe(configure, tmp, &surface->configure_list, link)
137         xdg_surface_configure_destroy(configure);
138
139     if (surface->configure_idle) {
140         wl_event_source_remove(surface->configure_idle);
141         surface->configure_idle = NULL;
142     }
143
144     surface->configured = false;
145     surface->mapped = false;
146 }
147
148 void
149 reset_xdg_surface(struct ds_xdg_surface *surface)
150 {
151     struct ds_xdg_toplevel_requested *req;
152
153     if (surface->role != DS_XDG_SURFACE_ROLE_NONE)
154         unmap_xdg_surface(surface);
155
156     if (surface->added) {
157         wl_signal_emit(&surface->events.destroy, surface);
158         surface->added = false;
159     }
160
161     switch (surface->role) {
162         case DS_XDG_SURFACE_ROLE_TOPLEVEL:
163             wl_resource_set_user_data(surface->toplevel->resource, NULL);
164             surface->toplevel->resource = NULL;
165             req = &surface->toplevel->requested;
166             if (req->fullscreen_output)
167                 wl_list_remove(&req->fullscreen_output_destroy.link);
168             free(surface->toplevel);
169             surface->toplevel = NULL;
170             break;
171         case DS_XDG_SURFACE_ROLE_POPUP:
172             // TODO
173             break;
174         case DS_XDG_SURFACE_ROLE_NONE:
175             // This space is intentionally left blank
176             break;
177     }
178
179     surface->role = DS_XDG_SURFACE_ROLE_NONE;
180 }
181
182 void
183 destroy_xdg_surface(struct ds_xdg_surface *surface)
184 {
185     reset_xdg_surface(surface);
186
187     wl_resource_set_user_data(surface->resource, NULL);
188
189     ds_surface_reset_role_data(surface->ds_surface);
190
191     wl_list_remove(&surface->link);
192     wl_list_remove(&surface->listener.surface_destroy.link);
193     wl_list_remove(&surface->listener.surface_commit.link);
194
195     free(surface);
196 }
197
198 void
199 handle_xdg_surface_commit(struct ds_surface *ds_surface)
200 {
201     struct ds_xdg_surface *surface;
202
203     surface = ds_surface_get_role_data(ds_surface);
204     surface->current = surface->pending;
205
206     switch (surface->role) {
207         case DS_XDG_SURFACE_ROLE_NONE:
208             // inert toplevel or popup
209             break;
210         case DS_XDG_SURFACE_ROLE_TOPLEVEL:
211             handle_xdg_surface_toplevel_committed(surface);
212             // TODO
213             break;
214         case DS_XDG_SURFACE_ROLE_POPUP:
215             // TODO
216             break;
217     }
218
219     if (!surface->added) {
220         surface->added = true;
221         wl_signal_emit(&surface->client->shell->events.new_surface, surface);
222     }
223
224     if (surface->configured &&
225             ds_surface_has_buffer(surface->ds_surface) &&
226             !surface->mapped) {
227         surface->mapped = true;
228         wl_signal_emit(&surface->events.map, surface);
229     }
230 }
231
232 void handle_xdg_surface_precommit(struct ds_surface *ds_surface)
233 {
234     struct ds_xdg_surface *surface;
235
236     surface = ds_surface_get_role_data(ds_surface);
237
238     // TODO
239     (void)surface;
240 }
241
242 uint32_t
243 ds_xdg_surface_schedule_configure(struct ds_xdg_surface *surface)
244 {
245     struct wl_display *display;
246     struct wl_event_loop *loop;
247
248     display = wl_client_get_display(surface->client->wl_client);
249     loop = wl_display_get_event_loop(display);
250
251     if (!surface->configure_idle) {
252         surface->scheduled_serial = wl_display_next_serial(display);
253         surface->configure_idle = wl_event_loop_add_idle(loop,
254                 surface_send_configure, surface);
255         if (!surface->configure_idle)
256             wl_client_post_no_memory(surface->client->wl_client);
257     }
258
259     return surface->scheduled_serial;
260 }
261
262 void
263 ds_xdg_surface_ping(struct ds_xdg_surface *surface)
264 {
265 }
266
267 static void
268 xdg_surface_handle_surface_destroy(struct wl_listener *listener, void *data)
269 {
270     struct ds_xdg_surface *surface;
271
272     surface = wl_container_of(listener, surface, listener.surface_destroy);
273     destroy_xdg_surface(surface);
274 }
275
276 static void
277 xdg_surface_handle_surface_commit(struct wl_listener *listener, void *data)
278 {
279     struct ds_xdg_surface *surface;
280
281     surface = wl_container_of(listener, surface, listener.surface_commit);
282
283     if (ds_surface_has_buffer(surface->ds_surface) &&
284             !surface->configured) {
285         wl_resource_post_error(surface->resource,
286                 XDG_SURFACE_ERROR_UNCONFIGURED_BUFFER,
287                 "xdg_surface has never been configured");
288         return;
289     }
290
291     if (!ds_surface_get_role(surface->ds_surface)) {
292         wl_resource_post_error(surface->resource,
293                 XDG_SURFACE_ERROR_NOT_CONSTRUCTED,
294                 "xdg_surface must have a role");
295         return;
296     }
297 }
298
299 static void
300 xdg_surface_handle_resource_destroy(struct wl_resource *resource)
301 {
302     struct ds_xdg_surface *surface;
303
304     surface = wl_resource_get_user_data(resource);
305     if (!surface)
306         return;
307
308     destroy_xdg_surface(surface);
309 }
310
311 static void
312 xdg_surface_configure_destroy(struct ds_xdg_surface_configure *configure)
313 {
314     wl_list_remove(&configure->link);
315     free(configure->toplevel_configure);
316     free(configure);
317 }
318
319 static void
320 xdg_surface_handle_destroy(struct wl_client *client,
321         struct wl_resource *resource)
322 {
323     struct ds_xdg_surface *surface;
324
325     surface = wl_resource_get_user_data(resource);
326
327     if (surface->role != DS_XDG_SURFACE_ROLE_NONE) {
328         ds_err("Tried to destroy an xdg_surface before its role object");
329         return;
330     }
331
332     wl_resource_destroy(resource);
333 }
334
335 static void
336 xdg_surface_handle_get_toplevel(struct wl_client *client,
337         struct wl_resource *resource, uint32_t id)
338 {
339     struct ds_xdg_surface *surface;
340
341     surface = wl_resource_get_user_data(resource);
342     create_xdg_toplevel(surface, id);
343 }
344
345 static void
346 xdg_surface_handle_get_popup(struct wl_client *client,
347         struct wl_resource *resource, uint32_t id,
348         struct wl_resource *parent_resource,
349         struct wl_resource *positioner_resource)
350 {
351     struct ds_xdg_surface *surface;
352
353     surface = wl_resource_get_user_data(resource);
354
355     // TODO
356     (void)surface;
357 }
358
359 static void
360 xdg_surface_handle_ack_configure(struct wl_client *client,
361         struct wl_resource *resource, uint32_t serial)
362 {
363     struct ds_xdg_surface *surface;
364
365     surface = wl_resource_get_user_data(resource);
366
367     if (surface->role == DS_XDG_SURFACE_ROLE_NONE) {
368         wl_resource_post_error(surface->resource,
369                 XDG_SURFACE_ERROR_NOT_CONSTRUCTED,
370                 "xdg_surface must have a role");
371         return;
372     }
373
374     bool found = false;
375     struct ds_xdg_surface_configure *configure, *tmp;
376     wl_list_for_each(configure, &surface->configure_list, link) {
377         if (configure->serial == serial) {
378             found = true;
379             break;
380         }
381     }
382
383     if (!found) {
384         wl_resource_post_error(surface->client->resource,
385                 XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE,
386                 "wrong configure serial: %u", serial);
387         return;
388     }
389
390     wl_list_for_each_safe(configure, tmp, &surface->configure_list, link) {
391         if (configure->serial == serial)
392             break;
393
394         wl_signal_emit(&surface->events.ack_configure, configure);
395         xdg_surface_configure_destroy(configure);
396     }
397
398     switch (surface->role) {
399         case DS_XDG_SURFACE_ROLE_NONE:
400             assert(0 && "not reached");
401             break;
402         case DS_XDG_SURFACE_ROLE_TOPLEVEL:
403             // TODO
404             break;
405         case DS_XDG_SURFACE_ROLE_POPUP:
406             break;
407     }
408
409     surface->configured = true;
410     surface->pending.configure_serial = serial;
411
412     wl_signal_emit(&surface->events.ack_configure, configure);
413     xdg_surface_configure_destroy(configure);
414 }
415
416 static void
417 xdg_surface_handle_set_window_geometry(struct wl_client *client,
418         struct wl_resource *resource,
419         int32_t x, int32_t y, int32_t width, int32_t height)
420 {
421     struct ds_xdg_surface *surface;
422
423     surface = wl_resource_get_user_data(resource);
424
425     if (surface->role == DS_XDG_SURFACE_ROLE_NONE) {
426         wl_resource_post_error(surface->resource,
427                 XDG_SURFACE_ERROR_NOT_CONSTRUCTED,
428                 "xdg_surface must have a role");
429         return;
430     }
431
432     if (width <= 0 || height <= 0) {
433         ds_err("Client tried to set invalid geometry");
434         wl_resource_post_error(resource, -1,
435                 "Tried to set invalid xdg_surface geometry");
436         return;
437     }
438
439     surface->pending.geometry.x = x;
440     surface->pending.geometry.y = y;
441     surface->pending.geometry.width = width;
442     surface->pending.geometry.height = height;
443 }
444
445 static const struct xdg_surface_interface xdg_surface_impl =
446 {
447     .destroy = xdg_surface_handle_destroy,
448     .get_toplevel = xdg_surface_handle_get_toplevel,
449     .get_popup = xdg_surface_handle_get_popup,
450     .ack_configure = xdg_surface_handle_ack_configure,
451     .set_window_geometry = xdg_surface_handle_set_window_geometry,
452 };
453
454 static void
455 surface_send_configure(void *user_data)
456 {
457     struct ds_xdg_surface *surface;
458     struct ds_xdg_surface_configure *configure;
459
460     surface = user_data;
461     surface->configure_idle = NULL;
462
463     configure = calloc(1, sizeof *configure);
464     if (!configure) {
465         wl_client_post_no_memory(surface->client->wl_client);
466         return;
467     }
468
469     wl_list_insert(surface->configure_list.prev, &configure->link);
470     configure->serial = surface->scheduled_serial;
471     configure->surface = surface;
472
473     switch (surface->role) {
474         case DS_XDG_SURFACE_ROLE_NONE:
475             assert(0 && "not reached");
476             break;
477         case DS_XDG_SURFACE_ROLE_TOPLEVEL:
478             send_xdg_toplevel_configure(surface, configure);
479             break;
480         case DS_XDG_SURFACE_ROLE_POPUP:
481             break;
482     }
483
484     wl_signal_emit(&surface->events.configure, configure);
485
486     xdg_surface_send_configure(surface->resource, configure->serial);
487 }