impelement libds-tizen-renderer
[platform/core/uifw/libds-tizen.git] / src / renderer / renderer.c
1 #include <assert.h>
2 #include <stdint.h>
3 #include <stdlib.h>
4 #include <wayland-server.h>
5 #include <tizen-extension-server-protocol.h>
6 #include <libds/log.h>
7
8 #include "util.h"
9 #include "libds-tizen/renderer.h"
10
11 #define TIZEN_RENDERER_VERSION 1
12
13 struct ds_tizen_renderer
14 {
15     struct wl_global *global;
16
17     struct wl_list clients;
18
19     struct wl_listener destroy;
20
21     struct {
22         struct wl_signal destroy;
23         struct wl_signal get_renderer_surface;
24     } events;
25 };
26
27 struct ds_tizen_renderer_client
28 {
29     struct ds_tizen_renderer *renderer;
30
31     struct wl_resource *resource;
32     struct wl_client *wl_client;
33
34     struct wl_list infos;
35
36     struct {
37         struct wl_signal destroy;
38     } events;
39
40     struct wl_list link; // ds_tizen_renderer::clients
41 };
42
43 struct ds_tizen_renderer_info
44 {
45     struct ds_tizen_renderer_client *client;
46
47     struct wl_resource *resource;
48
49     struct ds_surface *surface;
50
51     struct wl_list link; // ds_tizen_renderer_client::infos
52 };
53
54 static void renderer_handle_display_destroy(struct wl_listener *listener,
55         void *data);
56
57 static void renderer_bind(struct wl_client *wl_client, void *data,
58         uint32_t version, uint32_t id);
59
60 static struct ds_tizen_renderer_info *tizen_renderer_client_find_info(
61     struct ds_tizen_renderer_client *client,
62     struct ds_surface *surface);
63
64 static struct ds_tizen_renderer_info *tizen_renderer_client_get_info(
65         struct ds_tizen_renderer_client *client,
66         struct ds_surface *surface);
67
68 WL_EXPORT struct ds_tizen_renderer *
69 ds_tizen_renderer_create(struct wl_display *display)
70 {
71     struct ds_tizen_renderer *renderer;
72
73     renderer = calloc(1, sizeof *renderer);
74     if (!renderer) {
75         ds_err("calloc() failed.");
76         return NULL;
77     }
78
79     renderer->global = wl_global_create(display, &tizen_renderer_interface,
80             TIZEN_RENDERER_VERSION, renderer, renderer_bind);
81     if (!renderer->global) {
82         ds_err("wl_global_create() failed. tizen_renderer_interface");
83         free(renderer);
84         return NULL;
85     }
86
87     wl_list_init(&renderer->clients);
88
89     renderer->destroy.notify = renderer_handle_display_destroy;
90     wl_display_add_destroy_listener(display, &renderer->destroy);
91
92     wl_signal_init(&renderer->events.destroy);
93     wl_signal_init(&renderer->events.get_renderer_surface);
94
95     ds_inf("Global created: tizen_renderer(%p)", renderer);
96
97     return renderer;
98 }
99
100 WL_EXPORT void
101 ds_tizen_renderer_add_destroy_listener(
102         struct ds_tizen_renderer *renderer,
103         struct wl_listener *listener)
104 {
105     wl_signal_add(&renderer->events.destroy, listener);
106 }
107
108 WL_EXPORT void
109 ds_tizen_renderer_add_get_renderer_surface_info_listener(
110         struct ds_tizen_renderer *renderer,
111         struct wl_listener *listener)
112 {
113     wl_signal_add(&renderer->events.get_renderer_surface, listener);
114 }
115
116 WL_EXPORT void
117 ds_tizen_renderer_info_add_destroy_listener(
118         struct ds_tizen_renderer_info *info,
119         struct wl_listener *listener)
120 {
121     wl_signal_add(&info->client->events.destroy, listener);
122 }
123
124 WL_EXPORT struct ds_surface *
125 ds_tizen_renderer_info_get_surface(
126         struct ds_tizen_renderer_info *info)
127 {
128     return info->surface;
129 }
130
131 WL_EXPORT void
132 ds_tizen_renderer_info_send_redraw(
133     struct ds_tizen_renderer_info *info)
134 {
135     tizen_renderer_surface_send_redraw_request(info->resource);
136 }
137
138 static struct ds_tizen_renderer_info *
139 tizen_renderer_client_find_info(struct ds_tizen_renderer_client *client,
140     struct ds_surface *surface)
141 {
142     struct ds_tizen_renderer_info *info;
143
144     wl_list_for_each(info, &client->infos, link) {
145         if (surface == info->surface)
146             return info;
147     }
148
149     return NULL;
150 }
151
152 static struct ds_tizen_renderer_info *
153 tizen_renderer_client_get_info(struct ds_tizen_renderer_client *client,
154     struct ds_surface *surface)
155 {
156     struct ds_tizen_renderer_info *info;
157
158     info = tizen_renderer_client_find_info(client, surface);
159     if (info)
160         return info;
161
162     info = calloc(1, sizeof *info);
163     if (info == NULL) {
164         ds_err("calloc() failed. tizen_renderer");
165         return NULL;
166     }
167
168     info->client = client;
169     info->surface = surface;
170
171     wl_list_insert(&client->infos, &info->link);
172
173     return info;
174 }
175
176 static void
177 renderer_handle_display_destroy(struct wl_listener *listener, void *data)
178 {
179     struct ds_tizen_renderer *renderer;
180
181     renderer = wl_container_of(listener, renderer, destroy);
182
183     ds_inf("Global destroy: renderer(%p)", renderer);
184
185     wl_signal_emit(&renderer->events.destroy, renderer);
186     wl_list_remove(&renderer->destroy.link);
187     wl_global_destroy(renderer->global);
188     free(renderer);
189 }
190
191 static void
192 renderer_surface_handle_destroy(struct wl_client *wl_client,
193     struct wl_resource *resource)
194 {
195     wl_resource_destroy(resource);
196 }
197
198 static const struct tizen_renderer_surface_interface renderer_surface_impl =
199 {
200    renderer_surface_handle_destroy,
201 };
202
203 static void
204 _tizen_renderer_info_handle_destroy(struct wl_resource *resource)
205 {
206     struct ds_tizen_renderer_info *info;
207
208     info = wl_resource_get_user_data(resource);
209
210     ds_inf("_tizen_renderer_info_handle_destroy (info:%p)", info);
211
212     wl_signal_emit(&info->client->events.destroy, info);
213     wl_list_remove(&info->link);
214     free(info);
215 }
216
217 static void
218 renderer_handle_get_renderer_surface(struct wl_client *wl_client,
219     struct wl_resource *resource,uint32_t id,
220     struct wl_resource *surface_resource)
221 {
222     struct ds_tizen_renderer_client *client;
223     struct ds_tizen_renderer_info *info;
224     struct ds_surface *surface;
225
226     ds_inf("tizen_renderer: get_renderer_surface");
227
228     client = wl_resource_get_user_data(resource);
229     surface = ds_surface_from_resource(surface_resource);
230
231     info = tizen_renderer_client_get_info(client, surface);
232     if (info == NULL) {
233         ds_err("tizen_renderer_client_get_info() failed.");
234         wl_client_post_no_memory(wl_client);
235         return;
236     }
237
238     info->resource = wl_resource_create(wl_client,
239         &tizen_renderer_surface_interface, wl_resource_get_version(resource),
240         id);
241     if (info->resource == NULL) {
242         ds_err("tizen_renderer : wl_resource_create() failed.");
243         wl_list_remove(&info->link);
244         free(info);
245         wl_client_post_no_memory(wl_client);
246         return;
247     }
248
249     wl_resource_set_implementation(info->resource, &renderer_surface_impl, info,
250         _tizen_renderer_info_handle_destroy);
251
252     wl_signal_emit(&client->renderer->events.get_renderer_surface, info);
253 }
254
255 static void
256 renderer_handle_destroy(struct wl_client *wl_client,
257     struct wl_resource *resource)
258 {
259     struct ds_tizen_renderer_client *client;
260
261     client = wl_resource_get_user_data(resource);
262
263     if (!wl_list_empty(&client->infos)) {
264         ds_err("tizen_renderer was destroyed before children");
265         return;
266     }
267
268     wl_resource_destroy(resource);
269 }
270
271 static const struct tizen_renderer_interface renderer_impl =
272 {
273    renderer_handle_get_renderer_surface,
274    renderer_handle_destroy,
275 };
276
277 static void
278 _tizen_renderer_client_handle_destroy(struct wl_resource *resource)
279 {
280     struct ds_tizen_renderer_client *client;
281     struct ds_tizen_renderer_info *info, *tmp;
282
283     client = wl_resource_get_user_data(resource);
284
285     ds_inf("_tizen_renderer_client_handle_destroy (client:%p)", client);
286
287     wl_list_for_each_safe(info, tmp, &client->infos, link) {
288         wl_signal_emit(&client->events.destroy, info);
289         wl_list_remove(&info->link);
290         free(info);
291     }
292
293     wl_list_remove(&client->link);
294     free(client);
295 }
296
297 static void
298 renderer_bind(struct wl_client *wl_client, void *data, uint32_t version,
299         uint32_t id)
300 {
301     struct ds_tizen_renderer *renderer = data;
302     struct ds_tizen_renderer_client *client;
303
304     client = calloc(1, sizeof *client);
305     if (client == NULL) {
306         ds_err("calloc() failed. tizen_renderer");
307         wl_client_post_no_memory(wl_client);
308         return;
309     }
310
311     ds_inf("tizen_renderer_client binds. (client:%p)", client);
312
313     client->renderer = renderer;
314     client->wl_client = wl_client;
315
316     wl_list_init(&client->infos);
317
318     client->resource = wl_resource_create(wl_client, &tizen_renderer_interface,
319             MIN(version, TIZEN_RENDERER_VERSION), id);
320
321     if (client->resource == NULL) {
322         ds_err("tizen_renderer : wl_resource_create() failed.");
323         free(client);
324         wl_client_post_no_memory(wl_client);
325         return;
326     }
327
328     wl_resource_set_implementation(client->resource, &renderer_impl, client,
329             _tizen_renderer_client_handle_destroy);
330
331     wl_signal_init(&client->events.destroy);
332
333     wl_list_insert(&renderer->clients, &client->link);
334 }