blob: 5a5c73381cdf9d8599bb678f6d6faba7c43c798e [file] [log] [blame]
Nobuhiko Tanibata923bc142014-11-27 13:23:32 +09001/*
2 * Copyright (C) 2013 DENSO CORPORATION
3 *
Bryce Harrington1f6b0d12015-06-10 22:48:59 -07004 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
Nobuhiko Tanibata923bc142014-11-27 13:23:32 +090010 *
Bryce Harrington1f6b0d12015-06-10 22:48:59 -070011 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
Nobuhiko Tanibata923bc142014-11-27 13:23:32 +090022 */
23
24#include <sys/wait.h>
25#include <unistd.h>
26#include <stdlib.h>
27#include <stdio.h>
28#include <string.h>
29#include <linux/input.h>
30#include <assert.h>
31#include <fcntl.h>
32#include <signal.h>
33#include <sys/mman.h>
34#include <getopt.h>
35#include <wayland-cursor.h>
36#include "../shared/cairo-util.h"
37#include "../shared/config-parser.h"
38#include "../shared/os-compatibility.h"
39#include "ivi-application-client-protocol.h"
40#include "ivi-hmi-controller-client-protocol.h"
41
42/**
43 * A reference implementation how to use ivi-hmi-controller interface to
44 * interact with hmi-controller. This is launched from hmi-controller by using
45 * hmi_client_start and create a pthread.
46 *
47 * The basic flow is as followed,
48 * 1/ read configuration from weston.ini.
49 * 2/ draw png file to surface according to configuration of weston.ini
50 * 3/ set up UI by using ivi-hmi-controller protocol
51 * 4/ Enter event loop
52 * 5/ If a surface receives touch/pointer event, followings are invoked
53 * according to type of event and surface
54 * 5-1/ If a surface to launch ivi_application receive touch up, it execs
55 * ivi-application configured in weston.ini.
56 * 5-2/ If a surface to switch layout mode receive touch up, it sends a request,
57 * ivi_hmi_controller_switch_mode, to hmi-controller.
58 * 5-3/ If a surface to show workspace having launchers, it sends a request,
59 * ivi_hmi_controller_home, to hmi-controller.
60 * 5-4/ If touch down events happens in workspace,
61 * ivi_hmi_controller_workspace_control is sent to slide workspace.
62 * When control finished, event: ivi_hmi_controller_workspace_end_control
63 * is received.
64 */
65
66/*****************************************************************************
67 * structure, globals
68 ****************************************************************************/
69enum cursor_type {
70 CURSOR_BOTTOM_LEFT,
71 CURSOR_BOTTOM_RIGHT,
72 CURSOR_BOTTOM,
73 CURSOR_DRAGGING,
74 CURSOR_LEFT_PTR,
75 CURSOR_LEFT,
76 CURSOR_RIGHT,
77 CURSOR_TOP_LEFT,
78 CURSOR_TOP_RIGHT,
79 CURSOR_TOP,
80 CURSOR_IBEAM,
81 CURSOR_HAND1,
82 CURSOR_WATCH,
83
84 CURSOR_BLANK
85};
86struct wlContextCommon {
87 struct wl_display *wlDisplay;
88 struct wl_registry *wlRegistry;
89 struct wl_compositor *wlCompositor;
90 struct wl_shm *wlShm;
91 uint32_t formats;
92 struct wl_seat *wlSeat;
93 struct wl_pointer *wlPointer;
94 struct wl_touch *wlTouch;
95 struct ivi_application *iviApplication;
96 struct ivi_hmi_controller *hmiCtrl;
97 struct hmi_homescreen_setting *hmi_setting;
98 struct wl_list list_wlContextStruct;
99 struct wl_surface *enterSurface;
100 int32_t is_home_on;
101 struct wl_cursor_theme *cursor_theme;
102 struct wl_cursor **cursors;
103 struct wl_surface *pointer_surface;
104 enum cursor_type current_cursor;
105 uint32_t enter_serial;
106};
107
108struct wlContextStruct {
109 struct wlContextCommon *cmm;
110 struct wl_surface *wlSurface;
111 struct wl_buffer *wlBuffer;
112 cairo_surface_t *ctx_image;
113 void *data;
114 uint32_t id_surface;
115 struct wl_list link;
116};
117
118struct
119hmi_homescreen_srf {
120 uint32_t id;
121 char *filePath;
122 uint32_t color;
123};
124
125struct
126hmi_homescreen_workspace {
127 struct wl_array launcher_id_array;
128 struct wl_list link;
129};
130
131struct
132hmi_homescreen_launcher {
133 uint32_t icon_surface_id;
134 uint32_t workspace_id;
135 char *icon;
136 char *path;
137 struct wl_list link;
138};
139
140struct
141hmi_homescreen_setting {
142 struct hmi_homescreen_srf background;
143 struct hmi_homescreen_srf panel;
144 struct hmi_homescreen_srf tiling;
145 struct hmi_homescreen_srf sidebyside;
146 struct hmi_homescreen_srf fullscreen;
147 struct hmi_homescreen_srf random;
148 struct hmi_homescreen_srf home;
149 struct hmi_homescreen_srf workspace_background;
150
151 struct wl_list workspace_list;
152 struct wl_list launcher_list;
153
154 char *cursor_theme;
155 int32_t cursor_size;
156 uint32_t transition_duration;
157};
158
159static void *
160fail_on_null(void *p, size_t size, char *file, int32_t line)
161{
162 if (size && !p) {
163 fprintf(stderr, "%s(%d) %zd: out of memory\n",
164 file, line, size);
165 exit(EXIT_FAILURE);
166 }
167
168 return p;
169}
170
171static void *
172mem_alloc(size_t size, char *file, int32_t line)
173{
174 return fail_on_null(calloc(1, size), size, file, line);
175}
176
177#define MEM_ALLOC(s) mem_alloc((s),__FILE__,__LINE__)
178#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
179
180/*****************************************************************************
181 * Event Handler
182 ****************************************************************************/
183
184static void
185shm_format(void *data, struct wl_shm *pWlShm, uint32_t format)
186{
187 struct wlContextCommon *pCtx = data;
188
189 pCtx->formats |= (1 << format);
190}
191
192static struct wl_shm_listener shm_listenter = {
193 shm_format
194};
195
196static int32_t
197getIdOfWlSurface(struct wlContextCommon *pCtx, struct wl_surface *wlSurface)
198{
199 struct wlContextStruct *pWlCtxSt = NULL;
200
201 if (NULL == pCtx || NULL == wlSurface )
202 return 0;
203
204 wl_list_for_each(pWlCtxSt, &pCtx->list_wlContextStruct, link) {
205 if (pWlCtxSt->wlSurface == wlSurface)
206 return pWlCtxSt->id_surface;
207 }
208
209 return -1;
210}
211
212static void
213set_pointer_image(struct wlContextCommon *pCtx, uint32_t index)
214{
215 struct wl_cursor *cursor = NULL;
216 struct wl_cursor_image *image = NULL;
217 struct wl_buffer *buffer = NULL;
218
219 if (!pCtx->wlPointer || !pCtx->cursors)
220 return;
221
222 if (CURSOR_BLANK == pCtx->current_cursor) {
223 wl_pointer_set_cursor(pCtx->wlPointer, pCtx->enter_serial,
224 NULL, 0, 0);
225 return;
226 }
227
228 cursor = pCtx->cursors[pCtx->current_cursor];
229 if (!cursor)
230 return;
231
232 if (cursor->image_count <= index) {
233 fprintf(stderr, "cursor index out of range\n");
234 return;
235 }
236
237 image = cursor->images[index];
238 buffer = wl_cursor_image_get_buffer(image);
239
240 if (!buffer)
241 return;
242
243 wl_pointer_set_cursor(pCtx->wlPointer, pCtx->enter_serial,
244 pCtx->pointer_surface,
245 image->hotspot_x, image->hotspot_y);
246
247 wl_surface_attach(pCtx->pointer_surface, buffer, 0, 0);
248
249 wl_surface_damage(pCtx->pointer_surface, 0, 0,
250 image->width, image->height);
251
252 wl_surface_commit(pCtx->pointer_surface);
253}
254
255static void
256PointerHandleEnter(void *data, struct wl_pointer *wlPointer, uint32_t serial,
257 struct wl_surface *wlSurface, wl_fixed_t sx, wl_fixed_t sy)
258{
259 struct wlContextCommon *pCtx = data;
260
261 pCtx->enter_serial = serial;
262 pCtx->enterSurface = wlSurface;
263 set_pointer_image(pCtx, 0);
264#ifdef _DEBUG
265 printf("ENTER PointerHandleEnter: x(%d), y(%d)\n", sx, sy);
266#endif
267}
268
269static void
270PointerHandleLeave(void *data, struct wl_pointer *wlPointer, uint32_t serial,
271 struct wl_surface *wlSurface)
272{
273 struct wlContextCommon *pCtx = data;
274
275 pCtx->enterSurface = NULL;
276
277#ifdef _DEBUG
278 printf("ENTER PointerHandleLeave: serial(%d)\n", serial);
279#endif
280}
281
282static void
283PointerHandleMotion(void *data, struct wl_pointer *wlPointer, uint32_t time,
284 wl_fixed_t sx, wl_fixed_t sy)
285{
286#ifdef _DEBUG
287 printf("ENTER PointerHandleMotion: x(%d), y(%d)\n", sx, sy);
288#endif
289}
290
291/**
292 * if a surface assigned as launcher receives touch-off event, invoking
293 * ivi-application which configured in weston.ini with path to binary.
294 */
295extern char **environ; /*defied by libc */
296
297static pid_t
298execute_process(char *path, char *argv[])
299{
300 pid_t pid = fork();
301 if (pid < 0)
302 fprintf(stderr, "Failed to fork\n");
303
304 if (pid)
305 return pid;
306
307 if (-1 == execve(path, argv, environ)) {
308 fprintf(stderr, "Failed to execve %s\n", path);
309 exit(1);
310 }
311
312 return pid;
313}
314
315static int32_t
316launcher_button(uint32_t surfaceId, struct wl_list *launcher_list)
317{
318 struct hmi_homescreen_launcher *launcher = NULL;
319
320 wl_list_for_each(launcher, launcher_list, link) {
321 char *argv[] = { NULL };
322
323 if (surfaceId != launcher->icon_surface_id)
324 continue;
325
326 execute_process(launcher->path, argv);
327
328 return 1;
329 }
330
331 return 0;
332}
333
334/**
335 * is-method to identify a surface set as launcher in workspace or workspace
336 * itself. This is-method is used to decide whether request;
337 * ivi_hmi_controller_workspace_control is sent or not.
338 */
339static int32_t
340isWorkspaceSurface(uint32_t id, struct hmi_homescreen_setting *hmi_setting)
341{
342 struct hmi_homescreen_launcher *launcher = NULL;
343
344 if (id == hmi_setting->workspace_background.id)
345 return 1;
346
347 wl_list_for_each(launcher, &hmi_setting->launcher_list, link) {
348 if (id == launcher->icon_surface_id)
349 return 1;
350 }
351
352 return 0;
353}
354
355/**
356 * Decide which request is sent to hmi-controller
357 */
358static void
359touch_up(struct ivi_hmi_controller *hmi_ctrl, uint32_t id_surface,
360 int32_t *is_home_on, struct hmi_homescreen_setting *hmi_setting)
361{
362 if (launcher_button(id_surface, &hmi_setting->launcher_list)) {
363 *is_home_on = 0;
364 ivi_hmi_controller_home(hmi_ctrl, IVI_HMI_CONTROLLER_HOME_OFF);
365 } else if (id_surface == hmi_setting->tiling.id) {
366 ivi_hmi_controller_switch_mode(hmi_ctrl,
367 IVI_HMI_CONTROLLER_LAYOUT_MODE_TILING);
368 } else if (id_surface == hmi_setting->sidebyside.id) {
369 ivi_hmi_controller_switch_mode(hmi_ctrl,
370 IVI_HMI_CONTROLLER_LAYOUT_MODE_SIDE_BY_SIDE);
371 } else if (id_surface == hmi_setting->fullscreen.id) {
372 ivi_hmi_controller_switch_mode(hmi_ctrl,
373 IVI_HMI_CONTROLLER_LAYOUT_MODE_FULL_SCREEN);
374 } else if (id_surface == hmi_setting->random.id) {
375 ivi_hmi_controller_switch_mode(hmi_ctrl,
376 IVI_HMI_CONTROLLER_LAYOUT_MODE_RANDOM);
377 } else if (id_surface == hmi_setting->home.id) {
378 *is_home_on = !(*is_home_on);
379 if (*is_home_on) {
380 ivi_hmi_controller_home(hmi_ctrl,
381 IVI_HMI_CONTROLLER_HOME_ON);
382 } else {
383 ivi_hmi_controller_home(hmi_ctrl,
384 IVI_HMI_CONTROLLER_HOME_OFF);
385 }
386 }
387}
388
389/**
390 * Even handler of Pointer event. IVI system is usually manipulated by touch
391 * screen. However, some systems also have pointer device.
392 * Release is the same behavior as touch off
393 * Pressed is the same behavior as touch on
394 */
395static void
396PointerHandleButton(void *data, struct wl_pointer *wlPointer, uint32_t serial,
397 uint32_t time, uint32_t button, uint32_t state)
398{
399 struct wlContextCommon *pCtx = data;
400 struct ivi_hmi_controller *hmi_ctrl = pCtx->hmiCtrl;
401 const uint32_t id_surface = getIdOfWlSurface(pCtx, pCtx->enterSurface);
402
403 if (BTN_RIGHT == button)
404 return;
405
406 switch (state) {
407 case WL_POINTER_BUTTON_STATE_RELEASED:
408 touch_up(hmi_ctrl, id_surface, &pCtx->is_home_on,
409 pCtx->hmi_setting);
410 break;
411
412 case WL_POINTER_BUTTON_STATE_PRESSED:
413
414 if (isWorkspaceSurface(id_surface, pCtx->hmi_setting)) {
415 ivi_hmi_controller_workspace_control(hmi_ctrl,
416 pCtx->wlSeat,
417 serial);
418 }
419
420 break;
421 }
422#ifdef _DEBUG
423 printf("ENTER PointerHandleButton: button(%d), state(%d)\n",
424 button, state);
425#endif
426}
427
428static void
429PointerHandleAxis(void *data, struct wl_pointer *wlPointer, uint32_t time,
430 uint32_t axis, wl_fixed_t value)
431{
432#ifdef _DEBUG
433 printf("ENTER PointerHandleAxis: axis(%d), value(%d)\n", axis, value);
434#endif
435}
436
437static struct wl_pointer_listener pointer_listener = {
438 PointerHandleEnter,
439 PointerHandleLeave,
440 PointerHandleMotion,
441 PointerHandleButton,
442 PointerHandleAxis
443};
444
445/**
446 * Even handler of touch event
447 */
448static void
449TouchHandleDown(void *data, struct wl_touch *wlTouch, uint32_t serial,
450 uint32_t time, struct wl_surface *surface, int32_t id,
451 wl_fixed_t x_w, wl_fixed_t y_w)
452{
453 struct wlContextCommon *pCtx = data;
454 struct ivi_hmi_controller *hmi_ctrl = pCtx->hmiCtrl;
455 uint32_t id_surface = 0;
456
457 if (0 == id)
458 pCtx->enterSurface = surface;
459
460 id_surface = getIdOfWlSurface(pCtx, pCtx->enterSurface);
461
462 /**
463 * When touch down happens on surfaces of workspace, ask
464 * hmi-controller to start control workspace to select page of
465 * workspace. After sending seat to hmi-controller by
466 * ivi_hmi_controller_workspace_control,
467 * hmi-controller-homescreen doesn't receive any event till
468 * hmi-controller sends back it.
469 */
470 if (isWorkspaceSurface(id_surface, pCtx->hmi_setting)) {
471 ivi_hmi_controller_workspace_control(hmi_ctrl, pCtx->wlSeat,
472 serial);
473 }
474}
475
476static void
477TouchHandleUp(void *data, struct wl_touch *wlTouch, uint32_t serial,
478 uint32_t time, int32_t id)
479{
480 struct wlContextCommon *pCtx = data;
481 struct ivi_hmi_controller *hmi_ctrl = pCtx->hmiCtrl;
482
483 const uint32_t id_surface = getIdOfWlSurface(pCtx, pCtx->enterSurface);
484
485 /**
486 * triggering event according to touch-up happening on which surface.
487 */
488 if (id == 0){
489 touch_up(hmi_ctrl, id_surface, &pCtx->is_home_on,
490 pCtx->hmi_setting);
491 }
492}
493
494static void
495TouchHandleMotion(void *data, struct wl_touch *wlTouch, uint32_t time,
496 int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
497{
498}
499
500static void
501TouchHandleFrame(void *data, struct wl_touch *wlTouch)
502{
503}
504
505static void
506TouchHandleCancel(void *data, struct wl_touch *wlTouch)
507{
508}
509
510static struct wl_touch_listener touch_listener = {
511 TouchHandleDown,
512 TouchHandleUp,
513 TouchHandleMotion,
514 TouchHandleFrame,
515 TouchHandleCancel,
516};
517
518/**
519 * Handler of capabilities
520 */
521static void
522seat_handle_capabilities(void *data, struct wl_seat *seat, uint32_t caps)
523{
524 struct wlContextCommon *p_wlCtx = (struct wlContextCommon*)data;
525 struct wl_seat *wlSeat = p_wlCtx->wlSeat;
526 struct wl_pointer *wlPointer = p_wlCtx->wlPointer;
527 struct wl_touch *wlTouch = p_wlCtx->wlTouch;
528
529 if (p_wlCtx->hmi_setting->cursor_theme) {
530 if ((caps & WL_SEAT_CAPABILITY_POINTER) && !wlPointer){
531 wlPointer = wl_seat_get_pointer(wlSeat);
532 wl_pointer_add_listener(wlPointer,
533 &pointer_listener, data);
534 } else
535 if (!(caps & WL_SEAT_CAPABILITY_POINTER) && wlPointer){
536 wl_pointer_destroy(wlPointer);
537 wlPointer = NULL;
538 }
539 p_wlCtx->wlPointer = wlPointer;
540 }
541
542 if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !wlTouch){
543 wlTouch = wl_seat_get_touch(wlSeat);
544 wl_touch_add_listener(wlTouch, &touch_listener, data);
545 } else
546 if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && wlTouch){
547 wl_touch_destroy(wlTouch);
548 wlTouch = NULL;
549 }
550 p_wlCtx->wlTouch = wlTouch;
551}
552
553static struct wl_seat_listener seat_Listener = {
554 seat_handle_capabilities,
555};
556
557/**
558 * Registration of event
559 * This event is received when hmi-controller server finished controlling
560 * workspace.
561 */
562static void
563ivi_hmi_controller_workspace_end_control(void *data,
564 struct ivi_hmi_controller *hmi_ctrl,
565 int32_t is_controlled)
566{
567 struct wlContextCommon *pCtx = data;
568 const uint32_t id_surface = getIdOfWlSurface(pCtx, pCtx->enterSurface);
569
570 if (is_controlled)
571 return;
572
573 /**
574 * During being controlled by hmi-controller, any input event is not
575 * notified. So when control ends with touch up, it invokes launcher
576 * if up event happens on a launcher surface.
577 *
578 */
579 if (launcher_button(id_surface, &pCtx->hmi_setting->launcher_list)) {
580 pCtx->is_home_on = 0;
581 ivi_hmi_controller_home(hmi_ctrl, IVI_HMI_CONTROLLER_HOME_OFF);
582 }
583}
584
585static const struct ivi_hmi_controller_listener hmi_controller_listener = {
586 ivi_hmi_controller_workspace_end_control
587};
588
589/**
590 * Registration of interfaces
591 */
592static void
593registry_handle_global(void *data, struct wl_registry *registry, uint32_t name,
594 const char *interface, uint32_t version)
595{
596 struct wlContextCommon *p_wlCtx = (struct wlContextCommon*)data;
597
598 if (!strcmp(interface, "wl_compositor")) {
599 p_wlCtx->wlCompositor =
600 wl_registry_bind(registry, name,
601 &wl_compositor_interface, 1);
602 } else if (!strcmp(interface, "wl_shm")) {
603 p_wlCtx->wlShm =
604 wl_registry_bind(registry, name, &wl_shm_interface, 1);
605 wl_shm_add_listener(p_wlCtx->wlShm, &shm_listenter, p_wlCtx);
606 } else if (!strcmp(interface, "wl_seat")) {
607 p_wlCtx->wlSeat =
608 wl_registry_bind(registry, name, &wl_seat_interface, 1);
609 wl_seat_add_listener(p_wlCtx->wlSeat, &seat_Listener, data);
610 } else if (!strcmp(interface, "ivi_application")) {
611 p_wlCtx->iviApplication =
612 wl_registry_bind(registry, name,
613 &ivi_application_interface, 1);
614 } else if (!strcmp(interface, "ivi_hmi_controller")) {
615 p_wlCtx->hmiCtrl =
616 wl_registry_bind(registry, name,
617 &ivi_hmi_controller_interface, 1);
618
619 ivi_hmi_controller_add_listener(p_wlCtx->hmiCtrl,
620 &hmi_controller_listener, p_wlCtx);
621 }
622}
623
624static void
625registry_handle_global_remove(void *data, struct wl_registry *registry,
626 uint32_t name)
627{
628}
629
630static const struct wl_registry_listener registry_listener = {
631 registry_handle_global,
632 registry_handle_global_remove
633};
634
635static void
636frame_listener_func(void *data, struct wl_callback *callback, uint32_t time)
637{
638 if (callback)
639 wl_callback_destroy(callback);
640}
641
642static const struct wl_callback_listener frame_listener = {
643 frame_listener_func
644};
645
646/*
647 * The following correspondences between file names and cursors was copied
648 * from: https://bugs.kde.org/attachment.cgi?id=67313
649 */
650static const char *bottom_left_corners[] = {
651 "bottom_left_corner",
652 "sw-resize",
653 "size_bdiag"
654};
655
656static const char *bottom_right_corners[] = {
657 "bottom_right_corner",
658 "se-resize",
659 "size_fdiag"
660};
661
662static const char *bottom_sides[] = {
663 "bottom_side",
664 "s-resize",
665 "size_ver"
666};
667
668static const char *grabbings[] = {
669 "grabbing",
670 "closedhand",
671 "208530c400c041818281048008011002"
672};
673
674static const char *left_ptrs[] = {
675 "left_ptr",
676 "default",
677 "top_left_arrow",
678 "left-arrow"
679};
680
681static const char *left_sides[] = {
682 "left_side",
683 "w-resize",
684 "size_hor"
685};
686
687static const char *right_sides[] = {
688 "right_side",
689 "e-resize",
690 "size_hor"
691};
692
693static const char *top_left_corners[] = {
694 "top_left_corner",
695 "nw-resize",
696 "size_fdiag"
697};
698
699static const char *top_right_corners[] = {
700 "top_right_corner",
701 "ne-resize",
702 "size_bdiag"
703};
704
705static const char *top_sides[] = {
706 "top_side",
707 "n-resize",
708 "size_ver"
709};
710
711static const char *xterms[] = {
712 "xterm",
713 "ibeam",
714 "text"
715};
716
717static const char *hand1s[] = {
718 "hand1",
719 "pointer",
720 "pointing_hand",
721 "e29285e634086352946a0e7090d73106"
722};
723
724static const char *watches[] = {
725 "watch",
726 "wait",
727 "0426c94ea35c87780ff01dc239897213"
728};
729
730struct cursor_alternatives {
731 const char **names;
732 size_t count;
733};
734
735static const struct cursor_alternatives cursors[] = {
736 { bottom_left_corners, ARRAY_LENGTH(bottom_left_corners) },
737 { bottom_right_corners, ARRAY_LENGTH(bottom_right_corners) },
738 { bottom_sides, ARRAY_LENGTH(bottom_sides) },
739 { grabbings, ARRAY_LENGTH(grabbings) },
740 { left_ptrs, ARRAY_LENGTH(left_ptrs) },
741 { left_sides, ARRAY_LENGTH(left_sides) },
742 { right_sides, ARRAY_LENGTH(right_sides) },
743 { top_left_corners, ARRAY_LENGTH(top_left_corners) },
744 { top_right_corners, ARRAY_LENGTH(top_right_corners) },
745 { top_sides, ARRAY_LENGTH(top_sides) },
746 { xterms, ARRAY_LENGTH(xterms) },
747 { hand1s, ARRAY_LENGTH(hand1s) },
748 { watches, ARRAY_LENGTH(watches) },
749};
750
751static void
752create_cursors(struct wlContextCommon *cmm)
753{
754 uint32_t i = 0;
755 uint32_t j = 0;
756 struct wl_cursor *cursor = NULL;
757 char *cursor_theme = cmm->hmi_setting->cursor_theme;
758 int32_t cursor_size = cmm->hmi_setting->cursor_size;
759
760 cmm->cursor_theme = wl_cursor_theme_load(cursor_theme, cursor_size,
761 cmm->wlShm);
762
763 cmm->cursors =
764 MEM_ALLOC(ARRAY_LENGTH(cursors) * sizeof(cmm->cursors[0]));
765
766 for (i = 0; i < ARRAY_LENGTH(cursors); i++) {
767 cursor = NULL;
768
769 for (j = 0; !cursor && j < cursors[i].count; ++j) {
770 cursor = wl_cursor_theme_get_cursor(
771 cmm->cursor_theme, cursors[i].names[j]);
772 }
773
774 if (!cursor) {
775 fprintf(stderr, "could not load cursor '%s'\n",
776 cursors[i].names[0]);
777 }
778
779 cmm->cursors[i] = cursor;
780 }
781}
782
783static void
784destroy_cursors(struct wlContextCommon *cmm)
785{
786 if (cmm->cursor_theme)
787 wl_cursor_theme_destroy(cmm->cursor_theme);
788
789 free(cmm->cursors);
790}
791
792/**
793 * Internal method to prepare parts of UI
794 */
795static void
796createShmBuffer(struct wlContextStruct *p_wlCtx)
797{
798 struct wl_shm_pool *pool;
799
800 int fd = -1;
801 int size = 0;
802 int width = 0;
803 int height = 0;
804 int stride = 0;
805
806 width = cairo_image_surface_get_width(p_wlCtx->ctx_image);
807 height = cairo_image_surface_get_height(p_wlCtx->ctx_image);
808 stride = cairo_image_surface_get_stride(p_wlCtx->ctx_image);
809
810 size = stride * height;
811
812 fd = os_create_anonymous_file(size);
813 if (fd < 0) {
814 fprintf(stderr, "creating a buffer file for %d B failed: %m\n",
815 size);
816 return ;
817 }
818
819 p_wlCtx->data =
820 mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
821
822 if (MAP_FAILED == p_wlCtx->data) {
823 fprintf(stderr, "mmap failed: %m\n");
824 close(fd);
825 return;
826 }
827
828 pool = wl_shm_create_pool(p_wlCtx->cmm->wlShm, fd, size);
829 p_wlCtx->wlBuffer = wl_shm_pool_create_buffer(pool, 0,
830 width,
831 height,
832 stride,
833 WL_SHM_FORMAT_ARGB8888);
834
835 if (NULL == p_wlCtx->wlBuffer) {
836 fprintf(stderr, "wl_shm_create_buffer failed: %m\n");
837 close(fd);
838 return;
839 }
840
841 wl_shm_pool_destroy(pool);
842 close(fd);
843}
844
845static void
846destroyWLContextCommon(struct wlContextCommon *p_wlCtx)
847{
848 destroy_cursors(p_wlCtx);
849
850 if (p_wlCtx->pointer_surface)
851 wl_surface_destroy(p_wlCtx->pointer_surface);
852
853 if (p_wlCtx->wlCompositor)
854 wl_compositor_destroy(p_wlCtx->wlCompositor);
855}
856
857static void
858destroyWLContextStruct(struct wlContextStruct *p_wlCtx)
859{
860 if (p_wlCtx->wlSurface)
861 wl_surface_destroy(p_wlCtx->wlSurface);
862
863 if (p_wlCtx->ctx_image) {
864 cairo_surface_destroy(p_wlCtx->ctx_image);
865 p_wlCtx->ctx_image = NULL;
866 }
867}
868
869static int
870createSurface(struct wlContextStruct *p_wlCtx)
871{
872 p_wlCtx->wlSurface =
873 wl_compositor_create_surface(p_wlCtx->cmm->wlCompositor);
874 if (NULL == p_wlCtx->wlSurface) {
875 printf("Error: wl_compositor_create_surface failed.\n");
876 destroyWLContextCommon(p_wlCtx->cmm);
877 abort();
878 }
879
880 return 0;
881}
882
883static void
884drawImage(struct wlContextStruct *p_wlCtx)
885{
886 struct wl_callback *callback;
887
888 int width = 0;
889 int height = 0;
890 int stride = 0;
891 void *data = NULL;
892
893 width = cairo_image_surface_get_width(p_wlCtx->ctx_image);
894 height = cairo_image_surface_get_height(p_wlCtx->ctx_image);
895 stride = cairo_image_surface_get_stride(p_wlCtx->ctx_image);
896 data = cairo_image_surface_get_data(p_wlCtx->ctx_image);
897
898 memcpy(p_wlCtx->data, data, stride * height);
899
900 wl_surface_attach(p_wlCtx->wlSurface, p_wlCtx->wlBuffer, 0, 0);
901 wl_surface_damage(p_wlCtx->wlSurface, 0, 0, width, height);
902
903 callback = wl_surface_frame(p_wlCtx->wlSurface);
904 wl_callback_add_listener(callback, &frame_listener, NULL);
905
906 wl_surface_commit(p_wlCtx->wlSurface);
907}
908
909static void
910create_ivisurface(struct wlContextStruct *p_wlCtx,
911 uint32_t id_surface,
912 cairo_surface_t *surface)
913{
914 struct ivi_surface *ivisurf = NULL;
915
916 p_wlCtx->ctx_image = surface;
917
918 p_wlCtx->id_surface = id_surface;
919 wl_list_init(&p_wlCtx->link);
920 wl_list_insert(&p_wlCtx->cmm->list_wlContextStruct, &p_wlCtx->link);
921
922 createSurface(p_wlCtx);
923 createShmBuffer(p_wlCtx);
924
925 ivisurf = ivi_application_surface_create(p_wlCtx->cmm->iviApplication,
926 id_surface,
927 p_wlCtx->wlSurface);
928 if (ivisurf == NULL) {
929 fprintf(stderr, "Failed to create ivi_client_surface\n");
930 return;
931 }
932
933 drawImage(p_wlCtx);
934}
935
936static void
937create_ivisurfaceFromFile(struct wlContextStruct *p_wlCtx,
938 uint32_t id_surface,
939 const char *imageFile)
940{
941 cairo_surface_t *surface = load_cairo_surface(imageFile);
942
943 if (NULL == surface) {
944 fprintf(stderr, "Failed to load_cairo_surface %s\n", imageFile);
945 return;
946 }
947
948 create_ivisurface(p_wlCtx, id_surface, surface);
949}
950
951static void
952set_hex_color(cairo_t *cr, uint32_t color)
953{
954 cairo_set_source_rgba(cr,
955 ((color >> 16) & 0xff) / 255.0,
956 ((color >> 8) & 0xff) / 255.0,
957 ((color >> 0) & 0xff) / 255.0,
958 ((color >> 24) & 0xff) / 255.0);
959}
960
961static void
962create_ivisurfaceFromColor(struct wlContextStruct *p_wlCtx,
963 uint32_t id_surface,
964 uint32_t width, uint32_t height,
965 uint32_t color)
966{
967 cairo_surface_t *surface = NULL;
968 cairo_t *cr = NULL;
969
970 surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
971 width, height);
972
973 cr = cairo_create(surface);
974 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
975 cairo_rectangle(cr, 0, 0, width, height);
976 set_hex_color(cr, color);
977 cairo_fill(cr);
978 cairo_destroy(cr);
979
980 create_ivisurface(p_wlCtx, id_surface, surface);
981}
982
983static void
984UI_ready(struct ivi_hmi_controller *controller)
985{
986 ivi_hmi_controller_UI_ready(controller);
987}
988
989/**
990 * Internal method to set up UI by using ivi-hmi-controller
991 */
992static void
993create_background(struct wlContextStruct *p_wlCtx, const uint32_t id_surface,
994 const char *imageFile)
995{
996 create_ivisurfaceFromFile(p_wlCtx, id_surface, imageFile);
997}
998
999static void
1000create_panel(struct wlContextStruct *p_wlCtx, const uint32_t id_surface,
1001 const char *imageFile)
1002{
1003 create_ivisurfaceFromFile(p_wlCtx, id_surface, imageFile);
1004}
1005
1006static void
1007create_button(struct wlContextStruct *p_wlCtx, const uint32_t id_surface,
1008 const char *imageFile, uint32_t number)
1009{
1010 create_ivisurfaceFromFile(p_wlCtx, id_surface, imageFile);
1011}
1012
1013static void
1014create_home_button(struct wlContextStruct *p_wlCtx, const uint32_t id_surface,
1015 const char *imageFile)
1016{
1017 create_ivisurfaceFromFile(p_wlCtx, id_surface, imageFile);
1018}
1019
1020static void
1021create_workspace_background(struct wlContextStruct *p_wlCtx,
1022 struct hmi_homescreen_srf *srf)
1023{
1024 create_ivisurfaceFromColor(p_wlCtx, srf->id, 1, 1, srf->color);
1025}
1026
1027static void
1028create_launchers(struct wlContextCommon *cmm, struct wl_list *launcher_list)
1029{
1030 struct hmi_homescreen_launcher **launchers;
1031 struct hmi_homescreen_launcher *launcher = NULL;
1032
1033 int launcher_count = wl_list_length(launcher_list);
1034 int ii = 0;
1035 int start = 0;
1036
1037 if (0 == launcher_count)
1038 return;
1039
1040 launchers = MEM_ALLOC(launcher_count * sizeof(*launchers));
1041
1042 wl_list_for_each(launcher, launcher_list, link) {
1043 launchers[ii] = launcher;
1044 ii++;
1045 }
1046
1047 for (ii = 0; ii < launcher_count; ii++) {
1048 int jj = 0;
1049
1050 if (ii != launcher_count - 1 &&
1051 launchers[ii]->workspace_id ==
1052 launchers[ii + 1]->workspace_id)
1053 continue;
1054
1055 for (jj = start; jj <= ii; jj++) {
1056 struct wlContextStruct *p_wlCtx;
1057
1058 p_wlCtx = MEM_ALLOC(sizeof(*p_wlCtx));
1059 p_wlCtx->cmm = cmm;
1060 create_ivisurfaceFromFile(p_wlCtx,
1061 launchers[jj]->icon_surface_id,
1062 launchers[jj]->icon);
1063 }
1064
1065 start = ii + 1;
1066 }
1067
1068 free(launchers);
1069}
1070
1071/**
1072 * Internal method to read out weston.ini to get configuration
1073 */
1074static struct hmi_homescreen_setting *
1075hmi_homescreen_setting_create(void)
1076{
Pekka Paalanen6c71aae2015-03-24 15:56:19 +02001077 const char *config_file;
Nobuhiko Tanibata923bc142014-11-27 13:23:32 +09001078 struct weston_config *config = NULL;
1079 struct weston_config_section *shellSection = NULL;
1080 struct hmi_homescreen_setting *setting = MEM_ALLOC(sizeof(*setting));
1081 struct weston_config_section *section = NULL;
1082 const char *name = NULL;
1083 uint32_t workspace_layer_id;
1084 uint32_t icon_surface_id = 0;
1085
1086 wl_list_init(&setting->workspace_list);
1087 wl_list_init(&setting->launcher_list);
1088
Pekka Paalanen6c71aae2015-03-24 15:56:19 +02001089 config_file = weston_config_get_name_from_env();
1090 config = weston_config_parse(config_file);
Nobuhiko Tanibata923bc142014-11-27 13:23:32 +09001091
1092 shellSection =
1093 weston_config_get_section(config, "ivi-shell", NULL, NULL);
1094
1095 weston_config_section_get_string(
1096 shellSection, "cursor-theme", &setting->cursor_theme, NULL);
1097
1098 weston_config_section_get_int(
1099 shellSection, "cursor-size", &setting->cursor_size, 32);
1100
1101 weston_config_section_get_uint(
1102 shellSection, "workspace-layer-id", &workspace_layer_id, 3000);
1103
1104 weston_config_section_get_string(
1105 shellSection, "background-image", &setting->background.filePath,
1106 DATADIR "/weston/background.png");
1107
1108 weston_config_section_get_uint(
1109 shellSection, "background-id", &setting->background.id, 1001);
1110
1111 weston_config_section_get_string(
1112 shellSection, "panel-image", &setting->panel.filePath,
1113 DATADIR "/weston/panel.png");
1114
1115 weston_config_section_get_uint(
1116 shellSection, "panel-id", &setting->panel.id, 1002);
1117
1118 weston_config_section_get_string(
1119 shellSection, "tiling-image", &setting->tiling.filePath,
1120 DATADIR "/weston/tiling.png");
1121
1122 weston_config_section_get_uint(
1123 shellSection, "tiling-id", &setting->tiling.id, 1003);
1124
1125 weston_config_section_get_string(
1126 shellSection, "sidebyside-image", &setting->sidebyside.filePath,
1127 DATADIR "/weston/sidebyside.png");
1128
1129 weston_config_section_get_uint(
1130 shellSection, "sidebyside-id", &setting->sidebyside.id, 1004);
1131
1132 weston_config_section_get_string(
1133 shellSection, "fullscreen-image", &setting->fullscreen.filePath,
1134 DATADIR "/weston/fullscreen.png");
1135
1136 weston_config_section_get_uint(
1137 shellSection, "fullscreen-id", &setting->fullscreen.id, 1005);
1138
1139 weston_config_section_get_string(
1140 shellSection, "random-image", &setting->random.filePath,
1141 DATADIR "/weston/random.png");
1142
1143 weston_config_section_get_uint(
1144 shellSection, "random-id", &setting->random.id, 1006);
1145
1146 weston_config_section_get_string(
1147 shellSection, "home-image", &setting->home.filePath,
1148 DATADIR "/weston/home.png");
1149
1150 weston_config_section_get_uint(
1151 shellSection, "home-id", &setting->home.id, 1007);
1152
1153 weston_config_section_get_uint(
1154 shellSection, "workspace-background-color",
1155 &setting->workspace_background.color, 0x99000000);
1156
1157 weston_config_section_get_uint(
1158 shellSection, "workspace-background-id",
1159 &setting->workspace_background.id, 2001);
1160
1161 icon_surface_id = workspace_layer_id + 1;
1162
1163 while (weston_config_next_section(config, &section, &name)) {
1164 struct hmi_homescreen_launcher *launcher;
1165
1166 if (strcmp(name, "ivi-launcher") != 0)
1167 continue;
1168
1169 launcher = MEM_ALLOC(sizeof(*launcher));
1170 wl_list_init(&launcher->link);
1171
1172 weston_config_section_get_string(section, "icon",
1173 &launcher->icon, NULL);
1174 weston_config_section_get_string(section, "path",
1175 &launcher->path, NULL);
1176 weston_config_section_get_uint(section, "workspace-id",
1177 &launcher->workspace_id, 0);
1178 weston_config_section_get_uint(section, "icon-id",
1179 &launcher->icon_surface_id,
1180 icon_surface_id);
1181 icon_surface_id++;
1182
1183 wl_list_insert(setting->launcher_list.prev, &launcher->link);
1184 }
1185
1186 weston_config_destroy(config);
1187 return setting;
1188}
1189
1190/**
1191 * Main thread
1192 *
1193 * The basic flow are as followed,
1194 * 1/ read configuration from weston.ini by hmi_homescreen_setting_create
1195 * 2/ draw png file to surface according to configuration of weston.ini and
1196 * set up UI by using ivi-hmi-controller protocol by each create_* method
1197 */
1198int main(int argc, char **argv)
1199{
1200 struct wlContextCommon wlCtxCommon;
1201 struct wlContextStruct wlCtx_BackGround;
1202 struct wlContextStruct wlCtx_Panel;
1203 struct wlContextStruct wlCtx_Button_1;
1204 struct wlContextStruct wlCtx_Button_2;
1205 struct wlContextStruct wlCtx_Button_3;
1206 struct wlContextStruct wlCtx_Button_4;
1207 struct wlContextStruct wlCtx_HomeButton;
1208 struct wlContextStruct wlCtx_WorkSpaceBackGround;
1209 struct wl_list launcher_wlCtxList;
1210 int ret = 0;
1211 struct hmi_homescreen_setting *hmi_setting;
1212 struct wlContextStruct *pWlCtxSt = NULL;
1213
1214 hmi_setting = hmi_homescreen_setting_create();
1215
1216 memset(&wlCtxCommon, 0x00, sizeof(wlCtxCommon));
1217 memset(&wlCtx_BackGround, 0x00, sizeof(wlCtx_BackGround));
1218 memset(&wlCtx_Panel, 0x00, sizeof(wlCtx_Panel));
1219 memset(&wlCtx_Button_1, 0x00, sizeof(wlCtx_Button_1));
1220 memset(&wlCtx_Button_2, 0x00, sizeof(wlCtx_Button_2));
1221 memset(&wlCtx_Button_3, 0x00, sizeof(wlCtx_Button_3));
1222 memset(&wlCtx_Button_4, 0x00, sizeof(wlCtx_Button_4));
1223 memset(&wlCtx_HomeButton, 0x00, sizeof(wlCtx_HomeButton));
1224 memset(&wlCtx_WorkSpaceBackGround, 0x00,
1225 sizeof(wlCtx_WorkSpaceBackGround));
1226 wl_list_init(&launcher_wlCtxList);
1227 wl_list_init(&wlCtxCommon.list_wlContextStruct);
1228
1229 wlCtxCommon.hmi_setting = hmi_setting;
1230
1231 wlCtxCommon.wlDisplay = wl_display_connect(NULL);
1232 if (NULL == wlCtxCommon.wlDisplay) {
1233 printf("Error: wl_display_connect failed.\n");
1234 return -1;
1235 }
1236
1237 /* get wl_registry */
1238 wlCtxCommon.formats = 0;
1239 wlCtxCommon.wlRegistry = wl_display_get_registry(wlCtxCommon.wlDisplay);
1240 wl_registry_add_listener(wlCtxCommon.wlRegistry,
1241 &registry_listener, &wlCtxCommon);
1242 wl_display_roundtrip(wlCtxCommon.wlDisplay);
1243
1244 if (wlCtxCommon.wlShm == NULL) {
1245 fprintf(stderr, "No wl_shm global\n");
1246 exit(1);
1247 }
1248
1249 wl_display_roundtrip(wlCtxCommon.wlDisplay);
1250
1251 if (!(wlCtxCommon.formats & (1 << WL_SHM_FORMAT_XRGB8888))) {
1252 fprintf(stderr, "WL_SHM_FORMAT_XRGB32 not available\n");
1253 exit(1);
1254 }
1255
1256 if (wlCtxCommon.hmi_setting->cursor_theme) {
1257 create_cursors(&wlCtxCommon);
1258
1259 wlCtxCommon.pointer_surface =
1260 wl_compositor_create_surface(wlCtxCommon.wlCompositor);
1261
1262 wlCtxCommon.current_cursor = CURSOR_LEFT_PTR;
1263 }
1264
1265 wlCtx_BackGround.cmm = &wlCtxCommon;
1266 wlCtx_Panel.cmm = &wlCtxCommon;
1267 wlCtx_Button_1.cmm = &wlCtxCommon;
1268 wlCtx_Button_2.cmm = &wlCtxCommon;
1269 wlCtx_Button_3.cmm = &wlCtxCommon;
1270 wlCtx_Button_4.cmm = &wlCtxCommon;
1271 wlCtx_HomeButton.cmm = &wlCtxCommon;
1272 wlCtx_WorkSpaceBackGround.cmm = &wlCtxCommon;
1273
1274 /* create desktop widgets */
1275 create_background(&wlCtx_BackGround, hmi_setting->background.id,
1276 hmi_setting->background.filePath);
1277
1278 create_panel(&wlCtx_Panel, hmi_setting->panel.id,
1279 hmi_setting->panel.filePath);
1280
1281 create_button(&wlCtx_Button_1, hmi_setting->tiling.id,
1282 hmi_setting->tiling.filePath, 0);
1283
1284 create_button(&wlCtx_Button_2, hmi_setting->sidebyside.id,
1285 hmi_setting->sidebyside.filePath, 1);
1286
1287 create_button(&wlCtx_Button_3, hmi_setting->fullscreen.id,
1288 hmi_setting->fullscreen.filePath, 2);
1289
1290 create_button(&wlCtx_Button_4, hmi_setting->random.id,
1291 hmi_setting->random.filePath, 3);
1292
1293 create_workspace_background(&wlCtx_WorkSpaceBackGround,
1294 &hmi_setting->workspace_background);
1295
1296 create_launchers(&wlCtxCommon, &hmi_setting->launcher_list);
1297
1298 create_home_button(&wlCtx_HomeButton, hmi_setting->home.id,
1299 hmi_setting->home.filePath);
1300
1301 UI_ready(wlCtxCommon.hmiCtrl);
1302
1303 while(ret != -1)
1304 ret = wl_display_dispatch(wlCtxCommon.wlDisplay);
1305
1306 wl_list_for_each(pWlCtxSt, &wlCtxCommon.list_wlContextStruct, link) {
1307 destroyWLContextStruct(pWlCtxSt);
1308 }
1309
1310 destroyWLContextCommon(&wlCtxCommon);
1311
1312 return 0;
1313}