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