downstream: terminal: destroy display at the end.
[profile/ivi/weston-ivi-shell.git] / ivi-shell / ivi-shell.c
1 /*
2  * Copyright (C) 2013 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  * ivi-shell supports a type of shell for In-Vehicle Infotainment system.
25  * In-Vehicle Infotainment system traditionally manages surfaces with global
26  * identification. A protocol, ivi_application, supports such a feature
27  * by implementing a request, ivi_application::surface_creation defined in
28  * ivi_application.xml.
29  *
30  *  The ivi-shell explicitly loads a module to add business logic like how to
31  *  layout surfaces by using internal ivi-layout APIs.
32  */
33 #include "config.h"
34
35 #include <sys/wait.h>
36 #include <unistd.h>
37 #include <stdlib.h>
38 #include <stdio.h>
39 #include <string.h>
40 #include <linux/input.h>
41 #include <dlfcn.h>
42 #include <limits.h>
43 #include <assert.h>
44
45 #include <wayland-server.h>
46
47 #include "ivi-shell.h"
48 #include "ivi-shell-ext.h"
49 #include "ivi-application-server-protocol.h"
50 #include "ivi-layout-private.h"
51
52 #include "../shared/os-compatibility.h"
53
54 /* Representation of ivi_surface protocol object. */
55 struct ivi_shell_surface
56 {
57         struct wl_resource* resource;
58         struct ivi_shell *shell;
59         struct ivi_layout_surface *layout_surface;
60
61         struct weston_surface *surface;
62         struct wl_listener surface_destroy_listener;
63
64         uint32_t id_surface;
65
66         int32_t width;
67         int32_t height;
68
69         struct wl_list link;
70
71         struct wl_listener configured_listener;
72 };
73
74 struct ivi_shell_setting
75 {
76         char *ivi_module;
77 };
78
79 static struct ivi_shell *
80 get_shell_instance(void)
81 {
82     static struct ivi_shell *shell = NULL;
83
84     if (NULL == shell) {
85         shell = calloc(1, sizeof(*shell));
86     }
87
88     return shell;
89 }
90
91 /*
92  * Implementation of ivi_surface
93  */
94
95 static void
96 surface_configure_notify(struct wl_listener *listener, void *data)
97 {
98         struct ivi_layout_surface *layout_surf =
99                 (struct ivi_layout_surface *)data;
100
101         struct ivi_shell_surface *shell_surf =
102                 container_of(listener,
103                              struct ivi_shell_surface,
104                              configured_listener);
105
106         int32_t dest_width = 0;
107         int32_t dest_height = 0;
108         shell_surf->shell->ivi_layout->get_surface_dimension(layout_surf,
109                                           &dest_width, &dest_height);
110
111         if (shell_surf->resource)
112                 ivi_surface_send_configure(shell_surf->resource,
113                                            dest_width, dest_height);
114 }
115
116 static void
117 ivi_shell_surface_configure(struct weston_surface *, int32_t, int32_t);
118
119 static struct ivi_shell_surface *
120 get_ivi_shell_surface(struct weston_surface *surface)
121 {
122         if (surface->configure == ivi_shell_surface_configure)
123                 return surface->configure_private;
124
125         return NULL;
126 }
127
128 static void
129 ivi_shell_surface_configure(struct weston_surface *surface,
130                             int32_t sx, int32_t sy)
131 {
132         struct ivi_shell_surface *ivisurf = get_ivi_shell_surface(surface);
133         struct weston_view *view;
134         float from_x;
135         float from_y;
136         float to_x;
137         float to_y;
138
139         if (surface->width == 0 || surface->height == 0 || ivisurf == NULL)
140                 return;
141
142         view = ivisurf->shell->ivi_layout->get_weston_view(ivisurf->layout_surface);
143         if (view == NULL)
144                 return;
145
146         if (ivisurf->width != surface->width ||
147             ivisurf->height != surface->height) {
148                 ivisurf->width  = surface->width;
149                 ivisurf->height = surface->height;
150
151                 weston_view_to_global_float(view, 0, 0, &from_x, &from_y);
152                 weston_view_to_global_float(view, sx, sy, &to_x, &to_y);
153
154                 weston_view_set_position(view,
155                                          view->geometry.x + to_x - from_x,
156                                          view->geometry.y + to_y - from_y);
157                 weston_view_update_transform(view);
158
159                 ivisurf->shell->ivi_layout->surface_configure(ivisurf->layout_surface,
160                                               surface->width, surface->height);
161         }
162 }
163
164 /*
165  * The ivi_surface wl_resource destructor.
166  *
167  * Gets called via ivi_surface.destroy request or automatic wl_client clean-up.
168  */
169 static void
170 shell_destroy_shell_surface(struct wl_resource *resource)
171 {
172         struct ivi_shell_surface *ivisurf = wl_resource_get_user_data(resource);
173         if (ivisurf != NULL) {
174                 ivisurf->resource = NULL;
175         }
176 }
177
178 /* Gets called through the weston_surface destroy signal. */
179 static void
180 shell_handle_surface_destroy(struct wl_listener *listener, void *data)
181 {
182         struct ivi_shell_surface *ivisurf =
183                         container_of(listener, struct ivi_shell_surface,
184                                      surface_destroy_listener);
185
186         assert(ivisurf != NULL);
187
188         if (ivisurf->surface!=NULL) {
189                 ivisurf->surface->configure = NULL;
190                 ivisurf->surface->configure_private = NULL;
191                 ivisurf->surface = NULL;
192         }
193
194         wl_list_remove(&ivisurf->surface_destroy_listener.link);
195         wl_list_remove(&ivisurf->link);
196
197         if (ivisurf->resource != NULL) {
198                 wl_resource_set_user_data(ivisurf->resource, NULL);
199                 ivisurf->resource = NULL;
200         }
201         free(ivisurf);
202
203 }
204
205 /* Gets called, when a client sends ivi_surface.destroy request. */
206 static void
207 surface_destroy(struct wl_client *client, struct wl_resource *resource)
208 {
209         /*
210          * Fires the wl_resource destroy signal, and then calls
211          * ivi_surface wl_resource destructor: shell_destroy_shell_surface()
212          */
213         wl_resource_destroy(resource);
214 }
215
216 static const struct ivi_surface_interface surface_implementation = {
217         surface_destroy,
218 };
219
220 static struct shell_surface*
221 create_shell_surface(void *shell,
222                      struct weston_surface *weston_surface,
223                      const struct weston_shell_client *client)
224 {
225         struct ivi_shell_surface *ivisurf;
226         struct ivi_layout_surface *layout_surface;
227         static uint32_t id_surface = 0xffffffff; // FIXME
228
229         ivisurf = zalloc(sizeof *ivisurf);
230         if (ivisurf == NULL) {
231         weston_log("no memory\n");
232                 return NULL;
233         }
234
235         layout_surface = ((struct ivi_shell*)shell)
236                 ->ivi_layout->surface_create(weston_surface, id_surface);
237
238         wl_list_init(&ivisurf->link);
239         wl_list_insert(&((struct ivi_shell*)shell)->ivi_surface_list, &ivisurf->link);
240
241         ivisurf->shell = shell;
242         ivisurf->id_surface = id_surface;
243
244         ivisurf->resource = NULL;
245         ivisurf->width = 0;
246         ivisurf->height = 0;
247         ivisurf->layout_surface = layout_surface;
248         ivisurf->configured_listener.notify = surface_configure_notify;
249         ((struct ivi_shell*)shell)->ivi_layout->add_surface_configured_listener(
250                                         layout_surface, &ivisurf->configured_listener);
251
252         ivisurf->surface = weston_surface;
253
254         weston_surface->configure = ivi_shell_surface_configure;
255         weston_surface->configure_private = ivisurf;
256
257         id_surface--;
258
259         return NULL;
260 }
261
262 static struct weston_view*
263 get_primary_view(void *shell,
264                  struct shell_surface *shsurf)
265 {
266         return NULL;
267 }
268
269 static void
270 set_toplevel(struct shell_surface *shsurf)
271 {
272         /*
273          * non support for ivi-shell
274          * this shall not be done by client request.
275          */
276 }
277
278 static void
279 set_transient(struct shell_surface *shsurf,
280               struct weston_surface *parent,
281               int x, int y, uint32_t flags)
282 {
283         /*
284          * non support for ivi-shell
285          * this shall not be done by client request.
286          */
287 }
288
289 static void
290 set_fullscreen(struct shell_surface *shsurf,
291                uint32_t method,
292                uint32_t framerate,
293                struct weston_output *output)
294 {
295         /*
296          * non support for ivi-shell
297          * this shall not be done by client request.
298          */
299 }
300
301 static void
302 set_xwayland(struct shell_surface *shsurf,
303              int x, int y, uint32_t flags)
304 {
305         /*
306          * non support for ivi-shell
307          * this shall not be done by client request.
308          */
309 }
310
311 static int
312 move(struct shell_surface *shsurf, struct weston_seat *ws)
313 {
314         /*
315          * non support for ivi-shell
316          * this shall not be done by client request.
317          */
318
319         return 0; // success
320 }
321
322 static int
323 resize(struct shell_surface *shsurf, struct weston_seat *ws, uint32_t edges)
324 {
325         /*
326          * non support for ivi-shell
327          * this shall not be done by client request.
328          */
329
330         return 0; // success
331 }
332
333 static void
334 set_title(struct shell_surface *shsurf, const char *title)
335 {
336         /*
337          * title is not supported by ivi-shell
338          */
339 }
340
341 static void
342 set_window_geometry(struct shell_surface *shsurf,
343                     int32_t x, int32_t y, int32_t width, int32_t height)
344 {
345         /*
346          * non support for ivi-shell
347          * this shall not be done by client request.
348          */
349 }
350
351 /**
352  * Request handler for ivi_application.surface_create.
353  *
354  * Creates an ivi_surface protocol object associated with the given wl_surface.
355  * ivi_surface protocol object is represented by struct ivi_shell_surface.
356  *
357  * \param client The client.
358  * \param resource The ivi_application protocol object.
359  * \param id_surface The IVI surface ID.
360  * \param surface_resource The wl_surface protocol object.
361  * \param id The protocol object id for the new ivi_surface protocol object.
362  *
363  * The wl_surface is given the ivi_surface role and associated with a unique
364  * IVI ID which is used to identify the surface in a controller
365  * (window manager).
366  */
367 static void
368 application_surface_create(struct wl_client *client,
369                            struct wl_resource *resource,
370                            uint32_t id_surface,
371                            struct wl_resource *surface_resource,
372                            uint32_t id)
373 {
374         struct ivi_shell *shell = wl_resource_get_user_data(resource);
375         struct ivi_shell_surface *ivisurf;
376         struct ivi_layout_surface *layout_surface;
377         struct weston_surface *weston_surface =
378                 wl_resource_get_user_data(surface_resource);
379         struct wl_resource *res;
380
381         if (weston_surface->configure) {
382                 wl_resource_post_error(resource,
383                                        IVI_APPLICATION_ERROR_ROLE,
384                                        "surface->configure already "
385                                        "set");
386                 return;
387         }
388
389         layout_surface = shell->ivi_layout->surface_create(weston_surface,
390                                                     id_surface);
391
392         /* check if id_ivi is already used for wl_surface*/
393         if (layout_surface == NULL){
394                 wl_resource_post_error(resource,
395                                        IVI_APPLICATION_ERROR_IVI_ID,
396                                        "surface_id is already assigned "
397                                        "by another app");
398                 return;
399         }
400
401         ivisurf = zalloc(sizeof *ivisurf);
402         if (ivisurf == NULL) {
403                 wl_resource_post_no_memory(resource);
404                 return;
405         }
406
407         wl_list_init(&ivisurf->link);
408         wl_list_insert(&shell->ivi_surface_list, &ivisurf->link);
409
410         ivisurf->shell = shell;
411         ivisurf->id_surface = id_surface;
412
413         ivisurf->width = 0;
414         ivisurf->height = 0;
415         ivisurf->layout_surface = layout_surface;
416         ivisurf->configured_listener.notify = surface_configure_notify;
417         ivisurf->shell->ivi_layout->add_surface_configured_listener(layout_surface,
418                                                 &ivisurf->configured_listener);
419
420         /*
421          * The following code relies on wl_surface destruction triggering
422          * immediateweston_surface destruction
423          */
424         ivisurf->surface_destroy_listener.notify = shell_handle_surface_destroy;
425         wl_signal_add(&weston_surface->destroy_signal,
426                       &ivisurf->surface_destroy_listener);
427
428         ivisurf->surface = weston_surface;
429
430         weston_surface->configure = ivi_shell_surface_configure;
431         weston_surface->configure_private = ivisurf;
432
433         res = wl_resource_create(client, &ivi_surface_interface, 1, id);
434         if (res == NULL) {
435                 wl_client_post_no_memory(client);
436                 return;
437         }
438
439         ivisurf->resource = res;
440
441         wl_resource_set_implementation(res, &surface_implementation,
442                                        ivisurf, shell_destroy_shell_surface);
443
444         ivi_shell_surface_configure(weston_surface, 0,0);
445 }
446
447 static const struct ivi_application_interface application_implementation = {
448         application_surface_create
449 };
450
451 /*
452  * Handle wl_registry.bind of ivi_application global singleton.
453  */
454 static void
455 unbind_resource(struct wl_resource *resource)
456 {
457     wl_list_remove(wl_resource_get_link(resource));
458 }
459
460 static void
461 bind_ivi_application(struct wl_client *client,
462                      void *data, uint32_t version, uint32_t id)
463 {
464         struct ivi_shell *shell = data;
465         struct wl_resource *resource;
466
467         resource = wl_resource_create(client, &ivi_application_interface,
468                                       1, id);
469
470         wl_resource_set_implementation(resource,
471                                        &application_implementation,
472                                        shell, unbind_resource);
473
474         wl_list_insert(&shell->client_list, wl_resource_get_link(resource));
475 }
476
477 struct weston_view *
478 get_default_view(struct weston_surface *surface)
479 {
480         struct ivi_shell_surface *shsurf;
481         struct weston_view *view;
482
483         if (!surface || wl_list_empty(&surface->views))
484                 return NULL;
485
486         shsurf = get_ivi_shell_surface(surface);
487         if (shsurf && shsurf->layout_surface) {
488                 view = shsurf->shell->ivi_layout->get_weston_view(shsurf->layout_surface);
489                 if (view)
490                         return view;
491         }
492
493         wl_list_for_each(view, &surface->views, surface_link) {
494                 if (weston_view_is_mapped(view))
495                         return view;
496         }
497
498         return container_of(surface->views.next,
499                             struct weston_view, surface_link);
500 }
501
502 /*
503  * Called through the compositor's destroy signal.
504  */
505 static void
506 shell_destroy(struct wl_listener *listener, void *data)
507 {
508         struct ivi_shell *shell =
509                 container_of(listener, struct ivi_shell, destroy_listener);
510         struct ivi_shell_surface *ivisurf, *next;
511
512         input_panel_destroy(shell);
513
514         wl_list_for_each_safe(ivisurf, next, &shell->ivi_surface_list, link) {
515                 wl_list_remove(&ivisurf->link);
516                 free(ivisurf);
517         }
518
519         free(shell);
520 }
521
522 static void
523 init_ivi_shell(struct weston_compositor *compositor, struct ivi_shell *shell)
524 {
525         shell->compositor = compositor;
526
527         wl_list_init(&shell->ivi_surface_list);
528         wl_list_init(&shell->client_list);
529
530         weston_layer_init(&shell->input_panel_layer, NULL);
531
532         compositor->shell_interface.shell = shell;
533         compositor->shell_interface.create_shell_surface = create_shell_surface;
534         compositor->shell_interface.get_primary_view = get_primary_view;
535         compositor->shell_interface.set_toplevel = set_toplevel;
536         compositor->shell_interface.set_transient = set_transient;
537         compositor->shell_interface.set_fullscreen = set_fullscreen;
538         compositor->shell_interface.set_xwayland = set_xwayland;
539         compositor->shell_interface.move = move;
540         compositor->shell_interface.resize = resize;
541         compositor->shell_interface.set_title = set_title;
542         compositor->shell_interface.set_window_geometry = set_window_geometry;
543 }
544
545 static int
546 ivi_shell_setting_create(struct ivi_shell_setting *dest,
547                          struct weston_compositor *compositor)
548 {
549         int result = 0;
550         struct weston_config *config = compositor->config;
551         struct weston_config_section *section;
552
553         if (NULL == dest)
554                 return -1;
555
556         section = weston_config_get_section(config, "ivi-shell", NULL, NULL);
557
558         if (weston_config_section_get_string(
559                 section, "ivi-module", &dest->ivi_module, NULL) != 0)
560         {
561                 result = -1;
562         }
563
564         return result;
565 }
566
567 WL_EXPORT void
568 send_wl_shell_info(int32_t pid, const char *window_title, struct weston_surface *surface)
569 {
570         struct ivi_shell *shell = get_shell_instance();
571         struct wl_resource *resource;
572         uint32_t id_surface = 0;
573         struct ivi_shell_surface *ivisurf;
574
575         wl_list_for_each(ivisurf, &shell->ivi_surface_list, link) {
576                 if (surface == ivisurf->surface) {
577                         id_surface = ivisurf->id_surface;
578                         break;
579                 }
580         }
581
582         wl_resource_for_each(resource, &shell->client_list) {
583                 ivi_application_send_wl_shell_info(resource, pid, window_title, id_surface);
584         }
585 }
586
587 WL_EXPORT void
588 get_wl_shell_info(struct ivi_layout_surface *layout_surface, uint32_t id_surface,
589                   int32_t *pid_ret, const char **window_title_ret)
590 {
591         struct ivi_shell *shell = get_shell_instance();
592         struct ivi_layout_interface *ivi_layout = shell->ivi_layout;
593         struct weston_surface *surface;
594         struct wl_array shsurflist;
595         struct shell_surface **shsurface;
596         pid_t pid;
597         uid_t uid;
598         gid_t gid;
599
600         *pid_ret = 0;
601         *window_title_ret = "";
602
603         if (layout_surface != NULL && id_surface > 0) {
604                 surface = ivi_layout->get_weston_surface(layout_surface);
605
606                 if (surface != NULL && surface->resource != NULL && surface->resource->client != NULL) {
607                         wl_client_get_credentials(surface->resource->client, &pid, &uid, &gid);
608
609                         *pid_ret = pid;
610
611                         ivi_shell_get_shell_surfaces(&shsurflist);
612
613                         wl_array_for_each(shsurface, &shsurflist) {
614                                 if (surface == shell_surface_get_surface(*shsurface)) {
615                                         *window_title_ret = shell_surface_get_title(*shsurface);
616                                         break;
617                                 }
618                         }
619
620                         wl_array_release(&shsurflist);
621                 }
622         }
623 }
624
625 static void
626 click_to_activate_binding(struct weston_seat *seat, uint32_t time, uint32_t button,
627                           void *data)
628 {
629         if (seat->pointer->grab != &seat->pointer->default_grab) {
630                 return;
631         }
632         if (seat->pointer->focus == NULL) {
633                 return;
634         }
635
636         weston_surface_activate(seat->pointer->focus->surface, seat);
637 }
638
639 /*
640  * Initialization of ivi-shell.
641  */
642 static int
643 ivi_load_modules(struct weston_compositor *compositor, const char *modules,
644                  int *argc, char *argv[])
645 {
646         const char *p, *end;
647         char buffer[256];
648         int (*module_init)(struct weston_compositor *compositor,
649                            int *argc, char *argv[]);
650
651         if (modules == NULL)
652                 return 0;
653
654         p = modules;
655         while (*p) {
656                 end = strchrnul(p, ',');
657                 snprintf(buffer, sizeof buffer, "%.*s", (int)(end - p), p);
658
659                 module_init = weston_load_module(buffer, "module_init");
660                 if (module_init)
661                         module_init(compositor, argc, argv);
662
663                 p = end;
664                 while (*p == ',')
665                         p++;
666         }
667
668         return 0;
669 }
670
671 WL_EXPORT int
672 module_init(struct weston_compositor *compositor,
673             int *argc, char *argv[])
674 {
675         char ivi_layout_path[PATH_MAX];
676         void *module;
677         struct ivi_shell_setting setting = { };
678
679         struct ivi_shell *shell = get_shell_instance();
680         if (shell == NULL)
681                 return -1;
682
683         init_ivi_shell(compositor, shell);
684
685         shell->destroy_listener.notify = shell_destroy;
686         wl_signal_add(&compositor->destroy_signal, &shell->destroy_listener);
687
688         if (input_panel_setup(shell) < 0)
689                 return -1;
690
691         if (wl_global_create(compositor->wl_display,
692                              &ivi_application_interface, 1,
693                              shell, bind_ivi_application) == NULL)
694                 return -1;
695
696         if (ivi_shell_setting_create(&setting, compositor) != 0)
697                 return -1;
698
699         /*
700          * load module:ivi-layout
701          * ivi_layout_interface is referred by ivi-shell to use ivi-layout.
702          * The reason why the following code is written newly without
703          * using weston_load_module is it doesn't open library with
704          * RTLD_GLOBAL option.
705          */
706         snprintf(ivi_layout_path, sizeof ivi_layout_path,
707                  "%s/%s", MODULEDIR, "ivi-layout.so");
708         module = dlopen(ivi_layout_path, RTLD_NOW | RTLD_NOLOAD);
709         if (module) {
710                 weston_log("ivi-shell: Module '%s' already loaded\n",
711                            ivi_layout_path);
712                 dlclose(module);
713                 return -1;
714         }
715
716         weston_log("ivi-shell: Loading module '%s'\n", ivi_layout_path);
717         module = dlopen(ivi_layout_path, RTLD_NOW | RTLD_GLOBAL);
718         if (!module) {
719                 weston_log("ivi-shell: Failed to load module: %s\n", dlerror());
720                 return -1;
721         }
722
723         shell->ivi_layout = dlsym(module,"ivi_layout_interface");
724         if (!shell->ivi_layout){
725                 weston_log("ivi-shell: couldn't find ivi_layout_interface in '%s'\n", ivi_layout_path);
726                 free(setting.ivi_module);
727                 dlclose(module);
728                 return -1;
729         }
730
731         shell->ivi_layout->init_with_compositor(compositor);
732
733         /* Call module_init of ivi-modules which are defined in weston.ini */
734         if (ivi_load_modules(compositor, setting.ivi_module, argc, argv) < 0) {
735                 free(setting.ivi_module);
736                 dlclose(module);
737                 return -1;
738         }
739
740         weston_compositor_add_button_binding(compositor, BTN_LEFT, 0, click_to_activate_binding, shell);
741
742         free(setting.ivi_module);
743
744         /* Initialize ivi-shell-ext. wl_shell is supported here */
745         return init_ivi_shell_ext(compositor, argc, argv);
746 }