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