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