blob: 8f1c3ca57d69856ef316e34806b3631885e2dceb [file] [log] [blame]
Nobuhiko Tanibata487adc42014-11-27 13:22:37 +09001/*
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
Nobuhiko Tanibata487adc42014-11-27 13:22:37 +090035#include <string.h>
Nobuhiko Tanibata487adc42014-11-27 13:22:37 +090036#include <dlfcn.h>
37#include <limits.h>
38#include <assert.h>
Pekka Paalanen6c7a1c72015-02-19 17:12:19 +020039#include <linux/input.h>
Nobuhiko Tanibata487adc42014-11-27 13:22:37 +090040
41#include "ivi-shell.h"
42#include "ivi-application-server-protocol.h"
Nobuhiko Tanibata28dc18c2014-12-15 13:22:31 +090043#include "ivi-layout-export.h"
Nobuhiko Tanibata487adc42014-11-27 13:22:37 +090044#include "ivi-layout-private.h"
45
Nobuhiko Tanibata487adc42014-11-27 13:22:37 +090046/* Representation of ivi_surface protocol object. */
47struct ivi_shell_surface
48{
49 struct wl_resource* resource;
50 struct ivi_shell *shell;
51 struct ivi_layout_surface *layout_surface;
52
53 struct weston_surface *surface;
54 struct wl_listener surface_destroy_listener;
55
56 uint32_t id_surface;
57
58 int32_t width;
59 int32_t height;
60
61 struct wl_list link;
62
63 struct wl_listener configured_listener;
64};
65
66struct ivi_shell_setting
67{
68 char *ivi_module;
Pekka Paalanene35b2232015-02-19 17:08:44 +020069 int developermode;
Nobuhiko Tanibata487adc42014-11-27 13:22:37 +090070};
71
72/*
73 * Implementation of ivi_surface
74 */
75
76static void
77surface_configure_notify(struct wl_listener *listener, void *data)
78{
79 struct ivi_layout_surface *layout_surf =
80 (struct ivi_layout_surface *)data;
81
82 struct ivi_shell_surface *shell_surf =
83 container_of(listener,
84 struct ivi_shell_surface,
85 configured_listener);
86
87 int32_t dest_width = 0;
88 int32_t dest_height = 0;
Nobuhiko Tanibata28dc18c2014-12-15 13:22:31 +090089
90 ivi_layout_surface_get_dimension(layout_surf,
91 &dest_width, &dest_height);
Nobuhiko Tanibata487adc42014-11-27 13:22:37 +090092
93 if (shell_surf->resource)
94 ivi_surface_send_configure(shell_surf->resource,
95 dest_width, dest_height);
96}
97
98static void
99ivi_shell_surface_configure(struct weston_surface *, int32_t, int32_t);
100
101static struct ivi_shell_surface *
102get_ivi_shell_surface(struct weston_surface *surface)
103{
104 if (surface->configure == ivi_shell_surface_configure)
105 return surface->configure_private;
106
107 return NULL;
108}
109
110static void
111ivi_shell_surface_configure(struct weston_surface *surface,
112 int32_t sx, int32_t sy)
113{
114 struct ivi_shell_surface *ivisurf = get_ivi_shell_surface(surface);
Nobuhiko Tanibata487adc42014-11-27 13:22:37 +0900115
116 if (surface->width == 0 || surface->height == 0 || ivisurf == NULL)
117 return;
118
Nobuhiko Tanibata487adc42014-11-27 13:22:37 +0900119 if (ivisurf->width != surface->width ||
120 ivisurf->height != surface->height) {
121 ivisurf->width = surface->width;
122 ivisurf->height = surface->height;
123
Nobuhiko Tanibata28dc18c2014-12-15 13:22:31 +0900124 ivi_layout_surface_configure(ivisurf->layout_surface,
125 surface->width, surface->height);
Nobuhiko Tanibata487adc42014-11-27 13:22:37 +0900126 }
127}
128
129/*
130 * The ivi_surface wl_resource destructor.
131 *
132 * Gets called via ivi_surface.destroy request or automatic wl_client clean-up.
133 */
134static void
135shell_destroy_shell_surface(struct wl_resource *resource)
136{
137 struct ivi_shell_surface *ivisurf = wl_resource_get_user_data(resource);
138 if (ivisurf != NULL) {
139 ivisurf->resource = NULL;
140 }
141}
142
143/* Gets called through the weston_surface destroy signal. */
144static void
145shell_handle_surface_destroy(struct wl_listener *listener, void *data)
146{
147 struct ivi_shell_surface *ivisurf =
148 container_of(listener, struct ivi_shell_surface,
149 surface_destroy_listener);
150
151 assert(ivisurf != NULL);
152
153 if (ivisurf->surface!=NULL) {
154 ivisurf->surface->configure = NULL;
155 ivisurf->surface->configure_private = NULL;
156 ivisurf->surface = NULL;
157 }
158
159 wl_list_remove(&ivisurf->surface_destroy_listener.link);
160 wl_list_remove(&ivisurf->link);
161
162 if (ivisurf->resource != NULL) {
163 wl_resource_set_user_data(ivisurf->resource, NULL);
164 ivisurf->resource = NULL;
165 }
166 free(ivisurf);
167
168}
169
170/* Gets called, when a client sends ivi_surface.destroy request. */
171static void
172surface_destroy(struct wl_client *client, struct wl_resource *resource)
173{
174 /*
175 * Fires the wl_resource destroy signal, and then calls
176 * ivi_surface wl_resource destructor: shell_destroy_shell_surface()
177 */
178 wl_resource_destroy(resource);
179}
180
181static const struct ivi_surface_interface surface_implementation = {
182 surface_destroy,
183};
184
185/**
186 * Request handler for ivi_application.surface_create.
187 *
188 * Creates an ivi_surface protocol object associated with the given wl_surface.
189 * ivi_surface protocol object is represented by struct ivi_shell_surface.
190 *
191 * \param client The client.
192 * \param resource The ivi_application protocol object.
193 * \param id_surface The IVI surface ID.
194 * \param surface_resource The wl_surface protocol object.
195 * \param id The protocol object id for the new ivi_surface protocol object.
196 *
197 * The wl_surface is given the ivi_surface role and associated with a unique
198 * IVI ID which is used to identify the surface in a controller
199 * (window manager).
200 */
201static void
202application_surface_create(struct wl_client *client,
203 struct wl_resource *resource,
204 uint32_t id_surface,
205 struct wl_resource *surface_resource,
206 uint32_t id)
207{
208 struct ivi_shell *shell = wl_resource_get_user_data(resource);
209 struct ivi_shell_surface *ivisurf;
210 struct ivi_layout_surface *layout_surface;
211 struct weston_surface *weston_surface =
212 wl_resource_get_user_data(surface_resource);
213 struct wl_resource *res;
214
215 if (weston_surface_set_role(weston_surface, "ivi_surface",
216 resource, IVI_APPLICATION_ERROR_ROLE) < 0)
217 return;
218
Nobuhiko Tanibata28dc18c2014-12-15 13:22:31 +0900219 layout_surface = ivi_layout_surface_create(weston_surface, id_surface);
Nobuhiko Tanibata487adc42014-11-27 13:22:37 +0900220
221 /* check if id_ivi is already used for wl_surface*/
222 if (layout_surface == NULL){
223 wl_resource_post_error(resource,
224 IVI_APPLICATION_ERROR_IVI_ID,
225 "surface_id is already assigned "
226 "by another app");
227 return;
228 }
229
230 ivisurf = zalloc(sizeof *ivisurf);
231 if (ivisurf == NULL) {
232 wl_resource_post_no_memory(resource);
233 return;
234 }
235
236 wl_list_init(&ivisurf->link);
237 wl_list_insert(&shell->ivi_surface_list, &ivisurf->link);
238
239 ivisurf->shell = shell;
240 ivisurf->id_surface = id_surface;
241
242 ivisurf->width = 0;
243 ivisurf->height = 0;
244 ivisurf->layout_surface = layout_surface;
245 ivisurf->configured_listener.notify = surface_configure_notify;
Nobuhiko Tanibata28dc18c2014-12-15 13:22:31 +0900246 ivi_layout_surface_add_configured_listener(layout_surface,
247 &ivisurf->configured_listener);
Nobuhiko Tanibata487adc42014-11-27 13:22:37 +0900248 /*
249 * The following code relies on wl_surface destruction triggering
250 * immediateweston_surface destruction
251 */
252 ivisurf->surface_destroy_listener.notify = shell_handle_surface_destroy;
253 wl_signal_add(&weston_surface->destroy_signal,
254 &ivisurf->surface_destroy_listener);
255
256 ivisurf->surface = weston_surface;
257
258 weston_surface->configure = ivi_shell_surface_configure;
259 weston_surface->configure_private = ivisurf;
260
261 res = wl_resource_create(client, &ivi_surface_interface, 1, id);
262 if (res == NULL) {
263 wl_client_post_no_memory(client);
264 return;
265 }
266
267 ivisurf->resource = res;
268
269 wl_resource_set_implementation(res, &surface_implementation,
270 ivisurf, shell_destroy_shell_surface);
271}
272
273static const struct ivi_application_interface application_implementation = {
274 application_surface_create
275};
276
277/*
278 * Handle wl_registry.bind of ivi_application global singleton.
279 */
280static void
281bind_ivi_application(struct wl_client *client,
282 void *data, uint32_t version, uint32_t id)
283{
284 struct ivi_shell *shell = data;
285 struct wl_resource *resource;
286
287 resource = wl_resource_create(client, &ivi_application_interface,
288 1, id);
289
290 wl_resource_set_implementation(resource,
291 &application_implementation,
292 shell, NULL);
293}
294
Nobuhiko Tanibata0038b732014-11-27 13:25:34 +0900295struct weston_view *
296get_default_view(struct weston_surface *surface)
297{
298 struct ivi_shell_surface *shsurf;
299 struct weston_view *view;
300
301 if (!surface || wl_list_empty(&surface->views))
302 return NULL;
303
304 shsurf = get_ivi_shell_surface(surface);
305 if (shsurf && shsurf->layout_surface) {
Nobuhiko Tanibata28dc18c2014-12-15 13:22:31 +0900306 view = ivi_layout_get_weston_view(shsurf->layout_surface);
Nobuhiko Tanibata0038b732014-11-27 13:25:34 +0900307 if (view)
308 return view;
309 }
310
311 wl_list_for_each(view, &surface->views, surface_link) {
312 if (weston_view_is_mapped(view))
313 return view;
314 }
315
316 return container_of(surface->views.next,
317 struct weston_view, surface_link);
318}
319
Nobuhiko Tanibata487adc42014-11-27 13:22:37 +0900320/*
321 * Called through the compositor's destroy signal.
322 */
323static void
324shell_destroy(struct wl_listener *listener, void *data)
325{
326 struct ivi_shell *shell =
327 container_of(listener, struct ivi_shell, destroy_listener);
328 struct ivi_shell_surface *ivisurf, *next;
329
Nobuhiko Tanibata0038b732014-11-27 13:25:34 +0900330 input_panel_destroy(shell);
331
Nobuhiko Tanibata487adc42014-11-27 13:22:37 +0900332 wl_list_for_each_safe(ivisurf, next, &shell->ivi_surface_list, link) {
333 wl_list_remove(&ivisurf->link);
334 free(ivisurf);
335 }
336
337 free(shell);
338}
339
340static void
Pekka Paalanen6c7a1c72015-02-19 17:12:19 +0200341terminate_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
342 void *data)
343{
344 struct weston_compositor *compositor = data;
345
346 wl_display_terminate(compositor->wl_display);
347}
348
349static void
Pekka Paalanene35b2232015-02-19 17:08:44 +0200350init_ivi_shell(struct weston_compositor *compositor, struct ivi_shell *shell,
351 const struct ivi_shell_setting *setting)
Nobuhiko Tanibata487adc42014-11-27 13:22:37 +0900352{
353 shell->compositor = compositor;
354
355 wl_list_init(&shell->ivi_surface_list);
356
Nobuhiko Tanibata0038b732014-11-27 13:25:34 +0900357 weston_layer_init(&shell->input_panel_layer, NULL);
Pekka Paalanene35b2232015-02-19 17:08:44 +0200358
Pekka Paalanen6c7a1c72015-02-19 17:12:19 +0200359 if (setting->developermode) {
Pekka Paalanene35b2232015-02-19 17:08:44 +0200360 weston_install_debug_key_binding(compositor, MODIFIER_SUPER);
Pekka Paalanen6c7a1c72015-02-19 17:12:19 +0200361
362 weston_compositor_add_key_binding(compositor, KEY_BACKSPACE,
363 MODIFIER_CTRL | MODIFIER_ALT,
364 terminate_binding,
365 compositor);
366 }
Nobuhiko Tanibata487adc42014-11-27 13:22:37 +0900367}
368
369static int
370ivi_shell_setting_create(struct ivi_shell_setting *dest,
Pekka Paalanen8a005252015-03-20 15:53:53 +0200371 struct weston_compositor *compositor,
372 int *argc, char *argv[])
Nobuhiko Tanibata487adc42014-11-27 13:22:37 +0900373{
374 int result = 0;
375 struct weston_config *config = compositor->config;
376 struct weston_config_section *section;
377
Pekka Paalanen8a005252015-03-20 15:53:53 +0200378 const struct weston_option ivi_shell_options[] = {
379 { WESTON_OPTION_STRING, "ivi-module", 0, &dest->ivi_module },
380 };
381
382 parse_options(ivi_shell_options, ARRAY_LENGTH(ivi_shell_options),
383 argc, argv);
Nobuhiko Tanibata487adc42014-11-27 13:22:37 +0900384
385 section = weston_config_get_section(config, "ivi-shell", NULL, NULL);
386
Pekka Paalanen8a005252015-03-20 15:53:53 +0200387 if (!dest->ivi_module &&
388 weston_config_section_get_string(section, "ivi-module",
389 &dest->ivi_module, NULL) < 0) {
390 weston_log("Error: ivi-shell: No ivi-module set\n");
Nobuhiko Tanibata487adc42014-11-27 13:22:37 +0900391 result = -1;
392 }
393
Pekka Paalanene35b2232015-02-19 17:08:44 +0200394 weston_config_section_get_bool(section, "developermode",
395 &dest->developermode, 0);
396
Nobuhiko Tanibata487adc42014-11-27 13:22:37 +0900397 return result;
398}
399
400/*
401 * Initialization of ivi-shell.
402 */
Nobuhiko Tanibata487adc42014-11-27 13:22:37 +0900403WL_EXPORT int
404module_init(struct weston_compositor *compositor,
405 int *argc, char *argv[])
406{
407 struct ivi_shell *shell;
Nobuhiko Tanibata487adc42014-11-27 13:22:37 +0900408 struct ivi_shell_setting setting = { };
Pekka Paalanene35b2232015-02-19 17:08:44 +0200409 int retval = -1;
Nobuhiko Tanibata487adc42014-11-27 13:22:37 +0900410
411 shell = zalloc(sizeof *shell);
412 if (shell == NULL)
413 return -1;
414
Pekka Paalanen8a005252015-03-20 15:53:53 +0200415 if (ivi_shell_setting_create(&setting, compositor, argc, argv) != 0)
Pekka Paalanene35b2232015-02-19 17:08:44 +0200416 return -1;
417
418 init_ivi_shell(compositor, shell, &setting);
Nobuhiko Tanibata487adc42014-11-27 13:22:37 +0900419
420 shell->destroy_listener.notify = shell_destroy;
421 wl_signal_add(&compositor->destroy_signal, &shell->destroy_listener);
422
Nobuhiko Tanibata0038b732014-11-27 13:25:34 +0900423 if (input_panel_setup(shell) < 0)
Pekka Paalanene35b2232015-02-19 17:08:44 +0200424 goto out_settings;
Nobuhiko Tanibata487adc42014-11-27 13:22:37 +0900425
Murray Calavera9a51cd72015-06-10 21:16:02 +0000426 if (text_backend_init(compositor) < 0)
427 goto out_settings;
428
Nobuhiko Tanibata487adc42014-11-27 13:22:37 +0900429 if (wl_global_create(compositor->wl_display,
430 &ivi_application_interface, 1,
431 shell, bind_ivi_application) == NULL)
Pekka Paalanene35b2232015-02-19 17:08:44 +0200432 goto out_settings;
Nobuhiko Tanibata487adc42014-11-27 13:22:37 +0900433
Nobuhiko Tanibata28dc18c2014-12-15 13:22:31 +0900434 ivi_layout_init_with_compositor(compositor);
Nobuhiko Tanibata487adc42014-11-27 13:22:37 +0900435
Nobuhiko Tanibata487adc42014-11-27 13:22:37 +0900436 /* Call module_init of ivi-modules which are defined in weston.ini */
Pekka Paalanene35b2232015-02-19 17:08:44 +0200437 if (load_controller_modules(compositor, setting.ivi_module,
438 argc, argv) < 0)
439 goto out_settings;
Nobuhiko Tanibata487adc42014-11-27 13:22:37 +0900440
Pekka Paalanene35b2232015-02-19 17:08:44 +0200441 retval = 0;
442
443out_settings:
Nobuhiko Tanibata487adc42014-11-27 13:22:37 +0900444 free(setting.ivi_module);
Pekka Paalanene35b2232015-02-19 17:08:44 +0200445
446 return retval;
Nobuhiko Tanibata487adc42014-11-27 13:22:37 +0900447}