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