• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013 DENSO CORPORATION
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files (the
6  * "Software"), to deal in the Software without restriction, including
7  * without limitation the rights to use, copy, modify, merge, publish,
8  * distribute, sublicense, and/or sell copies of the Software, and to
9  * permit persons to whom the Software is furnished to do so, subject to
10  * the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the
13  * next paragraph) shall be included in all copies or substantial
14  * portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24  */
25 
26 /*
27  * ivi-shell supports a type of shell for In-Vehicle Infotainment system.
28  * In-Vehicle Infotainment system traditionally manages surfaces with global
29  * identification. A protocol, ivi_application, supports such a feature
30  * by implementing a request, ivi_application::surface_creation defined in
31  * ivi_application.xml.
32  *
33  *  The ivi-shell explicitly loads a module to add business logic like how to
34  *  layout surfaces by using internal ivi-layout APIs.
35  */
36 #include "config.h"
37 
38 #include <stdint.h>
39 #include <string.h>
40 #include <dlfcn.h>
41 #include <limits.h>
42 #include <assert.h>
43 #include <linux/input.h>
44 
45 #include "ivi-shell.h"
46 #include "ivi-application-server-protocol.h"
47 #include "ivi-layout-private.h"
48 #include "ivi-layout-shell.h"
49 #include "shared/helpers.h"
50 #include "compositor/weston.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 
70 /*
71  * Implementation of ivi_surface
72  */
73 
74 static void
75 ivi_shell_surface_committed(struct weston_surface *, int32_t, int32_t);
76 
77 static struct ivi_shell_surface *
get_ivi_shell_surface(struct weston_surface * surface)78 get_ivi_shell_surface(struct weston_surface *surface)
79 {
80 	struct ivi_shell_surface *shsurf;
81 
82 	if (surface->committed != ivi_shell_surface_committed)
83 		return NULL;
84 
85 	shsurf = surface->committed_private;
86 	assert(shsurf);
87 	assert(shsurf->surface == surface);
88 
89 	return shsurf;
90 }
91 
92 struct ivi_layout_surface *
shell_get_ivi_layout_surface(struct weston_surface * surface)93 shell_get_ivi_layout_surface(struct weston_surface *surface)
94 {
95 	struct ivi_shell_surface *shsurf;
96 
97 	shsurf = get_ivi_shell_surface(surface);
98 	if (!shsurf)
99 		return NULL;
100 
101 	return shsurf->layout_surface;
102 }
103 
104 void
shell_surface_send_configure(struct weston_surface * surface,int32_t width,int32_t height)105 shell_surface_send_configure(struct weston_surface *surface,
106 			     int32_t width, int32_t height)
107 {
108 	struct ivi_shell_surface *shsurf;
109 
110 	shsurf = get_ivi_shell_surface(surface);
111 	if (!shsurf)
112 		return;
113 
114 	if (shsurf->resource)
115 		ivi_surface_send_configure(shsurf->resource, width, height);
116 }
117 
118 static void
ivi_shell_surface_committed(struct weston_surface * surface,int32_t sx,int32_t sy)119 ivi_shell_surface_committed(struct weston_surface *surface,
120 			    int32_t sx, int32_t sy)
121 {
122 	struct ivi_shell_surface *ivisurf = get_ivi_shell_surface(surface);
123 
124 	assert(ivisurf);
125 	if (!ivisurf)
126 		return;
127 
128 	if (surface->width == 0 || surface->height == 0)
129 		return;
130 
131 	if (ivisurf->width != surface->width ||
132 	    ivisurf->height != surface->height) {
133 		ivisurf->width  = surface->width;
134 		ivisurf->height = surface->height;
135 
136 		ivi_layout_surface_configure(ivisurf->layout_surface,
137 					     surface->width, surface->height);
138 	}
139 }
140 
141 static int
ivi_shell_surface_get_label(struct weston_surface * surface,char * buf,size_t len)142 ivi_shell_surface_get_label(struct weston_surface *surface,
143 			    char *buf,
144 			    size_t len)
145 {
146 	struct ivi_shell_surface *shell_surf = get_ivi_shell_surface(surface);
147 
148 	if (!shell_surf)
149 		return snprintf(buf, len, "unidentified window in ivi-shell");
150 
151 	return snprintf(buf, len, "ivi-surface %#x", shell_surf->id_surface);
152 }
153 
154 static void
layout_surface_cleanup(struct ivi_shell_surface * ivisurf)155 layout_surface_cleanup(struct ivi_shell_surface *ivisurf)
156 {
157 	assert(ivisurf->layout_surface != NULL);
158 
159 	/* destroy weston_surface destroy signal. */
160 	if (!ivisurf->layout_surface->weston_desktop_surface)
161 		wl_list_remove(&ivisurf->surface_destroy_listener.link);
162 
163 	ivi_layout_surface_destroy(ivisurf->layout_surface);
164 	ivisurf->layout_surface = NULL;
165 
166 	ivisurf->surface->committed = NULL;
167 	ivisurf->surface->committed_private = NULL;
168 	weston_surface_set_label_func(ivisurf->surface, NULL);
169 	ivisurf->surface = NULL;
170 }
171 
172 /*
173  * The ivi_surface wl_resource destructor.
174  *
175  * Gets called via ivi_surface.destroy request or automatic wl_client clean-up.
176  */
177 static void
shell_destroy_shell_surface(struct wl_resource * resource)178 shell_destroy_shell_surface(struct wl_resource *resource)
179 {
180 	struct ivi_shell_surface *ivisurf = wl_resource_get_user_data(resource);
181 
182 	if (ivisurf == NULL)
183 		return;
184 
185 	assert(ivisurf->resource == resource);
186 
187 	if (ivisurf->layout_surface != NULL)
188 		layout_surface_cleanup(ivisurf);
189 
190 	wl_list_remove(&ivisurf->link);
191 
192 	free(ivisurf);
193 }
194 
195 /* Gets called through the weston_surface destroy signal. */
196 static void
shell_handle_surface_destroy(struct wl_listener * listener,void * data)197 shell_handle_surface_destroy(struct wl_listener *listener, void *data)
198 {
199 	struct ivi_shell_surface *ivisurf =
200 			container_of(listener, struct ivi_shell_surface,
201 				     surface_destroy_listener);
202 
203 	assert(ivisurf != NULL);
204 
205 	if (ivisurf->layout_surface != NULL)
206 		layout_surface_cleanup(ivisurf);
207 }
208 
209 /* Gets called, when a client sends ivi_surface.destroy request. */
210 static void
surface_destroy(struct wl_client * client,struct wl_resource * resource)211 surface_destroy(struct wl_client *client, struct wl_resource *resource)
212 {
213 	/*
214 	 * Fires the wl_resource destroy signal, and then calls
215 	 * ivi_surface wl_resource destructor: shell_destroy_shell_surface()
216 	 */
217 	wl_resource_destroy(resource);
218 }
219 
220 static const struct ivi_surface_interface surface_implementation = {
221 	surface_destroy,
222 };
223 
224 /**
225  * Request handler for ivi_application.surface_create.
226  *
227  * Creates an ivi_surface protocol object associated with the given wl_surface.
228  * ivi_surface protocol object is represented by struct ivi_shell_surface.
229  *
230  * \param client The client.
231  * \param resource The ivi_application protocol object.
232  * \param id_surface The IVI surface ID.
233  * \param surface_resource The wl_surface protocol object.
234  * \param id The protocol object id for the new ivi_surface protocol object.
235  *
236  * The wl_surface is given the ivi_surface role and associated with a unique
237  * IVI ID which is used to identify the surface in a controller
238  * (window manager).
239  */
240 static void
application_surface_create(struct wl_client * client,struct wl_resource * resource,uint32_t id_surface,struct wl_resource * surface_resource,uint32_t id)241 application_surface_create(struct wl_client *client,
242 			   struct wl_resource *resource,
243 			   uint32_t id_surface,
244 			   struct wl_resource *surface_resource,
245 			   uint32_t id)
246 {
247 	struct ivi_shell *shell = wl_resource_get_user_data(resource);
248 	struct ivi_shell_surface *ivisurf;
249 	struct ivi_layout_surface *layout_surface;
250 	struct weston_surface *weston_surface =
251 		wl_resource_get_user_data(surface_resource);
252 	struct wl_resource *res;
253 
254 	if (weston_surface_set_role(weston_surface, "ivi_surface",
255 				    resource, IVI_APPLICATION_ERROR_ROLE) < 0)
256 		return;
257 
258 	layout_surface = ivi_layout_surface_create(weston_surface, id_surface);
259 
260 	/* check if id_ivi is already used for wl_surface*/
261 	if (layout_surface == NULL) {
262 		wl_resource_post_error(resource,
263 				       IVI_APPLICATION_ERROR_IVI_ID,
264 				       "surface_id is already assigned "
265 				       "by another app");
266 		return;
267 	}
268 
269 	layout_surface->weston_desktop_surface = NULL;
270 
271 	ivisurf = zalloc(sizeof *ivisurf);
272 	if (ivisurf == NULL) {
273 		wl_resource_post_no_memory(resource);
274 		return;
275 	}
276 
277 	wl_list_init(&ivisurf->link);
278 	wl_list_insert(&shell->ivi_surface_list, &ivisurf->link);
279 
280 	ivisurf->shell = shell;
281 	ivisurf->id_surface = id_surface;
282 
283 	ivisurf->width = 0;
284 	ivisurf->height = 0;
285 	ivisurf->layout_surface = layout_surface;
286 
287 	/*
288 	 * The following code relies on wl_surface destruction triggering
289 	 * immediateweston_surface destruction
290 	 */
291 	ivisurf->surface_destroy_listener.notify = shell_handle_surface_destroy;
292 	wl_signal_add(&weston_surface->destroy_signal,
293 		      &ivisurf->surface_destroy_listener);
294 
295 	ivisurf->surface = weston_surface;
296 
297 	weston_surface->committed = ivi_shell_surface_committed;
298 	weston_surface->committed_private = ivisurf;
299 	weston_surface_set_label_func(weston_surface,
300 				      ivi_shell_surface_get_label);
301 
302 	res = wl_resource_create(client, &ivi_surface_interface, 1, id);
303 	if (res == NULL) {
304 		wl_client_post_no_memory(client);
305 		return;
306 	}
307 
308 	ivisurf->resource = res;
309 
310 	wl_resource_set_implementation(res, &surface_implementation,
311 				       ivisurf, shell_destroy_shell_surface);
312 }
313 
314 static const struct ivi_application_interface application_implementation = {
315 	application_surface_create
316 };
317 
318 /*
319  * Handle wl_registry.bind of ivi_application global singleton.
320  */
321 static void
bind_ivi_application(struct wl_client * client,void * data,uint32_t version,uint32_t id)322 bind_ivi_application(struct wl_client *client,
323 		     void *data, uint32_t version, uint32_t id)
324 {
325 	struct ivi_shell *shell = data;
326 	struct wl_resource *resource;
327 
328 	resource = wl_resource_create(client, &ivi_application_interface,
329 				      1, id);
330 
331 	wl_resource_set_implementation(resource,
332 				       &application_implementation,
333 				       shell, NULL);
334 }
335 
336 /*
337  * Called through the compositor's destroy signal.
338  */
339 static void
shell_destroy(struct wl_listener * listener,void * data)340 shell_destroy(struct wl_listener *listener, void *data)
341 {
342 	struct ivi_shell *shell =
343 		container_of(listener, struct ivi_shell, destroy_listener);
344 	struct ivi_shell_surface *ivisurf, *next;
345 
346 	wl_list_remove(&shell->destroy_listener.link);
347 	wl_list_remove(&shell->wake_listener.link);
348 
349 	wl_list_for_each_safe(ivisurf, next, &shell->ivi_surface_list, link) {
350 		wl_list_remove(&ivisurf->link);
351 		free(ivisurf);
352 	}
353 
354 	free(shell);
355 }
356 
357 /*
358  * Called through the compositor's wake signal.
359  */
360 static void
wake_handler(struct wl_listener * listener,void * data)361 wake_handler(struct wl_listener *listener, void *data)
362 {
363 	struct weston_compositor *compositor = data;
364 
365 	weston_compositor_damage_all(compositor);
366 }
367 
368 static void
terminate_binding(struct weston_keyboard * keyboard,const struct timespec * time,uint32_t key,void * data)369 terminate_binding(struct weston_keyboard *keyboard, const struct timespec *time,
370 		  uint32_t key, void *data)
371 {
372 	struct weston_compositor *compositor = data;
373 
374 	weston_compositor_exit(compositor);
375 }
376 
377 static void
init_ivi_shell(struct weston_compositor * compositor,struct ivi_shell * shell)378 init_ivi_shell(struct weston_compositor *compositor, struct ivi_shell *shell)
379 {
380 	struct weston_config *config = wet_get_config(compositor);
381 	struct weston_config_section *section;
382 	bool developermode;
383 
384 	shell->compositor = compositor;
385 
386 	wl_list_init(&shell->ivi_surface_list);
387 
388 	section = weston_config_get_section(config, "ivi-shell", NULL, NULL);
389 
390 	weston_config_section_get_bool(section, "developermode",
391 				       &developermode, 0);
392 
393 	if (developermode) {
394 		weston_install_debug_key_binding(compositor, MODIFIER_SUPER);
395 
396 		weston_compositor_add_key_binding(compositor, KEY_BACKSPACE,
397 						  MODIFIER_CTRL | MODIFIER_ALT,
398 						  terminate_binding,
399 						  compositor);
400 	}
401 }
402 
403 static void
activate_binding(struct weston_seat * seat,struct weston_view * focus_view)404 activate_binding(struct weston_seat *seat,
405 		 struct weston_view *focus_view)
406 {
407 	struct weston_surface *focus = focus_view->surface;
408 	struct weston_surface *main_surface =
409 		weston_surface_get_main_surface(focus);
410 
411 	if (get_ivi_shell_surface(main_surface) == NULL)
412 		return;
413 
414 	weston_seat_set_keyboard_focus(seat, focus);
415 }
416 
417 static void
click_to_activate_binding(struct weston_pointer * pointer,const struct timespec * time,uint32_t button,void * data)418 click_to_activate_binding(struct weston_pointer *pointer,
419 			  const struct timespec *time,
420 			  uint32_t button, void *data)
421 {
422 	if (pointer->grab != &pointer->default_grab)
423 		return;
424 	if (pointer->focus == NULL)
425 		return;
426 
427 	activate_binding(pointer->seat, pointer->focus);
428 }
429 
430 static void
touch_to_activate_binding(struct weston_touch * touch,const struct timespec * time,void * data)431 touch_to_activate_binding(struct weston_touch *touch,
432 			  const struct timespec *time,
433 			  void *data)
434 {
435 	if (touch->grab != &touch->default_grab)
436 		return;
437 	if (touch->focus == NULL)
438 		return;
439 
440 	activate_binding(touch->seat, touch->focus);
441 }
442 
443 static void
shell_add_bindings(struct weston_compositor * compositor,struct ivi_shell * shell)444 shell_add_bindings(struct weston_compositor *compositor,
445 		   struct ivi_shell *shell)
446 {
447 	weston_compositor_add_button_binding(compositor, BTN_LEFT, 0,
448 					     click_to_activate_binding,
449 					     shell);
450 	weston_compositor_add_button_binding(compositor, BTN_RIGHT, 0,
451 					     click_to_activate_binding,
452 					     shell);
453 	weston_compositor_add_touch_binding(compositor, 0,
454 					    touch_to_activate_binding,
455 					    shell);
456 }
457 
458 /*
459  * libweston-desktop
460  */
461 
462 static void
desktop_surface_ping_timeout(struct weston_desktop_client * client,void * user_data)463 desktop_surface_ping_timeout(struct weston_desktop_client *client,
464 			     void *user_data)
465 {
466 	/* Not supported */
467 }
468 
469 static void
desktop_surface_pong(struct weston_desktop_client * client,void * user_data)470 desktop_surface_pong(struct weston_desktop_client *client,
471 		     void *user_data)
472 {
473 	/* Not supported */
474 }
475 
476 static void
desktop_surface_added(struct weston_desktop_surface * surface,void * user_data)477 desktop_surface_added(struct weston_desktop_surface *surface,
478 		      void *user_data)
479 {
480 	struct ivi_shell *shell = (struct ivi_shell *) user_data;
481 	struct ivi_layout_surface *layout_surface;
482 	struct ivi_shell_surface *ivisurf;
483 	struct weston_surface *weston_surf =
484 			weston_desktop_surface_get_surface(surface);
485 
486 	layout_surface = ivi_layout_desktop_surface_create(weston_surf);
487 	if (!layout_surface) {
488 		return;
489 	}
490 
491 	layout_surface->weston_desktop_surface = surface;
492 
493 	ivisurf = zalloc(sizeof *ivisurf);
494 	if (!ivisurf) {
495 		return;
496 	}
497 
498 	ivisurf->shell = shell;
499 	ivisurf->id_surface = IVI_INVALID_ID;
500 
501 	ivisurf->width = 0;
502 	ivisurf->height = 0;
503 	ivisurf->layout_surface = layout_surface;
504 	ivisurf->surface = weston_surf;
505 
506 	weston_desktop_surface_set_user_data(surface, ivisurf);
507 }
508 
509 static void
desktop_surface_removed(struct weston_desktop_surface * surface,void * user_data)510 desktop_surface_removed(struct weston_desktop_surface *surface,
511 			void *user_data)
512 {
513 	struct ivi_shell_surface *ivisurf = (struct ivi_shell_surface *)
514 			weston_desktop_surface_get_user_data(surface);
515 
516 	assert(ivisurf != NULL);
517 
518 	if (ivisurf->layout_surface)
519 		layout_surface_cleanup(ivisurf);
520 }
521 
522 static void
desktop_surface_committed(struct weston_desktop_surface * surface,int32_t sx,int32_t sy,void * user_data)523 desktop_surface_committed(struct weston_desktop_surface *surface,
524 			  int32_t sx, int32_t sy, void *user_data)
525 {
526 	struct ivi_shell_surface *ivisurf = (struct ivi_shell_surface *)
527 			weston_desktop_surface_get_user_data(surface);
528 	struct weston_surface *weston_surf =
529 			weston_desktop_surface_get_surface(surface);
530 
531 	if(!ivisurf)
532 		return;
533 
534 	if (weston_surf->width == 0 || weston_surf->height == 0)
535 		return;
536 
537 	if (ivisurf->width != weston_surf->width ||
538 	    ivisurf->height != weston_surf->height) {
539 		ivisurf->width  = weston_surf->width;
540 		ivisurf->height = weston_surf->height;
541 
542 		ivi_layout_desktop_surface_configure(ivisurf->layout_surface,
543 						 weston_surf->width,
544 						 weston_surf->height);
545 	}
546 }
547 
548 static void
desktop_surface_move(struct weston_desktop_surface * surface,struct weston_seat * seat,uint32_t serial,void * user_data)549 desktop_surface_move(struct weston_desktop_surface *surface,
550 		     struct weston_seat *seat, uint32_t serial, void *user_data)
551 {
552 	/* Not supported */
553 }
554 
555 static void
desktop_surface_resize(struct weston_desktop_surface * surface,struct weston_seat * seat,uint32_t serial,enum weston_desktop_surface_edge edges,void * user_data)556 desktop_surface_resize(struct weston_desktop_surface *surface,
557 		       struct weston_seat *seat, uint32_t serial,
558 		       enum weston_desktop_surface_edge edges, void *user_data)
559 {
560 	/* Not supported */
561 }
562 
563 static void
desktop_surface_fullscreen_requested(struct weston_desktop_surface * surface,bool fullscreen,struct weston_output * output,void * user_data)564 desktop_surface_fullscreen_requested(struct weston_desktop_surface *surface,
565 				     bool fullscreen,
566 				     struct weston_output *output,
567 				     void *user_data)
568 {
569 	/* Not supported */
570 }
571 
572 static void
desktop_surface_maximized_requested(struct weston_desktop_surface * surface,bool maximized,void * user_data)573 desktop_surface_maximized_requested(struct weston_desktop_surface *surface,
574 				    bool maximized, void *user_data)
575 {
576 	/* Not supported */
577 }
578 
579 static void
desktop_surface_minimized_requested(struct weston_desktop_surface * surface,void * user_data)580 desktop_surface_minimized_requested(struct weston_desktop_surface *surface,
581 				    void *user_data)
582 {
583 	/* Not supported */
584 }
585 
586 static void
desktop_surface_set_xwayland_position(struct weston_desktop_surface * surface,int32_t x,int32_t y,void * user_data)587 desktop_surface_set_xwayland_position(struct weston_desktop_surface *surface,
588 				      int32_t x, int32_t y, void *user_data)
589 {
590 	/* Not supported */
591 }
592 
593 static const struct weston_desktop_api shell_desktop_api = {
594 	.struct_size = sizeof(struct weston_desktop_api),
595 	.ping_timeout = desktop_surface_ping_timeout,
596 	.pong = desktop_surface_pong,
597 	.surface_added = desktop_surface_added,
598 	.surface_removed = desktop_surface_removed,
599 	.committed = desktop_surface_committed,
600 
601 	.move = desktop_surface_move,
602 	.resize = desktop_surface_resize,
603 	.fullscreen_requested = desktop_surface_fullscreen_requested,
604 	.maximized_requested = desktop_surface_maximized_requested,
605 	.minimized_requested = desktop_surface_minimized_requested,
606 	.set_xwayland_position = desktop_surface_set_xwayland_position,
607 };
608 
609 /*
610  * end of libweston-desktop
611  */
612 
613 /*
614  * Initialization of ivi-shell.
615  */
616 WL_EXPORT int
wet_shell_init(struct weston_compositor * compositor,int * argc,char * argv[])617 wet_shell_init(struct weston_compositor *compositor,
618 	       int *argc, char *argv[])
619 {
620 	struct ivi_shell *shell;
621 
622 	shell = zalloc(sizeof *shell);
623 	if (shell == NULL)
624 		return -1;
625 
626 	if (!weston_compositor_add_destroy_listener_once(compositor,
627 							 &shell->destroy_listener,
628 							 shell_destroy)) {
629 		free(shell);
630 		return 0;
631 	}
632 
633 	init_ivi_shell(compositor, shell);
634 
635 	shell->wake_listener.notify = wake_handler;
636 	wl_signal_add(&compositor->wake_signal, &shell->wake_listener);
637 
638 	shell->desktop = weston_desktop_create(compositor, &shell_desktop_api, shell);
639 	if (!shell->desktop)
640 		goto err_shell;
641 
642 	if (wl_global_create(compositor->wl_display,
643 			     &ivi_application_interface, 1,
644 			     shell, bind_ivi_application) == NULL)
645 		goto err_desktop;
646 
647 	ivi_layout_init_with_compositor(compositor);
648 	shell_add_bindings(compositor, shell);
649 
650 	return IVI_SUCCEEDED;
651 
652 err_desktop:
653 	weston_desktop_destroy(shell->desktop);
654 
655 err_shell:
656 	wl_list_remove(&shell->destroy_listener.link);
657 	free(shell);
658 
659 	return IVI_FAILED;
660 }
661