Revert "screen: add wtz_screen_set_opaque_region request callback"
[platform/core/uifw/libds-tizen.git] / src / blender / blender.c
1 #include <assert.h>
2 #include <stdint.h>
3 #include <stdlib.h>
4 #include <wayland-server.h>
5 #include <tizen-surface-server-protocol.h>
6 #include <wtz-blender-server-protocol.h>
7 #include <libds/log.h>
8 #include <libds/util/addon.h>
9 #include <libds/types/ds_surface.h>
10
11 #include "util.h"
12 #include "libds-tizen/blender.h"
13
14 #define TIZEN_BLENDER_VERSION 1
15
16 struct ds_tizen_blender
17 {
18     struct wl_global *global;
19
20     struct wl_list clients;
21
22     struct wl_listener destroy;
23
24     struct {
25         struct wl_signal destroy;
26         struct wl_signal new_blend;
27     } events;
28 };
29
30 struct ds_tizen_blender_client
31 {
32     struct wl_list link; //clients
33
34     struct ds_tizen_blender *blender;
35
36     struct wl_resource *resource;
37     struct wl_client *wl_client;
38
39     struct {
40         struct wl_signal destroy;
41     } events;
42 };
43
44 struct ds_tizen_blend
45 {
46     struct wl_resource *resource;
47     struct wl_client *wl_client;
48
49     struct ds_tizen_blend_state current, pending;
50
51     struct ds_surface *surface;
52     struct ds_addon surface_addon;
53
54     struct {
55         struct wl_listener surface_commit;
56     } listener;
57
58     struct {
59         struct wl_signal commit;
60         struct wl_signal destroy;
61     } events;
62 };
63
64 static void
65 blender_handle_display_destroy(struct wl_listener *listener, void *data);
66 static void
67 blender_bind(struct wl_client *wl_client, void *data, uint32_t version,
68         uint32_t id);
69
70 WL_EXPORT struct ds_tizen_blender *
71 ds_tizen_blender_create(struct wl_display *display)
72 {
73     struct ds_tizen_blender *blender;
74
75     blender = calloc(1, sizeof *blender);
76     if (!blender) {
77         ds_err("calloc() failed.");
78         return NULL;
79     }
80
81     blender->global = wl_global_create(display, &wtz_blender_interface,
82             TIZEN_BLENDER_VERSION, blender, blender_bind);
83     if (!blender->global) {
84         ds_err("wl_global_create() failed. tizen_surface_shm_interface");
85         free(blender);
86         return NULL;
87     }
88
89     wl_list_init(&blender->clients);
90
91     blender->destroy.notify = blender_handle_display_destroy;
92     wl_display_add_destroy_listener(display, &blender->destroy);
93
94     wl_signal_init(&blender->events.destroy);
95     wl_signal_init(&blender->events.new_blend);
96
97     ds_inf("Global created: tizen_blender(%p)", blender);
98
99     return blender;
100 }
101
102 WL_EXPORT void
103 ds_tizen_blender_add_destroy_listener(struct ds_tizen_blender *blender,
104         struct wl_listener *listener)
105 {
106     wl_signal_add(&blender->events.destroy, listener);
107 }
108
109 WL_EXPORT void
110 ds_tizen_blender_add_new_blend_listener(struct ds_tizen_blender *blender,
111         struct wl_listener *listener)
112 {
113     wl_signal_add(&blender->events.new_blend, listener);
114 }
115
116 WL_EXPORT void
117 ds_tizen_blend_add_destroy_listener(struct ds_tizen_blend *blend,
118         struct wl_listener *listener)
119 {
120     wl_signal_add(&blend->events.destroy, listener);
121 }
122
123 WL_EXPORT void
124 ds_tizen_blend_add_commit_listener(struct ds_tizen_blend *blend,
125         struct wl_listener *listener)
126 {
127     wl_signal_add(&blend->events.commit, listener);
128 }
129
130 WL_EXPORT struct ds_surface *
131 ds_tizen_blend_get_surface(struct ds_tizen_blend *blend)
132 {
133     return blend->surface;
134 }
135
136 WL_EXPORT struct ds_tizen_blend_state *
137 ds_tizen_blend_get_state(struct ds_tizen_blend *blend)
138 {
139     return &blend->current;
140 }
141
142 static void
143 blender_handle_display_destroy(struct wl_listener *listener, void *data)
144 {
145     struct ds_tizen_blender *blender;
146
147     blender = wl_container_of(listener, blender, destroy);
148
149     ds_inf("Global destroy: blender(%p)", blender);
150
151     wl_signal_emit_mutable(&blender->events.destroy, blender);
152     wl_list_remove(&blender->destroy.link);
153     wl_global_destroy(blender->global);
154     free(blender);
155 }
156
157 static void
158 blend_handle_destroy(struct wl_client *client, struct wl_resource *resource)
159 {
160     wl_resource_destroy(resource);
161 }
162
163 static void
164 blend_handle_set_alpha(struct wl_client *client, struct wl_resource *resource,
165         uint32_t alpha)
166 {
167     struct ds_tizen_blend *blend;
168
169     blend = wl_resource_get_user_data(resource);
170
171     blend->pending.alpha = alpha;
172     blend->pending.committed |= DS_TIZEN_BLEND_STATE_ALPHA;
173 }
174
175 static void
176 blend_handle_set_equation(struct wl_client *client, struct wl_resource *resource,
177         uint32_t equation)
178 {
179     struct ds_tizen_blend *blend;
180
181     blend = wl_resource_get_user_data(resource);
182
183     blend->pending.equation = equation;
184     blend->pending.committed |= DS_TIZEN_BLEND_STATE_EQUATION;
185 }
186
187 static const struct wtz_blend_interface blend_impl = {
188    blend_handle_destroy,
189    blend_handle_set_alpha,
190    blend_handle_set_equation,
191 };
192
193 static void
194 blend_destroy(struct ds_tizen_blend *blend)
195 {
196     ds_inf("blend_destroy (blend:%p)", blend);
197
198     wl_signal_emit_mutable(&blend->events.destroy, blend);
199
200     if (blend->listener.surface_commit.notify)
201         wl_list_remove(&blend->listener.surface_commit.link);
202
203     if (blend->surface)
204         ds_addon_finish(&blend->surface_addon);
205
206     free(blend);
207 }
208
209 static void
210 blend_handle_resource_destroy(struct wl_resource *resource)
211 {
212     struct ds_tizen_blend *blend;
213
214     blend = wl_resource_get_user_data(resource);
215
216     ds_inf("blend_handle_resource_destroy (blend:%p)", blend);
217
218     if (blend->surface) {
219         blend->resource = NULL;
220         return;
221     }
222
223     blend_destroy(blend);
224 }
225
226 static void
227 blend_handle_surface_commit(struct wl_listener *listener, void *data)
228 {
229     struct ds_tizen_blend *blend;
230
231     blend = wl_container_of(listener, blend, listener.surface_commit);
232
233     if (!blend->resource) {
234         blend_destroy(blend);
235         return;
236     }
237
238     if (blend->pending.committed == DS_TIZEN_BLEND_STATE_NONE) {
239         blend->current.committed = DS_TIZEN_BLEND_STATE_NONE;
240         return;
241     }
242
243     if (blend->pending.committed & DS_TIZEN_BLEND_STATE_ALPHA)
244         blend->current.alpha = blend->pending.alpha;
245
246     if (blend->pending.committed & DS_TIZEN_BLEND_STATE_EQUATION)
247         blend->current.equation = blend->pending.equation;
248
249     blend->current.committed = blend->pending.committed;
250     blend->pending.committed = DS_TIZEN_BLEND_STATE_NONE;
251
252     wl_signal_emit_mutable(&blend->events.commit, blend);
253 }
254
255 static void
256 blend_handle_surface_destroy(struct ds_addon *addon)
257 {
258     struct ds_tizen_blend *blend;
259
260     blend = wl_container_of(addon, blend, surface_addon);
261
262     if (blend->listener.surface_commit.notify) {
263         wl_list_remove(&blend->listener.surface_commit.link);
264         blend->listener.surface_commit.notify = NULL;
265     }
266
267     ds_addon_finish(&blend->surface_addon);
268     blend->surface = NULL;
269
270     if (!blend->resource)
271         blend_destroy(blend);
272 }
273
274 static struct ds_addon_interface blend_addon_impl = {
275         .name = "ds_tizen_blend",
276         .destroy = blend_handle_surface_destroy,
277 };
278
279 static struct ds_tizen_blend *
280 blend_client_get_from_surface(struct ds_tizen_blender_client *client, struct ds_surface *surface)
281 {
282    struct ds_addon *addon;
283    struct ds_tizen_blend *blend;
284
285     addon = ds_addon_find(&surface->addons, client, &blend_addon_impl);
286     if (!addon) return NULL;
287
288     blend = wl_container_of(addon, blend, surface_addon);
289
290     return blend;
291 }
292
293 static void
294 blender_handle_get_blend(struct wl_client *wl_client,
295         struct wl_resource *resource,
296         uint32_t id, struct wl_resource *surface_resource)
297 {
298     struct ds_tizen_blender_client *client;
299     struct ds_surface *surface;
300     struct ds_tizen_blend *blend;
301
302     ds_inf("tizen_blender: get_blend");
303
304     client = wl_resource_get_user_data(resource);
305
306     surface = ds_surface_from_resource(surface_resource);
307     if (!surface) {
308         wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
309                 "invalid wl_surface resource:%u",
310                 (unsigned int)wl_resource_get_id(surface_resource));
311         return;
312     }
313
314     blend = blend_client_get_from_surface(client, surface);
315     if (blend) {
316         wl_resource_post_error(resource, WTZ_BLENDER_ERROR_BLEND_EXISTS,
317                 "blend object already exists");
318         return;
319     }
320
321     blend = calloc(1, sizeof *blend);
322     if (blend == NULL) {
323         ds_err("calloc() failed. tizen_blend");
324         wl_client_post_no_memory(wl_client);
325         return;
326     }
327
328     blend->resource = wl_resource_create(wl_client, &wtz_blend_interface,
329            wl_resource_get_version(resource), id);
330     if (blend->resource == NULL) {
331         ds_err("tizen_blend : wl_resource_create() failed.");
332         free(blend);
333         wl_client_post_no_memory(wl_client);
334         return;
335     }
336
337     wl_resource_set_implementation(blend->resource, &blend_impl, blend,
338         blend_handle_resource_destroy);
339
340     ds_addon_init(&blend->surface_addon, &surface->addons, client, &blend_addon_impl);
341
342     blend->listener.surface_commit.notify = blend_handle_surface_commit;
343     ds_surface_add_commit_listener(surface, &blend->listener.surface_commit);
344
345     blend->surface = surface;
346
347     wl_signal_init(&blend->events.destroy);
348     wl_signal_init(&blend->events.commit);
349
350     wl_signal_emit_mutable(&client->blender->events.new_blend, blend);
351 }
352
353 static void
354 blender_handle_destroy(struct wl_client *wl_client,
355         struct wl_resource *resource)
356 {
357     wl_resource_destroy(resource);
358 }
359
360 static const struct wtz_blender_interface blender_impl =
361 {
362     blender_handle_destroy,
363     blender_handle_get_blend,
364 };
365
366 static void
367 blender_client_handle_destroy(struct wl_resource *resource)
368 {
369     struct ds_tizen_blender_client *client;
370
371     client = wl_resource_get_user_data(resource);
372
373     ds_inf("blender_client_handle_destroy (client:%p)", client);
374
375     wl_list_remove(&client->link);
376     free(client);
377 }
378
379 static void
380 blender_bind(struct wl_client *wl_client, void *data, uint32_t version,
381         uint32_t id)
382 {
383     struct ds_tizen_blender *blender = data;
384     struct ds_tizen_blender_client *client;
385
386     client = calloc(1, sizeof *client);
387     if (client == NULL) {
388         ds_err("calloc() failed. tizen_blender");
389         wl_client_post_no_memory(wl_client);
390         return;
391     }
392
393     ds_inf("tizen_blender_client binds. (client:%p)", client);
394
395     client->blender = blender;
396     client->wl_client = wl_client;
397
398     client->resource = wl_resource_create(wl_client, &wtz_blender_interface,
399             MIN(version, TIZEN_BLENDER_VERSION), id);
400     if (client->resource == NULL) {
401         ds_err("tizen_blender : wl_resource_create() failed.");
402         free(client);
403         wl_client_post_no_memory(wl_client);
404         return;
405     }
406
407     wl_resource_set_implementation(client->resource, &blender_impl, client,
408             blender_client_handle_destroy);
409
410     wl_signal_init(&client->events.destroy);
411
412     wl_list_insert(&blender->clients, &client->link);
413 }