d2d3a2541bd6ad796118ae352eb60869ab864d13
[platform/upstream/enlightenment.git] / src / bin / e_blender.c
1 #include "e_blender_intern.h"
2 #include "e_client_intern.h"
3 #include "e_comp_object_intern.h"
4
5 #include <wtz-blender-server-protocol.h>
6
7 static E_Blender *_blender = NULL;
8
9 static void _e_blend_surface_set(E_Blend *blend, struct wl_resource *surface);
10
11 static void
12 _e_blend_cb_destroy(struct wl_client *client,
13                     struct wl_resource *resource)
14 {
15    wl_resource_destroy(resource);
16 }
17
18 static void
19 _e_blend_cb_set_alpha(struct wl_client *client,
20                       struct wl_resource *resource,
21                       uint32_t value)
22 {
23    E_Blend *blend;
24
25    blend = wl_resource_get_user_data(resource);
26    if (!blend) return;
27    if (!blend->surface) return;
28    if (blend->alpha == value) return;
29
30    blend->alpha = value;
31    blend->changed = EINA_TRUE;
32
33    ELOGF("E_BLENDER", "E_Blend:%p set alpha:%x",
34          e_client_from_surface_resource(blend->surface), blend, value);
35 }
36
37 static void
38 _e_blend_cb_set_equation(struct wl_client *client,
39                          struct wl_resource *resource,
40                          uint32_t equation)
41 {
42    E_Blend *blend;
43
44    blend = wl_resource_get_user_data(resource);
45    if (!blend) return;
46    if (!blend->surface) return;
47    if (blend->equation == equation) return;
48
49    if ((equation != WTZ_BLEND_EQUATION_PREMULTIPLIED) &&
50        (equation != WTZ_BLEND_EQUATION_NONE))
51      {
52         wl_resource_post_error(resource, WTZ_BLEND_ERROR_INVALID_EQUATION,
53                                "Invalid equation");
54         return;
55      }
56
57    blend->equation = equation;
58    blend->changed = EINA_TRUE;
59
60    ELOGF("E_BLENDER", "E_Blend:%p set equation:%d",
61          e_client_from_surface_resource(blend->surface), blend, equation);
62 }
63
64 static const struct wtz_blend_interface _e_blend_implementation = {
65    _e_blend_cb_destroy,
66    _e_blend_cb_set_alpha,
67    _e_blend_cb_set_equation,
68 };
69
70 static void
71 _e_blend_free(E_Blend *blend)
72 {
73    ELOGF("E_BLENDER", "E_Blend:%p Free",
74          blend->surface ? e_client_from_surface_resource(blend->surface) : NULL,
75          blend);
76
77    _e_blend_surface_set(blend, NULL);
78    free(blend);
79 }
80
81 static void
82 _e_blend_cb_surface_destroy(struct wl_listener *listener, void *data)
83 {
84    E_Blend *blend;
85
86    blend = container_of(listener, E_Blend, surface_destroy_listener);
87
88    if (blend->resource)
89      _e_blend_surface_set(blend, NULL);
90    else
91      _e_blend_free(blend);
92 }
93
94 static void
95 _e_blend_cb_surface_state_commit(struct wl_listener *listener, void *data)
96 {
97    E_Blend *blend;
98    E_Client *ec;
99    int a, r, g, b;
100
101    blend = container_of(listener, E_Blend, surface_state_commit_listener);
102    if (!blend->changed) return;
103
104    ec = e_client_from_surface_resource(blend->surface);
105    if (!ec) return;
106
107    if (!blend->resource)
108      {
109         e_comp_object_render_op_set(ec->frame, EVAS_RENDER_BLEND);
110         evas_object_color_set(ec->frame, 255, 255, 255, 255);
111         _e_blend_free(blend);
112         return;
113      }
114
115    if (!ec->argb) return;
116
117    a = r = g = b = 255;
118    a = (int)((blend->alpha / (double)0xffffffff) * a);
119    evas_color_argb_premul(a, &r, &g, &b);
120
121    evas_object_color_set(ec->frame, r, g, b, a);
122
123    if (blend->equation == WTZ_BLEND_EQUATION_PREMULTIPLIED)
124      e_comp_object_render_op_set(ec->frame, EVAS_RENDER_BLEND);
125    else if (blend->equation == WTZ_BLEND_EQUATION_NONE)
126      e_comp_object_render_op_set(ec->frame, EVAS_RENDER_COPY);
127
128    blend->changed = EINA_FALSE;
129 }
130
131 static void
132 _e_blend_surface_set(E_Blend *blend, struct wl_resource *surface)
133 {
134    E_Client *ec;
135    E_Comp_Client_Data *cdata;
136
137    if (blend->surface == surface) return;
138
139    if (blend->surface_destroy_listener.notify)
140      {
141         wl_list_remove(&blend->surface_destroy_listener.link);
142         blend->surface_destroy_listener.notify = NULL;
143      }
144
145    if (blend->surface_state_commit_listener.notify)
146      {
147         wl_list_remove(&blend->surface_state_commit_listener.link);
148         blend->surface_state_commit_listener.notify = NULL;
149      }
150
151    blend->surface = NULL;
152
153    if (surface)
154      {
155         ec = e_client_from_surface_resource(surface);
156         EINA_SAFETY_ON_NULL_RETURN(ec);
157
158         cdata = e_client_cdata_get(ec);
159         EINA_SAFETY_ON_NULL_RETURN(cdata);
160
161         blend->surface = surface;
162
163         blend->surface_destroy_listener.notify = _e_blend_cb_surface_destroy;
164         wl_resource_add_destroy_listener(surface, &blend->surface_destroy_listener);
165
166         blend->surface_state_commit_listener.notify = _e_blend_cb_surface_state_commit;
167         wl_signal_add(&cdata->state_commit_signal, &blend->surface_state_commit_listener);
168      }
169 }
170
171 static void
172 _e_blend_cb_resource_destroy(struct wl_resource *resource)
173 {
174    E_Blend *blend;
175    Evas_Render_Op render_op;
176    E_Client *ec;
177    int a;
178
179    blend = wl_resource_get_user_data(resource);
180    if (!blend) return;
181
182    if (blend->surface)
183      {
184          ec = e_client_from_surface_resource(blend->surface);
185          if (ec)
186            {
187               e_comp_object_color_get(ec->frame, NULL, NULL, NULL, &a);
188               render_op = e_comp_object_render_op_get(ec->frame);
189               if ((a != 255) || (render_op != EVAS_RENDER_BLEND))
190                 {
191                    blend->resource = NULL;
192                    blend->changed = EINA_TRUE;
193                    return;
194                 }
195            }
196      }
197
198    _e_blend_free(blend);
199 }
200
201 static void
202 _e_blender_cb_destroy(struct wl_client *client,
203                       struct wl_resource *resource)
204 {
205    wl_resource_destroy(resource);
206 }
207
208 static E_Blend *
209 _e_blender_blend_get_from_surface(struct wl_resource *surface)
210 {
211    E_Blend *blend;
212    struct wl_listener *listener;
213
214    listener = wl_resource_get_destroy_listener(surface, _e_blend_cb_surface_destroy);
215    if (!listener) return NULL;
216
217    return wl_container_of(listener, blend, surface_destroy_listener);
218 }
219
220 static void
221 _e_blender_cb_get_blend(struct wl_client *client, struct wl_resource *resource,
222                         uint32_t id, struct wl_resource *surface)
223 {
224    E_Client *ec;
225    E_Blend *blend = NULL;
226    E_Blender *blender = _blender;
227
228    if (!blender)
229      {
230         ERR("blender is not initialized");
231         return;
232      }
233
234    ec = e_client_from_surface_resource(surface);
235    if ((!ec) || (e_object_is_del(E_OBJECT(ec))))
236      {
237         wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
238                                "invalid wl_surface resource:%u",
239                                (unsigned int)wl_resource_get_id(surface));
240         goto fail;
241      }
242
243    blend = _e_blender_blend_get_from_surface(surface);
244    if (blend)
245      {
246         if (blend->resource)
247           {
248              wl_resource_post_error(resource, WTZ_BLENDER_ERROR_BLEND_EXISTS,
249                                      "blend object already exists");
250              goto fail;
251           }
252         else
253           {
254              _e_blend_free(blend);
255           }
256      }
257
258    blend = E_NEW(E_Blend, 1);
259    if (!blend)
260      {
261         wl_client_post_no_memory(client);
262         goto fail;
263      }
264
265    blend->resource = wl_resource_create(client,
266                                         &wtz_blend_interface,
267                                         wl_resource_get_version(resource),
268                                         id);
269    if (!blend->resource)
270      {
271         wl_client_post_no_memory(client);
272         goto fail;
273      }
274
275    wl_resource_set_implementation(blend->resource,
276                                   &_e_blend_implementation,
277                                   blend,
278                                   _e_blend_cb_resource_destroy);
279
280    blend->alpha = 0xffffffff;
281    _e_blend_surface_set(blend, surface);
282
283    ELOGF("E_BLENDER", "E_Blend:%p Create", ec, blend);
284
285    return;
286
287 fail:
288    if (blend)
289      free(blend);
290
291    return;
292 }
293
294 static const struct wtz_blender_interface _e_blender_implementation = {
295    _e_blender_cb_destroy,
296    _e_blender_cb_get_blend,
297 };
298
299 static void
300 _e_blender_cb_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id)
301 {
302    struct wl_resource *resource;
303    E_Blender *blender;
304
305    blender = _blender;
306    if (!blender) return;
307
308    resource = wl_resource_create(client, &wtz_blender_interface, version, id);
309    if (!resource)
310      {
311         wl_client_post_no_memory(client);
312         return;
313      }
314
315    wl_resource_set_implementation(resource, &_e_blender_implementation,
316                                   blender, NULL);
317 }
318
319 EINTERN Eina_Bool
320 e_blender_init(void)
321 {
322    E_Blender *blender;
323
324    EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp_wl, EINA_FALSE);
325    EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp_wl->wl.disp, EINA_FALSE);
326
327    if (_blender) return EINA_TRUE;
328
329    blender = E_NEW(E_Blender, 1);
330    EINA_SAFETY_ON_NULL_RETURN_VAL(blender, EINA_FALSE);
331
332    blender->global = wl_global_create(e_comp_wl->wl.disp,
333                                       &wtz_blender_interface,
334                                       1,
335                                       blender,
336                                       _e_blender_cb_bind);
337    EINA_SAFETY_ON_NULL_GOTO(blender->global, fail);
338
339    _blender = blender;
340
341    return EINA_TRUE;
342
343 fail:
344    if (blender->global)
345       wl_global_destroy(blender->global);
346
347    E_FREE(blender);
348
349    return EINA_FALSE;
350 }
351
352 EINTERN void
353 e_blender_shutdown(void)
354 {
355    E_Blender *blender;
356
357    blender = _blender;
358    if (!blender) return;
359
360    wl_global_destroy(blender->global);
361    E_FREE(blender);
362
363    _blender = NULL;
364 }