ilmClient: free resources after use
[profile/ivi/wayland-ivi-extension.git] / ivi-layermanagement-api / ilmClient / src / ilm_client_wayland_platform.c
1 /**************************************************************************
2  *
3  * Copyright (C) 2013 DENSO CORPORATION
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *        http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  ****************************************************************************/
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <memory.h>
22 #include <unistd.h>
23 #include <signal.h>
24 #include <poll.h>
25 #include "ilm_client.h"
26 #include "ilm_client_platform.h"
27 #include "wayland-util.h"
28 #include "ivi-application-client-protocol.h"
29
30 static ilmErrorTypes wayland_getScreenResolution(t_ilm_uint screenID,
31                          t_ilm_uint* pWidth, t_ilm_uint* pHeight);
32 static ilmErrorTypes wayland_surfaceCreate(t_ilm_nativehandle nativehandle,
33                          t_ilm_int width, t_ilm_int height,
34                          ilmPixelFormat pixelFormat,
35                          t_ilm_surface* pSurfaceId);
36 static ilmErrorTypes wayland_surfaceRemove(const t_ilm_surface surfaceId);
37 static ilmErrorTypes wayland_surfaceRemoveNativeContent(
38                          t_ilm_surface surfaceId);
39 static ilmErrorTypes wayland_surfaceSetNativeContent(
40                          t_ilm_nativehandle nativehandle,
41                          t_ilm_int width, t_ilm_int height,
42                          ilmPixelFormat pixelFormat,
43                          t_ilm_surface surfaceId);
44 static ilmErrorTypes wayland_UpdateInputEventAcceptanceOn(
45                          t_ilm_surface surfaceId,
46                          ilmInputDevice devices,
47                          t_ilm_bool acceptance);
48 static ilmErrorTypes wayland_init(t_ilm_nativedisplay nativedisplay);
49 static void wayland_destroy(void);
50 static ilmErrorTypes wayland_surfaceInitialize(t_ilm_surface *pSurfaceId);
51
52 void init_ilmClientPlatformTable(void)
53 {
54     gIlmClientPlatformFunc.getScreenResolution =
55         wayland_getScreenResolution;
56     gIlmClientPlatformFunc.surfaceCreate =
57         wayland_surfaceCreate;
58     gIlmClientPlatformFunc.surfaceRemove =
59         wayland_surfaceRemove;
60     gIlmClientPlatformFunc.surfaceRemoveNativeContent =
61         wayland_surfaceRemoveNativeContent;
62     gIlmClientPlatformFunc.surfaceSetNativeContent =
63         wayland_surfaceSetNativeContent;
64     gIlmClientPlatformFunc.UpdateInputEventAcceptanceOn =
65         wayland_UpdateInputEventAcceptanceOn;
66     gIlmClientPlatformFunc.init =
67         wayland_init;
68     gIlmClientPlatformFunc.destroy =
69         wayland_destroy;
70     gIlmClientPlatformFunc.surfaceInitialize =
71         wayland_surfaceInitialize;
72 }
73
74 struct surface_context {
75     struct ivi_surface *surface;
76     t_ilm_uint id_surface;
77     struct ilmSurfaceProperties prop;
78
79     struct wl_list link;
80 };
81
82 struct screen_context {
83     struct wl_output *output;
84     t_ilm_uint id_screen;
85
86     uint32_t width;
87     uint32_t height;
88
89     struct wl_list link;
90 };
91
92 struct ilm_client_context {
93     int32_t valid;
94     struct wl_display *display;
95     struct wl_registry *registry;
96     struct wl_compositor *compositor;
97     struct ivi_application *ivi_application;
98
99     int32_t num_screen;
100     struct wl_list list_surface;
101     struct wl_list list_screen;
102
103     uint32_t internal_id_surface;
104     uint32_t name_controller;
105 };
106
107 static void
108 wayland_client_init(struct ilm_client_context *ctx)
109 {
110     ctx->internal_id_surface = 0;
111 }
112
113 static uint32_t
114 wayland_client_gen_surface_id(struct ilm_client_context *ctx)
115 {
116     struct surface_context *ctx_surf = NULL;
117     do {
118         int found = 0;
119         if (wl_list_length(&ctx->list_surface) == 0) {
120             ctx->internal_id_surface++;
121             return ctx->internal_id_surface;
122         }
123         wl_list_for_each(ctx_surf, &ctx->list_surface, link) {
124             if (ctx_surf->id_surface == ctx->internal_id_surface) {
125                 found = 1;
126                 break;
127             }
128
129             if (found == 0) {
130                 return ctx->internal_id_surface;
131             }
132         }
133         ctx->internal_id_surface++;
134     } while(1);
135 }
136
137 static void
138 output_listener_geometry(void *data,
139                          struct wl_output *wl_output,
140                          int32_t x,
141                          int32_t y,
142                          int32_t physical_width,
143                          int32_t physical_height,
144                          int32_t subpixel,
145                          const char *make,
146                          const char *model,
147                          int32_t transform)
148 {
149     struct screen_context *ctx_scrn = data;
150     (void)wl_output;
151     (void)x;
152     (void)y;
153     (void)subpixel;
154     (void)make;
155     (void)model;
156     (void)transform;
157
158     ctx_scrn->width = physical_width;
159     ctx_scrn->height = physical_height;
160 }
161
162 static void
163 output_listener_mode(void *data,
164                      struct wl_output *wl_output,
165                      uint32_t flags,
166                      int32_t width,
167                      int32_t height,
168                      int32_t refresh)
169 {
170     (void)data;
171     (void)wl_output;
172     (void)flags;
173     (void)width;
174     (void)height;
175     (void)refresh;
176 }
177
178 static void
179 output_listener_done(void *data,
180                      struct wl_output *output)
181 {
182     (void)data;
183     (void)output;
184 }
185
186 static void
187 output_listener_scale(void *data,
188                       struct wl_output *output,
189                       int32_t factor)
190 {
191     (void)data;
192     (void)output;
193     (void)factor;
194 }
195
196 static struct
197 wl_output_listener output_listener = {
198     output_listener_geometry,
199     output_listener_mode,
200     output_listener_done,
201     output_listener_scale
202 };
203
204 static void
205 registry_handle_client(void *data, struct wl_registry *registry,
206                        uint32_t name, const char *interface,
207                        uint32_t version)
208 {
209     struct ilm_client_context *ctx = data;
210     (void)version;
211
212     if (strcmp(interface, "ivi_application") == 0) {
213         ctx->ivi_application = wl_registry_bind(registry, name,
214                                            &ivi_application_interface, 1);
215         if (ctx->ivi_application == NULL) {
216             fprintf(stderr, "Failed to registry bind ivi_application\n");
217             return;
218         }
219     } else if (strcmp(interface, "wl_output") == 0) {
220         struct screen_context *ctx_scrn = calloc(1, sizeof *ctx_scrn);
221         if (ctx_scrn == NULL) {
222             fprintf(stderr, "Failed to allocate memory for screen_context\n");
223             return;
224         }
225         wl_list_init(&ctx_scrn->link);
226         ctx_scrn->output = wl_registry_bind(registry, name,
227                                            &wl_output_interface, 1);
228         if (ctx_scrn->output == NULL) {
229             free(ctx_scrn);
230             fprintf(stderr, "Failed to registry bind wl_output\n");
231             return;
232         }
233
234         if (wl_output_add_listener(ctx_scrn->output,
235                                    &output_listener,
236                                    ctx_scrn)) {
237             free(ctx_scrn);
238             fprintf(stderr, "Failed to add wl_output listener\n");
239             return;
240         }
241
242         ctx_scrn->id_screen = ctx->num_screen;
243         ctx->num_screen++;
244         wl_list_insert(&ctx->list_screen, &ctx_scrn->link);
245     }
246 }
247
248 static const struct wl_registry_listener registry_client_listener = {
249     registry_handle_client,
250     NULL
251 };
252
253 static struct ilm_client_context ilm_context = {0};
254
255 static void
256 destroy_client_resouses(void);
257
258 static void
259 wayland_destroy(void)
260 {
261     struct ilm_client_context *ctx = &ilm_context;
262     if (ctx->valid)
263     {
264         destroy_client_resouses();
265         ctx->valid = 0;
266     }
267 }
268
269 static void
270 destroy_client_resouses(void)
271 {
272     struct ilm_client_context *ctx = &ilm_context;
273
274     {
275         struct surface_context *c = NULL;
276         struct surface_context *n = NULL;
277         wl_list_for_each_safe(c, n, &ctx->list_surface, link) {
278             wl_list_remove(&c->link);
279             ivi_surface_destroy(c->surface);
280             free(c);
281         }
282     }
283
284     {
285         struct screen_context *ctx_scrn = NULL;
286         struct screen_context *next = NULL;
287         wl_list_for_each_safe(ctx_scrn, next, &ctx->list_screen, link) {
288             if (ctx_scrn->output != NULL) {
289                 wl_output_destroy(ctx_scrn->output);
290             }
291
292             wl_list_remove(&ctx_scrn->link);
293             free(ctx_scrn);
294         }
295     }
296
297     if (ctx->ivi_application != NULL) {
298         ivi_application_destroy(ctx->ivi_application);
299         ctx->ivi_application = NULL;
300     }
301
302     if (ctx->registry)
303     {
304         wl_registry_destroy(ctx->registry);
305         ctx->registry = NULL;
306     }
307 }
308
309 static ilmErrorTypes
310 wayland_init(t_ilm_nativedisplay nativedisplay)
311 {
312     struct ilm_client_context *ctx = &ilm_context;
313     memset(ctx, 0, sizeof *ctx);
314
315     wayland_client_init(ctx);
316     ctx->display = (struct wl_display*)nativedisplay;
317
318     return ILM_SUCCESS;
319 }
320
321 static void
322 init_client(void)
323 {
324     struct ilm_client_context *ctx = &ilm_context;
325
326     if (ctx->display == NULL) {
327         ctx->display = wl_display_connect(NULL);
328     }
329
330     ctx->num_screen = 0;
331
332     wl_list_init(&ctx->list_screen);
333     wl_list_init(&ctx->list_surface);
334
335     ctx->registry = wl_display_get_registry(ctx->display);
336     if (ctx->registry == NULL) {
337         fprintf(stderr, "Failed to get registry\n");
338         return;
339     }
340     if (wl_registry_add_listener(ctx->registry,
341                              &registry_client_listener, ctx)) {
342         fprintf(stderr, "Failed to add registry listener\n");
343         return;
344     }
345     wl_display_dispatch(ctx->display);
346     wl_display_roundtrip(ctx->display);
347
348     if ((ctx->display == NULL) || (ctx->ivi_application == NULL)) {
349         fprintf(stderr, "Failed to connect display at ilm_client\n");
350         return;
351     }
352     ctx->valid = 1;
353 }
354
355 static struct ilm_client_context*
356 get_client_instance(void)
357 {
358     struct ilm_client_context *ctx = &ilm_context;
359     if (ctx->valid == 0) {
360         init_client();
361     }
362
363     if (ctx->valid < 0) {
364         exit(0);
365     }
366
367     wl_display_roundtrip(ctx->display);
368
369     return ctx;
370 }
371
372 static void
373 create_client_surface(struct ilm_client_context *ctx,
374                       uint32_t id_surface,
375                       struct ivi_surface *surface)
376 {
377     struct surface_context *ctx_surf = NULL;
378
379     ctx_surf = calloc(1, sizeof *ctx_surf);
380     if (ctx_surf == NULL) {
381         fprintf(stderr, "Failed to allocate memory for surface_context\n");
382         return;
383     }
384
385     ctx_surf->surface = surface;
386     ctx_surf->id_surface = id_surface;
387     wl_list_init(&ctx_surf->link);
388     wl_list_insert(&ctx->list_surface, &ctx_surf->link);
389 }
390
391 static struct surface_context*
392 get_surface_context_by_id(struct ilm_client_context *ctx,
393                           uint32_t id_surface)
394 {
395     struct surface_context *ctx_surf = NULL;
396
397     wl_list_for_each(ctx_surf, &ctx->list_surface, link) {
398         if (ctx_surf->id_surface == id_surface) {
399             return ctx_surf;
400         }
401     }
402
403     return NULL;
404 }
405
406 static ilmErrorTypes
407 wayland_getScreenResolution(t_ilm_uint screenID,
408                             t_ilm_uint* pWidth,
409                             t_ilm_uint* pHeight)
410 {
411     ilmErrorTypes returnValue = ILM_FAILED;
412     struct ilm_client_context *ctx = get_client_instance();
413
414     if ((pWidth != NULL) && (pHeight != NULL))
415     {
416         struct screen_context *ctx_scrn;
417         wl_list_for_each(ctx_scrn, &ctx->list_screen, link) {
418             if (screenID == ctx_scrn->id_screen) {
419                 *pWidth = ctx_scrn->width;
420                 *pHeight = ctx_scrn->height;
421                 returnValue = ILM_SUCCESS;
422                 break;
423             }
424         }
425     }
426
427     return returnValue;
428 }
429
430 static ilmErrorTypes
431 wayland_surfaceCreate(t_ilm_nativehandle nativehandle,
432                       t_ilm_int width,
433                       t_ilm_int height,
434                       ilmPixelFormat pixelFormat,
435                       t_ilm_surface* pSurfaceId)
436 {
437     ilmErrorTypes returnValue = ILM_FAILED;
438     struct ilm_client_context *ctx = get_client_instance();
439     uint32_t surfaceid = 0;
440     struct ivi_surface *surf = NULL;
441     (void)pixelFormat;
442     (void)width;
443     (void)height;
444
445     if (nativehandle == 0) {
446         return returnValue;
447     }
448
449     if (pSurfaceId != NULL) {
450         if (*pSurfaceId == INVALID_ID) {
451             surfaceid =
452                 wayland_client_gen_surface_id(ctx);
453         }
454         else {
455             surfaceid = *pSurfaceId;
456         }
457
458         surf = ivi_application_surface_create(ctx->ivi_application, surfaceid,
459                                          (struct wl_surface*)nativehandle);
460
461         if (surf != NULL) {
462             create_client_surface(ctx, surfaceid, surf);
463             *pSurfaceId = surfaceid;
464             returnValue = ILM_SUCCESS;
465         }
466         else {
467             fprintf(stderr, "Failed to create ivi_surface\n");
468         }
469     }
470
471     return returnValue;
472 }
473
474 static ilmErrorTypes
475 wayland_surfaceRemove(t_ilm_surface surfaceId)
476 {
477     struct ilm_client_context *ctx = get_client_instance();
478     struct surface_context *ctx_surf = NULL;
479     struct surface_context *ctx_next = NULL;
480
481     wl_list_for_each_safe(ctx_surf, ctx_next,
482                           &ctx->list_surface,
483                           link) {
484         if (ctx_surf->id_surface == surfaceId) {
485             ivi_surface_destroy(ctx_surf->surface);
486             wl_list_remove(&ctx_surf->link);
487             free(ctx_surf);
488             break;
489         }
490     }
491
492     return ILM_SUCCESS;
493 }
494
495 static ilmErrorTypes
496 wayland_surfaceRemoveNativeContent(t_ilm_surface surfaceId)
497 {
498     (void)surfaceId;
499
500     /* There is no API to set native content
501         as such ivi_surface_set_native. */
502     return ILM_FAILED;
503 }
504
505 static ilmErrorTypes
506 wayland_surfaceSetNativeContent(t_ilm_nativehandle nativehandle,
507                                 t_ilm_int width,
508                                 t_ilm_int height,
509                                 ilmPixelFormat pixelFormat,
510                                 t_ilm_surface surfaceId)
511 {
512     (void)nativehandle;
513     (void)width;
514     (void)height;
515     (void)pixelFormat;
516     (void)surfaceId;
517
518     /* There is no API to set native content
519         as such ivi_surface_set_native. */
520     return ILM_FAILED;
521 }
522
523 static ilmErrorTypes
524 wayland_UpdateInputEventAcceptanceOn(t_ilm_surface surfaceId,
525                                      ilmInputDevice devices,
526                                      t_ilm_bool acceptance)
527 {
528     ilmErrorTypes returnValue = ILM_FAILED;
529     struct ilm_client_context *ctx = get_client_instance();
530     struct surface_context *ctx_surf = NULL;
531
532     ctx_surf = get_surface_context_by_id(ctx, (uint32_t)surfaceId);
533
534     if (ctx_surf != NULL) {
535         if (acceptance == ILM_TRUE) {
536             ctx_surf->prop.inputDevicesAcceptance = devices;
537         } else {
538             ctx_surf->prop.inputDevicesAcceptance &= ~devices;
539         }
540         returnValue = ILM_SUCCESS;
541     }
542
543     return returnValue;
544 }
545
546 static ilmErrorTypes
547 wayland_surfaceInitialize(t_ilm_surface *pSurfaceId)
548 {
549     ilmErrorTypes returnValue = ILM_FAILED;
550
551     returnValue = wayland_surfaceCreate((t_ilm_nativehandle)NULL,
552                                         100, 100, (ilmPixelFormat)NULL,
553                                         (t_ilm_surface*)pSurfaceId);
554     return returnValue;
555 }