screen: add ds_tizen_screen
[platform/core/uifw/libds-tizen.git] / src / screen / screen.c
1 #include <assert.h>
2 #include <stdint.h>
3 #include <stdlib.h>
4 #include <wayland-server.h>
5 #include <wtz-screen-server-protocol.h>
6 #include <libds/log.h>
7
8 #include "util.h"
9 #include "libds-tizen/screen.h"
10
11 #define TIZEN_SCREEN_VERSION 1
12
13 struct ds_tizen_screen
14 {
15     struct wl_global *global;
16
17     struct wl_list clients;
18
19     struct wl_listener destroy;
20
21     struct wl_array capabilities;
22
23     uint32_t splitscreen_capability;
24
25     bool splitscreen_enabled;
26
27     struct {
28         struct wl_signal destroy;
29         struct wl_signal get_splitscreen;
30     } events;
31 };
32
33 struct ds_tizen_screen_client
34 {
35     struct ds_tizen_screen *screen;
36
37     struct wl_resource *resource;
38     struct wl_client *client;
39
40     struct {
41         struct wl_signal destroy;
42     } events;
43
44     struct wl_list link; // ds_tizen_screen::clients
45 };
46
47 struct ds_tizen_splitscreen
48 {
49     struct wl_resource *resource;
50
51     struct ds_tizen_screen_client *screen_client;
52     struct ds_tizen_screen *screen;
53
54     struct {
55         struct wl_signal destroy;
56         struct wl_signal activate;
57         struct wl_signal deactivate;
58     } events;
59 };
60
61 struct ds_tizen_splitscreen_region
62 {
63     struct wl_resource *resource;
64
65     const char *appid;
66
67     struct {
68         struct wl_signal destroy;
69         struct wl_signal assign_appid;
70     } events;
71 };
72
73 static void
74 splitscreen_handle_destroy(struct wl_client *client,
75     struct wl_resource *splitscreen_resource)
76 {
77    wl_resource_destroy(splitscreen_resource);
78 }
79
80 static void
81 splitscreen_handle_activate(struct wl_client *client,
82     struct wl_resource *splitscreen_resource)
83 {
84     struct ds_tizen_splitscreen *splitscreen;
85
86     splitscreen = wl_resource_get_user_data(splitscreen_resource);
87
88     ds_inf("screen_splitscreen:%p activate", splitscreen);
89
90     wl_signal_emit_mutable(&splitscreen->events.activate, splitscreen);
91 }
92
93 static void
94 splitscreen_handle_deactivate(struct wl_client *client,
95     struct wl_resource *splitscreen_resource)
96 {
97     struct ds_tizen_splitscreen *splitscreen;
98
99     splitscreen = wl_resource_get_user_data(splitscreen_resource);
100
101     ds_inf("screen_splitscreen:%p deactivate", splitscreen);
102
103     wl_signal_emit_mutable(&splitscreen->events.deactivate, splitscreen);
104 }
105
106 static const struct wtz_splitscreen_interface splitscreen_impl =
107 {
108     .destroy = splitscreen_handle_destroy,
109     .activate = splitscreen_handle_activate,
110     .deactivate = splitscreen_handle_deactivate,
111 };
112
113 static void
114 _tizen_screen_splitscreen_handle_resource_destroy(struct wl_resource *splitscreen_resource)
115 {
116     struct ds_tizen_splitscreen *splitscreen;
117     struct ds_tizen_screen *screen;
118
119     splitscreen = wl_resource_get_user_data(splitscreen_resource);
120
121     ds_inf("screen_splitscreen:%p destroy", splitscreen);
122
123     wl_signal_emit_mutable(&splitscreen->events.destroy, splitscreen);
124
125     screen = splitscreen->screen;
126     screen->splitscreen_enabled = false; // unset splitscreen resource on a screen
127
128     free(splitscreen);
129 }
130
131 static void
132 screen_handle_get_splitscreen(struct wl_client *client,
133     struct wl_resource *screen_client_resource,
134     uint32_t id)
135 {
136     struct ds_tizen_screen_client *screen_client;
137     struct ds_tizen_splitscreen *splitscreen;
138     struct ds_tizen_screen *screen;
139
140     screen_client = wl_resource_get_user_data(screen_client_resource);
141
142     screen = screen_client->screen;
143
144     if (!screen->splitscreen_capability) {
145         wl_resource_post_error(screen_client_resource, WTZ_SCREEN_ERROR_NOT_SUPPORTED,
146                                "Not Supported");
147         return;
148     }
149
150     // check splitscreen resource on a screen
151     // splitscreen resource is only one per a screen.
152     if (screen->splitscreen_enabled) {
153         wl_resource_post_error(screen_client_resource, WTZ_SCREEN_ERROR_INVALID_PARAMETER,
154                         "Already Occupied");
155         return;
156     }
157
158     splitscreen = calloc(1, sizeof *splitscreen);
159     if (!splitscreen) {
160         wl_client_post_no_memory(client);
161         return;
162     }
163
164     splitscreen->resource = wl_resource_create(client, &wtz_splitscreen_interface,
165             wl_resource_get_version(screen_client_resource), id);
166     if (!splitscreen->resource) {
167         wl_client_post_no_memory(client);
168         free(splitscreen);
169         return;
170     }
171
172     splitscreen->screen_client = screen_client;
173     splitscreen->screen = screen;
174
175     wl_resource_set_implementation(splitscreen->resource, &splitscreen_impl,
176             splitscreen, _tizen_screen_splitscreen_handle_resource_destroy);
177
178     ds_inf("screen_splitscreen:%p create", splitscreen);
179
180     wl_signal_init(&splitscreen->events.destroy);
181     wl_signal_init(&splitscreen->events.activate);
182     wl_signal_init(&splitscreen->events.deactivate);
183
184     screen->splitscreen_enabled = true; // set splitscreen resource on a screen
185
186     wl_signal_emit_mutable(&screen_client->screen->events.get_splitscreen, splitscreen);
187 }
188
189 static void
190 screen_handle_destroy(struct wl_client *wl_client,
191     struct wl_resource *resource)
192 {
193     wl_resource_destroy(resource);
194 }
195
196 static const struct wtz_screen_interface screen_impl =
197 {
198     .destroy = screen_handle_destroy,
199     .get_splitscreen = screen_handle_get_splitscreen,
200 };
201
202 static void
203 _tizen_screen_client_handle_resource_destroy(struct wl_resource *resource)
204 {
205     struct ds_tizen_screen_client *client;
206
207     client = wl_resource_get_user_data(resource);
208
209     ds_inf("_tizen_screen_client_handle_destroy (client:%p)", client);
210
211     wl_list_remove(&client->link);
212     free(client);
213 }
214
215 static void
216 screen_bind(struct wl_client *wl_client, void *data, uint32_t version,
217          uint32_t id)
218 {
219     struct ds_tizen_screen *screen = data;
220     struct ds_tizen_screen_client *screen_client;
221
222     screen_client = calloc(1, sizeof *screen_client);
223     if (screen_client == NULL) {
224         ds_err("calloc() failed. tizen_screen");
225         wl_client_post_no_memory(wl_client);
226         return;
227     }
228
229     ds_inf("tizen_screen_client binds. (screen_client:%p)", screen_client);
230
231     screen_client->screen = screen;
232     screen_client->client = wl_client;
233
234     screen_client->resource = wl_resource_create(wl_client, &wtz_screen_interface,
235             MIN(version, TIZEN_SCREEN_VERSION), id);
236     if (screen_client->resource == NULL) {
237         ds_err("tizen_screen : wl_resource_create() failed.");
238         free(screen_client);
239         wl_client_post_no_memory(wl_client);
240         return;
241     }
242
243     wl_resource_set_implementation(screen_client->resource, &screen_impl, screen_client,
244             _tizen_screen_client_handle_resource_destroy);
245
246    // send the capabilities of the screen
247     wtz_screen_send_capabilities(screen_client->resource, &screen->capabilities);
248
249     wl_signal_init(&screen_client->events.destroy);
250
251     wl_list_insert(&screen->clients, &screen_client->link);
252 }
253
254 static void
255 screen_handle_display_destroy(struct wl_listener *listener, void *data)
256 {
257     struct ds_tizen_screen *screen;
258
259     screen = wl_container_of(listener, screen, destroy);
260
261     ds_inf("Global destroy: screen(%p)", screen);
262
263     wl_signal_emit_mutable(&screen->events.destroy, screen);
264     wl_list_remove(&screen->destroy.link);
265     wl_global_destroy(screen->global);
266     free(screen);
267 }
268
269 WL_EXPORT struct ds_tizen_screen *
270 ds_tizen_screen_create(struct wl_display *display)
271 {
272     struct ds_tizen_screen *screen;
273
274     screen = calloc(1, sizeof *screen);
275     if (!screen) {
276         ds_err("calloc() failed.");
277         return NULL;
278     }
279
280     screen->global = wl_global_create(display, &wtz_screen_interface,
281             TIZEN_SCREEN_VERSION, screen, screen_bind);
282     if (!screen->global) {
283         ds_err("wl_global_create() failed. wtz_screen_interface");
284         free(screen);
285         return NULL;
286     }
287
288     wl_list_init(&screen->clients);
289
290     screen->destroy.notify = screen_handle_display_destroy;
291     wl_display_add_destroy_listener(display, &screen->destroy);
292
293     wl_array_init(&screen->capabilities);
294
295     wl_signal_init(&screen->events.destroy);
296     wl_signal_init(&screen->events.get_splitscreen);
297
298     ds_inf("Global created: tizen_screen(%p)", screen);
299
300     return screen;
301 }
302
303 static void
304 _screen_capability_add(struct wl_array *capabilities, uint32_t cap)
305 {
306    uint32_t *c;
307
308    c = wl_array_add(capabilities, sizeof(*c));
309    if (c)
310      *c = cap;
311    else
312      ds_err("wl_array_add() failed");
313 }
314
315 WL_EXPORT void
316 ds_tizen_screen_add_capability(
317         struct ds_tizen_screen *screen,
318         enum ds_tizen_screen_capability cap)
319 {
320     uint32_t capability;
321
322     ds_inf("screen:%p add capability(%d)", screen, cap);
323
324     if (cap == DS_TIZEN_SCREEN_CAPABILITY_SPLITSCREEN) {
325         capability = WTZ_SCREEN_CAPABILITY_SPLITSCREEN;
326         screen->splitscreen_capability = 1;
327     } else
328         capability = WTZ_SCREEN_CAPABILITY_NONE;
329
330     _screen_capability_add(&screen->capabilities, capability);
331 }
332
333 WL_EXPORT void
334 ds_tizen_screen_add_destroy_listener(
335         struct ds_tizen_screen *screen,
336         struct wl_listener *listener)
337 {
338     wl_signal_add(&screen->events.destroy, listener);
339 }
340
341 WL_EXPORT void
342 ds_tizen_screen_add_get_splitscreen_listener(
343         struct ds_tizen_screen *screen,
344         struct wl_listener *listener)
345 {
346     wl_signal_add(&screen->events.get_splitscreen, listener);
347 }
348
349 WL_EXPORT void
350 ds_tizen_splitscreen_add_destroy_listener(
351         struct ds_tizen_splitscreen *splitscreen,
352         struct wl_listener *listener)
353 {
354     wl_signal_add(&splitscreen->events.destroy, listener);
355 }
356
357 WL_EXPORT void
358 ds_tizen_splitscreen_add_activate_listener(
359         struct ds_tizen_splitscreen *splitscreen,
360         struct wl_listener *listener)
361 {
362     wl_signal_add(&splitscreen->events.activate, listener);
363 }
364
365 WL_EXPORT void
366 ds_tizen_splitscreen_add_deactivate_listener(
367         struct ds_tizen_splitscreen *splitscreen,
368         struct wl_listener *listener)
369 {
370     wl_signal_add(&splitscreen->events.deactivate, listener);
371 }
372
373 static void
374 splitscreen_region_handle_destroy(struct wl_client *client,
375         struct wl_resource *splitscreen_region_resource)
376 {
377   wl_resource_destroy(splitscreen_region_resource);
378 }
379
380 static void
381 splitscreen_region_handle_assign_appid(struct wl_client *client,
382         struct wl_resource *splitscreen_region_resource, const char *appid)
383 {
384     struct ds_tizen_splitscreen_region *splitscreen_region;
385
386     splitscreen_region = wl_resource_get_user_data(splitscreen_region_resource);
387
388     ds_inf("screen_splitscreen_region:%p assign_appid", splitscreen_region);
389
390     splitscreen_region->appid = appid;
391
392     wl_signal_emit_mutable(&splitscreen_region->events.assign_appid, (void *)appid);
393 }
394
395 static const struct wtz_splitscreen_region_interface splitscreen_region_impl =
396 {
397    .destroy = splitscreen_region_handle_destroy,
398    .assign_appid = splitscreen_region_handle_assign_appid,
399 };
400
401 static void
402 _tizen_screen_splitscreen_region_handle_resource_destroy(
403         struct wl_resource *splitscreen_region_resource)
404 {
405     struct ds_tizen_splitscreen_region *splitscreen_region;
406
407     splitscreen_region = wl_resource_get_user_data(splitscreen_region_resource);
408
409     ds_inf("screen_splitscreen_region:%p destroy", splitscreen_region);
410
411     wl_signal_emit_mutable(&splitscreen_region->events.destroy,
412             splitscreen_region);
413
414     free(splitscreen_region);
415 }
416
417 WL_EXPORT struct ds_tizen_splitscreen_region *
418 ds_tizen_splitscreen_region_create(
419         struct ds_tizen_splitscreen *splitscreen,
420         const char *name, int32_t x, int32_t y, uint32_t w, uint32_t h)
421 {
422     struct ds_tizen_splitscreen_region *splitscreen_region;
423     struct ds_tizen_screen_client *screen_client;
424
425     splitscreen_region = calloc(1, sizeof *splitscreen_region);
426     if (!splitscreen_region) {
427         ds_err("calloc() failed.");
428         return NULL;
429     }
430
431     screen_client = splitscreen->screen_client;
432
433     splitscreen_region->resource = wl_resource_create(screen_client->client,
434             &wtz_splitscreen_region_interface,
435             TIZEN_SCREEN_VERSION, 0);
436     if (!splitscreen_region->resource) {
437         ds_err("wl_resource_create() failed. wtz_splitscreen_region_interface");
438         free(splitscreen_region);
439         return NULL;
440     }
441
442     wl_resource_set_implementation(splitscreen_region->resource,
443                 &splitscreen_region_impl, splitscreen_region,
444                 _tizen_screen_splitscreen_region_handle_resource_destroy);
445
446     // send the splitscreen_region resources
447     wtz_splitscreen_send_region(splitscreen->resource, splitscreen_region->resource);
448
449     // send the name of the split_screen_region
450     wtz_splitscreen_region_send_name(splitscreen_region->resource, name);
451
452     // send the geometry of the split_screen_region
453     wtz_splitscreen_region_send_geometry(
454             splitscreen_region->resource, x, y, w, h);
455
456     return splitscreen_region;
457 }
458
459 WL_EXPORT void
460 ds_tizen_splitscreen_region_add_destroy_listener(
461         struct ds_tizen_splitscreen_region *splitscreen_region,
462         struct wl_listener *listener)
463 {
464     wl_signal_add(&splitscreen_region->events.destroy, listener);
465 }
466
467 WL_EXPORT void
468 ds_tizen_splitscreen_region_add_assign_appid_listener(
469         struct ds_tizen_splitscreen_region *splitscreen_region,
470         struct wl_listener *listener)
471 {
472     wl_signal_add(&splitscreen_region->events.assign_appid, listener);
473 }