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