ilmClient: init surface_context::link on create
[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 wayland_destroy(void)
257 {
258     struct ilm_client_context *ctx = &ilm_context;
259     ctx->valid = 0;
260 }
261
262 static void
263 destroy_client_resouses(void)
264 {
265     struct ilm_client_context *ctx = &ilm_context;
266     struct screen_context *ctx_scrn = NULL;
267     struct screen_context *next = NULL;
268     wl_list_for_each_safe(ctx_scrn, next, &ctx->list_screen, link) {
269         if (ctx_scrn->output != NULL) {
270             wl_list_remove(&ctx_scrn->link);
271             wl_output_destroy(ctx_scrn->output);
272             free(ctx_scrn);
273         }
274     }
275     if (ctx->ivi_application != NULL) {
276         ivi_application_destroy(ctx->ivi_application);
277         ctx->ivi_application = NULL;
278     }
279 }
280
281 static ilmErrorTypes
282 wayland_init(t_ilm_nativedisplay nativedisplay)
283 {
284     struct ilm_client_context *ctx = &ilm_context;
285     memset(ctx, 0, sizeof *ctx);
286
287     wayland_client_init(ctx);
288     ctx->display = (struct wl_display*)nativedisplay;
289
290     return ILM_SUCCESS;
291 }
292
293 static void
294 init_client(void)
295 {
296     struct ilm_client_context *ctx = &ilm_context;
297
298     if (ctx->display == NULL) {
299         ctx->display = wl_display_connect(NULL);
300     }
301
302     ctx->num_screen = 0;
303
304     wl_list_init(&ctx->list_screen);
305     wl_list_init(&ctx->list_surface);
306
307     ctx->registry = wl_display_get_registry(ctx->display);
308     if (ctx->registry == NULL) {
309         fprintf(stderr, "Failed to get registry\n");
310         return;
311     }
312     if (wl_registry_add_listener(ctx->registry,
313                              &registry_client_listener, ctx)) {
314         fprintf(stderr, "Failed to add registry listener\n");
315         return;
316     }
317     wl_display_dispatch(ctx->display);
318     wl_display_roundtrip(ctx->display);
319
320     if ((ctx->display == NULL) || (ctx->ivi_application == NULL)) {
321         fprintf(stderr, "Failed to connect display at ilm_client\n");
322         return;
323     }
324     ctx->valid = 1;
325 }
326
327 static struct ilm_client_context*
328 get_client_instance(void)
329 {
330     struct ilm_client_context *ctx = &ilm_context;
331     if (ctx->valid == 0) {
332         init_client();
333     }
334
335     if (ctx->valid < 0) {
336         exit(0);
337     }
338
339     wl_display_roundtrip(ctx->display);
340
341     return ctx;
342 }
343
344 static void
345 create_client_surface(struct ilm_client_context *ctx,
346                       uint32_t id_surface,
347                       struct ivi_surface *surface)
348 {
349     struct surface_context *ctx_surf = NULL;
350
351     ctx_surf = calloc(1, sizeof *ctx_surf);
352     if (ctx_surf == NULL) {
353         fprintf(stderr, "Failed to allocate memory for surface_context\n");
354         return;
355     }
356
357     ctx_surf->surface = surface;
358     ctx_surf->id_surface = id_surface;
359     wl_list_init(&ctx_surf->link);
360     wl_list_insert(&ctx->list_surface, &ctx_surf->link);
361 }
362
363 static struct surface_context*
364 get_surface_context_by_id(struct ilm_client_context *ctx,
365                           uint32_t id_surface)
366 {
367     struct surface_context *ctx_surf = NULL;
368
369     wl_list_for_each(ctx_surf, &ctx->list_surface, link) {
370         if (ctx_surf->id_surface == id_surface) {
371             return ctx_surf;
372         }
373     }
374
375     return NULL;
376 }
377
378 static ilmErrorTypes
379 wayland_getScreenResolution(t_ilm_uint screenID,
380                             t_ilm_uint* pWidth,
381                             t_ilm_uint* pHeight)
382 {
383     ilmErrorTypes returnValue = ILM_FAILED;
384     struct ilm_client_context *ctx = get_client_instance();
385
386     if ((pWidth != NULL) && (pHeight != NULL))
387     {
388         struct screen_context *ctx_scrn;
389         wl_list_for_each(ctx_scrn, &ctx->list_screen, link) {
390             if (screenID == ctx_scrn->id_screen) {
391                 *pWidth = ctx_scrn->width;
392                 *pHeight = ctx_scrn->height;
393                 returnValue = ILM_SUCCESS;
394                 break;
395             }
396         }
397     }
398
399     return returnValue;
400 }
401
402 static ilmErrorTypes
403 wayland_surfaceCreate(t_ilm_nativehandle nativehandle,
404                       t_ilm_int width,
405                       t_ilm_int height,
406                       ilmPixelFormat pixelFormat,
407                       t_ilm_surface* pSurfaceId)
408 {
409     ilmErrorTypes returnValue = ILM_FAILED;
410     struct ilm_client_context *ctx = get_client_instance();
411     uint32_t surfaceid = 0;
412     struct ivi_surface *surf = NULL;
413     (void)pixelFormat;
414     (void)width;
415     (void)height;
416
417     if (nativehandle == 0) {
418         return returnValue;
419     }
420
421     if (pSurfaceId != NULL) {
422         if (*pSurfaceId == INVALID_ID) {
423             surfaceid =
424                 wayland_client_gen_surface_id(ctx);
425         }
426         else {
427             surfaceid = *pSurfaceId;
428         }
429
430         surf = ivi_application_surface_create(ctx->ivi_application, surfaceid,
431                                          (struct wl_surface*)nativehandle);
432
433         if (surf != NULL) {
434             create_client_surface(ctx, surfaceid, surf);
435             *pSurfaceId = surfaceid;
436             returnValue = ILM_SUCCESS;
437         }
438         else {
439             fprintf(stderr, "Failed to create ivi_surface\n");
440         }
441     }
442
443     return returnValue;
444 }
445
446 static ilmErrorTypes
447 wayland_surfaceRemove(t_ilm_surface surfaceId)
448 {
449     struct ilm_client_context *ctx = get_client_instance();
450     struct surface_context *ctx_surf = NULL;
451     struct surface_context *ctx_next = NULL;
452
453     wl_list_for_each_safe(ctx_surf, ctx_next,
454                           &ctx->list_surface,
455                           link) {
456         if (ctx_surf->id_surface == surfaceId) {
457             ivi_surface_destroy(ctx_surf->surface);
458             wl_list_remove(&ctx_surf->link);
459             free(ctx_surf);
460             break;
461         }
462     }
463
464     return ILM_SUCCESS;
465 }
466
467 static ilmErrorTypes
468 wayland_surfaceRemoveNativeContent(t_ilm_surface surfaceId)
469 {
470     (void)surfaceId;
471
472     /* There is no API to set native content
473         as such ivi_surface_set_native. */
474     return ILM_FAILED;
475 }
476
477 static ilmErrorTypes
478 wayland_surfaceSetNativeContent(t_ilm_nativehandle nativehandle,
479                                 t_ilm_int width,
480                                 t_ilm_int height,
481                                 ilmPixelFormat pixelFormat,
482                                 t_ilm_surface surfaceId)
483 {
484     (void)nativehandle;
485     (void)width;
486     (void)height;
487     (void)pixelFormat;
488     (void)surfaceId;
489
490     /* There is no API to set native content
491         as such ivi_surface_set_native. */
492     return ILM_FAILED;
493 }
494
495 static ilmErrorTypes
496 wayland_UpdateInputEventAcceptanceOn(t_ilm_surface surfaceId,
497                                      ilmInputDevice devices,
498                                      t_ilm_bool acceptance)
499 {
500     ilmErrorTypes returnValue = ILM_FAILED;
501     struct ilm_client_context *ctx = get_client_instance();
502     struct surface_context *ctx_surf = NULL;
503
504     ctx_surf = get_surface_context_by_id(ctx, (uint32_t)surfaceId);
505
506     if (ctx_surf != NULL) {
507         if (acceptance == ILM_TRUE) {
508             ctx_surf->prop.inputDevicesAcceptance = devices;
509         } else {
510             ctx_surf->prop.inputDevicesAcceptance &= ~devices;
511         }
512         returnValue = ILM_SUCCESS;
513     }
514
515     return returnValue;
516 }
517
518 static ilmErrorTypes
519 wayland_surfaceInitialize(t_ilm_surface *pSurfaceId)
520 {
521     ilmErrorTypes returnValue = ILM_FAILED;
522
523     returnValue = wayland_surfaceCreate((t_ilm_nativehandle)NULL,
524                                         100, 100, (ilmPixelFormat)NULL,
525                                         (t_ilm_surface*)pSurfaceId);
526     return returnValue;
527 }