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