downstream: Provide IVI-shell extensions again (wl-shell, wl-shell-info, etc)
[profile/ivi/weston-ivi-shell.git] / ivi-shell / ivi-shell-ext.c
1 /*
2  * Copyright (C) 2014 DENSO CORPORATION
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and
5  * its documentation for any purpose is hereby granted without fee, provided
6  * that the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation, and that the name of the copyright holders not be used in
9  * advertising or publicity pertaining to distribution of the software
10  * without specific, written prior permission.  The copyright holders make
11  * no representations about the suitability of this software for any
12  * purpose.  It is provided "as is" without express or implied warranty.
13  *
14  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
15  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
16  * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
17  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
18  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
19  * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21  */
22
23
24 /**
25  * ivi-shell-ext supports a type of shell for standard wayland.
26  *
27  */
28
29 #include <sys/wait.h>
30 #include <unistd.h>
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <linux/input.h>
35
36 #include "ivi-shell-ext.h"
37 #include "ivi-shell.h"
38 #include "compositor.h"
39 #include "ivi-layout-export.h"
40
41 struct ivi_shell_ext;
42
43 struct ping_timer
44 {
45     struct wl_event_source *source;
46     uint32_t serial;
47 };
48
49 struct shell_surface
50 {
51     struct wl_resource *resource;
52
53     struct weston_surface *surface;
54     struct weston_view *view;
55     struct wl_listener surface_destroy_listener;
56
57     struct ivi_shell_ext *shell;
58     struct ping_timer *ping_timer;
59
60     char *class;
61     char *title;
62
63     int32_t width;
64     int32_t height;
65
66     pid_t pid;
67
68     const struct weston_shell_client *client;
69     struct weston_output *output;
70
71     struct wl_list link;
72 };
73
74 struct link_weston_surface
75 {
76     struct wl_listener destroy_listener;
77     struct weston_surface *surface;
78     struct wl_list link;
79 };
80
81 struct ivi_shell_ext
82 {
83     struct wl_listener destroy_listener;
84     struct wl_list list_weston_surface;
85     struct wl_list list_shell_surface;
86 };
87
88 /* ------------------------------------------------------------------------- */
89 /* common functions                                                          */
90 /* ------------------------------------------------------------------------- */
91
92 static struct ivi_shell_ext *
93 get_instance(void)
94 {
95     static struct ivi_shell_ext  *shell = NULL;
96
97     if (NULL == shell) {
98         shell = calloc(1, sizeof(*shell));
99         wl_list_init(&shell->list_shell_surface);
100         wl_list_init(&shell->list_weston_surface);
101     }
102
103     return shell;
104 }
105
106 static void
107 configure(struct weston_view *view, float x, float y)
108 {
109     if (view != NULL) {
110         weston_view_set_position(view, x, y);
111         weston_view_update_transform(view);
112     }
113 }
114
115 /**
116  * Implementation of wl_shell
117  */
118
119 static void
120 shell_surface_configure(struct weston_surface *, int32_t, int32_t);
121
122 static struct shell_surface *
123 get_shell_surface(struct weston_surface *surface)
124 {
125     if (surface->configure == shell_surface_configure) {
126         return surface->configure_private;
127     } else {
128         return NULL;
129     }
130 }
131
132 static void
133 ping_timer_destroy(struct shell_surface *shsurf)
134 {
135     if (!shsurf || !shsurf->ping_timer) {
136         return;
137     }
138
139     if (shsurf->ping_timer->source) {
140         wl_event_source_remove(shsurf->ping_timer->source);
141     }
142
143     free(shsurf->ping_timer);
144     shsurf->ping_timer = NULL;
145 }
146
147 static void
148 destroy_shell_surface(struct shell_surface *shsurf)
149 {
150     wl_list_remove(&shsurf->surface_destroy_listener.link);
151
152 #if 0
153     shsurf->surface->configure = NULL;
154 #endif
155
156     ping_timer_destroy(shsurf);
157
158     free(shsurf->title);
159     shsurf->title = NULL;
160
161     wl_list_remove(&shsurf->link);
162     free(shsurf);
163     shsurf = NULL;
164 }
165
166 static void
167 shell_handle_surface_destroy(struct wl_listener *listener, void *data)
168 {
169     struct shell_surface *shsurf = NULL;
170
171     shsurf = container_of(listener,
172                           struct shell_surface,
173                           surface_destroy_listener);
174
175     if (wl_resource_get_client(shsurf->resource)) {
176         wl_resource_destroy(shsurf->resource);
177     } else {
178         wl_resource_destroy(shsurf->resource);
179         destroy_shell_surface(shsurf);
180     }
181 }
182
183 static void
184 shell_surface_configure(struct weston_surface *es,
185                         int32_t sx, int32_t sy)
186 {
187     struct shell_surface *shsurf = get_shell_surface(es);
188     float from_x = 0.0f;
189     float from_y = 0.0f;
190     float to_x = 0.0f;
191     float to_y = 0.0f;
192
193     if ((es == NULL) || (shsurf == NULL)) {
194         return;
195     }
196
197     if (shsurf->width != es->width || shsurf->height != es->height) {
198
199         shsurf->width = es->width;
200         shsurf->height = es->height;
201
202         weston_view_to_global_float(shsurf->view, 0, 0, &from_x, &from_y);
203         weston_view_to_global_float(shsurf->view, sx, sy, &to_x, &to_y);
204         configure(shsurf->view,
205                   shsurf->view->geometry.x + to_x - from_x,
206                   shsurf->view->geometry.y + to_y - from_y);
207     }
208 }
209
210 static void
211 send_configure(struct weston_surface *surface,
212                /* uint32_t edges, */ int32_t width, int32_t height)
213 {
214     struct shell_surface *shsurf = get_shell_surface(surface);
215
216     wl_shell_surface_send_configure(shsurf->resource,
217                                     0 /* edges */, width, height);
218 }
219
220 static const struct weston_shell_client shell_client = {
221     send_configure
222 };
223
224 static void
225 shell_destroy_shell_surface(struct wl_resource *resource)
226 {
227     struct shell_surface *shsurf = wl_resource_get_user_data(resource);
228
229     destroy_shell_surface(shsurf);
230 }
231
232 static void
233 shell_surface_pong(struct wl_client *client,
234                    struct wl_resource *resource, uint32_t serial)
235 {
236     struct shell_surface *shsurf = wl_resource_get_user_data(resource);
237
238     if (shsurf->ping_timer == NULL) {
239         return;
240     }
241
242     if (shsurf->ping_timer->serial == serial) {
243         ping_timer_destroy(shsurf);
244     }
245 }
246
247 static void
248 shell_surface_move(struct wl_client *client, struct wl_resource *resource,
249                    struct wl_resource *seat_resource, uint32_t serial)
250 {
251     /* not supported */
252     (void)client;
253     (void)resource;
254     (void)seat_resource;
255     (void)serial;
256 }
257
258 static void
259 shell_surface_resize(struct wl_client *client, struct wl_resource *resource,
260                      struct wl_resource *seat_resource, uint32_t serial,
261                      uint32_t edges)
262 {
263     /* not supported */
264     (void)client;
265     (void)resource;
266     (void)seat_resource;
267     (void)serial;
268     (void)edges;
269 }
270
271 static void
272 shell_surface_set_toplevel(struct wl_client *client,
273                            struct wl_resource *resource)
274 {
275     /* not supported */
276     (void)client;
277     (void)resource;
278 }
279
280 static void
281 shell_surface_set_transient(struct wl_client *client,
282                             struct wl_resource *resource,
283                             struct wl_resource *parent_resource,
284                             int x, int y, uint32_t flags)
285 {
286     /* not supported */
287     (void)client;
288     (void)resource;
289     (void)parent_resource;
290     (void)x;
291     (void)y;
292     (void)flags;
293 }
294
295 static void
296 shell_surface_set_fullscreen(struct wl_client *client,
297                              struct wl_resource *resource,
298                              uint32_t method,
299                              uint32_t framerate,
300                              struct wl_resource *output_resource)
301 {
302     /* not supported */
303     (void)client;
304     (void)resource;
305     (void)method;
306     (void)framerate;
307     (void)output_resource;
308 }
309
310 static void
311 shell_surface_set_popup(struct wl_client *client,
312                         struct wl_resource *resource,
313                         struct wl_resource *seat_resource,
314                         uint32_t serial,
315                         struct wl_resource *parent_resource,
316                         int32_t x, int32_t y, uint32_t flags)
317 {
318     /* not supported */
319     (void)client;
320     (void)resource;
321     (void)seat_resource;
322     (void)serial;
323     (void)parent_resource;
324     (void)x;
325     (void)y;
326     (void)flags;
327 }
328
329 static void
330 shell_surface_set_maximized(struct wl_client *client,
331                             struct wl_resource *resource,
332                             struct wl_resource *output_resource)
333 {
334     /* not supported */
335     (void)client;
336     (void)resource;
337     (void)output_resource;
338 }
339
340 static void
341 shell_surface_set_title(struct wl_client *client,
342                         struct wl_resource *resource, const char *title)
343 {
344     struct shell_surface *shsurf = wl_resource_get_user_data(resource);
345
346     free(shsurf->title);
347     if (title != NULL) {
348         shsurf->title = strdup(title);
349     } else {
350         shsurf->title = strdup("");
351     }
352
353     send_wl_shell_info(shsurf->pid, shsurf->title);
354 }
355
356 static void
357 shell_surface_set_class(struct wl_client *client,
358                         struct wl_resource *resource, const char *class)
359 {
360     struct shell_surface *shsurf = wl_resource_get_user_data(resource);
361
362     free(shsurf->class);
363     shsurf->class = strdup(class);
364 }
365
366 static const struct wl_shell_surface_interface shell_surface_implementation = {
367     shell_surface_pong,
368     shell_surface_move,
369     shell_surface_resize,
370     shell_surface_set_toplevel,
371     shell_surface_set_transient,
372     shell_surface_set_fullscreen,
373     shell_surface_set_popup,
374     shell_surface_set_maximized,
375     shell_surface_set_title,
376     shell_surface_set_class
377 };
378
379 static void
380 shell_weston_surface_destroy(struct wl_listener *listener, void *data)
381 {
382     struct link_weston_surface *lsurf = NULL;
383
384     lsurf = container_of(listener,
385                          struct link_weston_surface,
386                          destroy_listener);
387
388     wl_list_remove(&lsurf->link);
389     free(lsurf);
390     lsurf = NULL;
391 }
392
393 static struct shell_surface *
394 create_shell_surface(struct ivi_shell_ext *shell,
395                      struct wl_client *client,
396                      uint32_t id_wl_shell,
397                      struct weston_surface *surface,
398                      const struct weston_shell_client *shell_client)
399 {
400     struct shell_surface *shsurf = NULL;
401
402 #if 0
403     if (surface->configure) {
404         weston_log("surface->configure already set\n");
405         return NULL;
406     }
407 #endif
408
409     shsurf = calloc(1, sizeof *shsurf);
410     if (shsurf == NULL) {
411         weston_log("fails to allocate memory\n");
412         return NULL;
413     }
414
415 #if 0
416     surface->configure = shell_surface_configure;
417     surface->configure_private = shsurf;
418 #endif
419
420     shsurf->shell = shell;
421     shsurf->surface = surface;
422     shsurf->ping_timer = NULL;
423     shsurf->title = strdup("");
424
425     /* init link so its safe to always remove it in destroy_shell_surface */
426     wl_list_init(&shsurf->link);
427
428     shsurf->client = shell_client;
429     shsurf->resource = wl_resource_create(client, &wl_shell_surface_interface,
430                                           1, id_wl_shell);
431
432     wl_resource_set_implementation(shsurf->resource,
433                                    &shell_surface_implementation,
434                                    shsurf, shell_destroy_shell_surface);
435
436     shsurf->surface_destroy_listener.notify = shell_handle_surface_destroy;
437     wl_resource_add_destroy_listener(surface->resource,
438                                      &shsurf->surface_destroy_listener);
439
440     return shsurf;
441 }
442
443 static void
444 create_link_weston_surface(struct ivi_shell_ext *shell,
445                            struct weston_surface *surface)
446 {
447     struct link_weston_surface *lsurf = NULL;
448
449     lsurf = calloc(1, sizeof *lsurf);
450     if (lsurf == NULL) {
451         weston_log("fails to allocate memory\n");
452         return;
453     }
454
455     lsurf->surface = surface;
456
457     wl_list_init(&lsurf->link);
458     wl_list_insert(&shell->list_weston_surface, &lsurf->link);
459
460     lsurf->destroy_listener.notify = shell_weston_surface_destroy;
461     wl_resource_add_destroy_listener(surface->resource,
462                                      &lsurf->destroy_listener);
463 }
464
465 static void
466 shell_get_shell_surface(struct wl_client   *client,
467                         struct wl_resource *resource,
468                         uint32_t id_wl_shell,
469                         struct wl_resource *surface_resource)
470 {
471     struct ivi_shell_ext *shell = wl_resource_get_user_data(resource);
472     struct weston_surface *surface = NULL;
473     struct shell_surface  *shsurf  = NULL;
474     pid_t pid = 0;
475     uid_t uid = 0;
476     gid_t gid = 0;
477
478     surface = wl_resource_get_user_data(surface_resource);
479     if (get_shell_surface(surface)) {
480         wl_resource_post_error(surface_resource,
481                                WL_DISPLAY_ERROR_INVALID_OBJECT,
482                                "get_shell_surface already requested");
483         return;
484     }
485
486     shsurf = create_shell_surface(shell, client, id_wl_shell, surface, &shell_client);
487     if (!shsurf) {
488         wl_resource_post_error(surface_resource,
489                                WL_DISPLAY_ERROR_INVALID_OBJECT,
490                                "surface->configure already set");
491         return;
492     }
493
494     create_link_weston_surface(shell, surface);
495
496     wl_client_get_credentials(client, &pid, &uid, &gid);
497
498     shsurf->pid = pid;
499     wl_list_insert(&shell->list_shell_surface, &shsurf->link);
500
501     send_wl_shell_info(shsurf->pid, shsurf->title);
502 }
503
504 static const struct wl_shell_interface shell_implementation = {
505     shell_get_shell_surface
506 };
507
508 static void
509 bind_shell(struct wl_client *client, void *data,
510            uint32_t version, uint32_t id)
511 {
512     struct ivi_shell_ext *shell = data;
513     struct wl_resource *resource = NULL;
514
515     resource = wl_resource_create(client, &wl_shell_interface, 1, id);
516     wl_resource_set_implementation(resource,
517                                    &shell_implementation,
518                                    shell, NULL);
519 }
520
521 /**
522  * Initialization/destruction method of ivi-shell-ext
523  */
524 static void
525 shell_ext_destroy(struct wl_listener *listener, void *data)
526 {
527     struct ivi_shell_ext *shell = NULL;
528
529     shell = container_of(listener, struct ivi_shell_ext, destroy_listener);
530
531     free(shell);
532     shell = NULL;
533 }
534
535 /* ------------------------------------------------------------------------- */
536 /* export functions                                                          */
537 /* ------------------------------------------------------------------------- */
538 WL_EXPORT void
539 ivi_shell_get_shell_surfaces(struct wl_array *surfaces)
540 {
541     struct ivi_shell_ext *shell = get_instance();
542     wl_array_init(surfaces);
543
544     struct shell_surface *surface = NULL;
545     wl_list_for_each(surface, &shell->list_shell_surface, link) {
546         struct shell_surface **add = wl_array_add(surfaces, sizeof(surface));
547         *add = surface;
548     }
549 }
550
551 WL_EXPORT uint32_t
552 shell_surface_get_process_id(struct shell_surface *surface)
553 {
554     return surface->pid;
555 }
556
557 WL_EXPORT char*
558 shell_surface_get_title(struct shell_surface* surface)
559 {
560     return surface->title;
561 }
562
563 WL_EXPORT struct weston_surface *
564 shell_surface_get_surface(struct shell_surface* surface)
565 {
566     return surface->surface;
567 }
568
569 /**
570  * Initialization of ivi-shell-ext. wl_shell is supported here.
571  *
572  */
573
574 WL_EXPORT int
575 init_ivi_shell_ext(struct weston_compositor *ec,
576                    int *argc, char *argv[])
577 {
578     struct ivi_shell_ext *shell = get_instance();
579
580     wl_list_init(&shell->list_weston_surface);
581     wl_list_init(&shell->list_shell_surface);
582
583     shell->destroy_listener.notify = shell_ext_destroy;
584     wl_signal_add(&ec->destroy_signal, &shell->destroy_listener);
585
586     if (wl_global_create(ec->wl_display, &wl_shell_interface, 1,
587                          shell, bind_shell) == NULL) {
588         return -1;
589     }
590
591     return 0;
592 }