--- /dev/null
+#include "e.h"
+#include <wtz-blender-server-protocol.h>
+
+static E_Blender *_blender = NULL;
+
+static void _e_blend_surface_set(E_Blend *blend, struct wl_resource *surface);
+
+static void
+_e_blend_cb_destroy(struct wl_client *client,
+ struct wl_resource *resource)
+{
+ wl_resource_destroy(resource);
+}
+
+static void
+_e_blend_cb_set_alpha(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t value)
+{
+ E_Blend *blend;
+
+ blend = wl_resource_get_user_data(resource);
+ if (!blend) return;
+ if (!blend->surface) return;
+ if (blend->alpha == value) return;
+
+ blend->alpha = value;
+ blend->changed = EINA_TRUE;
+
+ ELOGF("E_BLENDER", "E_Blend:%p set alpha:%x",
+ e_client_from_surface_resource(blend->surface), blend, value);
+}
+
+static void
+_e_blend_cb_set_equation(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t equation)
+{
+ E_Blend *blend;
+
+ blend = wl_resource_get_user_data(resource);
+ if (!blend) return;
+ if (!blend->surface) return;
+ if (blend->equation == equation) return;
+
+ if ((equation != WTZ_BLEND_EQUATION_PREMULTIPLIED) &&
+ (equation != WTZ_BLEND_EQUATION_NONE))
+ {
+ wl_resource_post_error(resource, WTZ_BLEND_ERROR_INVALID_EQUATION,
+ "Invalid equation");
+ return;
+ }
+
+ blend->equation = equation;
+ blend->changed = EINA_TRUE;
+
+ ELOGF("E_BLENDER", "E_Blend:%p set equation:%d",
+ e_client_from_surface_resource(blend->surface), blend, equation);
+}
+
+static const struct wtz_blend_interface _e_blend_implementation = {
+ _e_blend_cb_destroy,
+ _e_blend_cb_set_alpha,
+ _e_blend_cb_set_equation,
+};
+
+static void
+_e_blend_free(E_Blend *blend)
+{
+ ELOGF("E_BLENDER", "E_Blend:%p Free",
+ blend->surface ? e_client_from_surface_resource(blend->surface) : NULL,
+ blend);
+
+ _e_blend_surface_set(blend, NULL);
+ free(blend);
+}
+
+static void
+_e_blend_cb_surface_destroy(struct wl_listener *listener, void *data)
+{
+ E_Blend *blend;
+
+ blend = container_of(listener, E_Blend, surface_destroy_listener);
+
+ if (blend->resource)
+ _e_blend_surface_set(blend, NULL);
+ else
+ _e_blend_free(blend);
+}
+
+static void
+_e_blend_cb_surface_state_commit(struct wl_listener *listener, void *data)
+{
+ E_Blend *blend;
+ E_Client *ec;
+ int a, r, g, b;
+
+ blend = container_of(listener, E_Blend, surface_state_commit_listener);
+ if (!blend->changed) return;
+
+ ec = e_client_from_surface_resource(blend->surface);
+ if (!ec) return;
+
+ if (!blend->resource)
+ {
+ e_comp_object_render_op_set(ec->frame, EVAS_RENDER_BLEND);
+ evas_object_color_set(ec->frame, 255, 255, 255, 255);
+ _e_blend_free(blend);
+ return;
+ }
+
+ if (!ec->argb) return;
+
+ a = r = g = b = 255;
+ a = (int)((blend->alpha / (double)0xffffffff) * a);
+ evas_color_argb_premul(a, &r, &g, &b);
+
+ evas_object_color_set(ec->frame, r, g, b, a);
+
+ if (blend->equation == WTZ_BLEND_EQUATION_PREMULTIPLIED)
+ e_comp_object_render_op_set(ec->frame, EVAS_RENDER_BLEND);
+ else if (blend->equation == WTZ_BLEND_EQUATION_NONE)
+ e_comp_object_render_op_set(ec->frame, EVAS_RENDER_COPY);
+
+ blend->changed = EINA_FALSE;
+}
+
+static void
+_e_blend_surface_set(E_Blend *blend, struct wl_resource *surface)
+{
+ E_Client *ec;
+ E_Comp_Client_Data *cdata;
+
+ if (blend->surface == surface) return;
+
+ if (blend->surface_destroy_listener.notify)
+ {
+ wl_list_remove(&blend->surface_destroy_listener.link);
+ blend->surface_destroy_listener.notify = NULL;
+ }
+
+ if (blend->surface_state_commit_listener.notify)
+ {
+ wl_list_remove(&blend->surface_state_commit_listener.link);
+ blend->surface_state_commit_listener.notify = NULL;
+ }
+
+ blend->surface = NULL;
+
+ if (surface)
+ {
+ ec = e_client_from_surface_resource(surface);
+ EINA_SAFETY_ON_NULL_RETURN(ec);
+
+ cdata = e_client_cdata_get(ec);
+ EINA_SAFETY_ON_NULL_RETURN(cdata);
+
+ blend->surface = surface;
+
+ blend->surface_destroy_listener.notify = _e_blend_cb_surface_destroy;
+ wl_resource_add_destroy_listener(surface, &blend->surface_destroy_listener);
+
+ blend->surface_state_commit_listener.notify = _e_blend_cb_surface_state_commit;
+ wl_signal_add(&cdata->state_commit_signal, &blend->surface_state_commit_listener);
+ }
+}
+
+static void
+_e_blend_cb_resource_destroy(struct wl_resource *resource)
+{
+ E_Blend *blend;
+ Evas_Render_Op render_op;
+ E_Client *ec;
+ int a;
+
+ blend = wl_resource_get_user_data(resource);
+ if (!blend) return;
+
+ if (blend->surface)
+ {
+ ec = e_client_from_surface_resource(blend->surface);
+ if (ec)
+ {
+ e_comp_object_color_get(ec->frame, NULL, NULL, NULL, &a);
+ render_op = e_comp_object_render_op_get(ec->frame);
+ if ((a != 255) || (render_op != EVAS_RENDER_BLEND))
+ {
+ blend->resource = NULL;
+ blend->changed = EINA_TRUE;
+ return;
+ }
+ }
+ }
+
+ _e_blend_free(blend);
+}
+
+static void
+_e_blender_cb_destroy(struct wl_client *client,
+ struct wl_resource *resource)
+{
+ wl_resource_destroy(resource);
+}
+
+static E_Blend *
+_e_blender_blend_get_from_surface(struct wl_resource *surface)
+{
+ E_Blend *blend;
+ struct wl_listener *listener;
+
+ listener = wl_resource_get_destroy_listener(surface, _e_blend_cb_surface_destroy);
+ if (!listener) return NULL;
+
+ return wl_container_of(listener, blend, surface_destroy_listener);
+}
+
+static void
+_e_blender_cb_get_blend(struct wl_client *client, struct wl_resource *resource,
+ uint32_t id, struct wl_resource *surface)
+{
+ E_Client *ec;
+ E_Blend *blend = NULL;
+ E_Blender *blender = _blender;
+
+ if (!blender)
+ {
+ ERR("blender is not initialized");
+ return;
+ }
+
+ ec = e_client_from_surface_resource(surface);
+ if ((!ec) || (e_object_is_del(E_OBJECT(ec))))
+ {
+ wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "invalid wl_surface resource:%u",
+ (unsigned int)wl_resource_get_id(surface));
+ goto fail;
+ }
+
+ blend = _e_blender_blend_get_from_surface(surface);
+ if (blend)
+ {
+ if (blend->resource)
+ {
+ wl_resource_post_error(resource, WTZ_BLENDER_ERROR_BLEND_EXISTS,
+ "blend object already exists");
+ goto fail;
+ }
+ else
+ {
+ _e_blend_free(blend);
+ }
+ }
+
+ blend = E_NEW(E_Blend, 1);
+ if (!blend)
+ {
+ wl_client_post_no_memory(client);
+ goto fail;
+ }
+
+ blend->resource = wl_resource_create(client,
+ &wtz_blend_interface,
+ wl_resource_get_version(resource),
+ id);
+ if (!blend->resource)
+ {
+ wl_client_post_no_memory(client);
+ goto fail;
+ }
+
+ wl_resource_set_implementation(blend->resource,
+ &_e_blend_implementation,
+ blend,
+ _e_blend_cb_resource_destroy);
+
+ blend->alpha = 0xffffffff;
+ _e_blend_surface_set(blend, surface);
+
+ ELOGF("E_BLENDER", "E_Blend:%p Create", ec, blend);
+
+ return;
+
+fail:
+ if (blend)
+ free(blend);
+
+ return;
+}
+
+static const struct wtz_blender_interface _e_blender_implementation = {
+ _e_blender_cb_destroy,
+ _e_blender_cb_get_blend,
+};
+
+static void
+_e_blender_cb_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id)
+{
+ struct wl_resource *resource;
+ E_Blender *blender;
+
+ blender = _blender;
+ if (!blender) return;
+
+ resource = wl_resource_create(client, &wtz_blender_interface, version, id);
+ if (!resource)
+ {
+ wl_client_post_no_memory(client);
+ return;
+ }
+
+ wl_resource_set_implementation(resource, &_e_blender_implementation,
+ blender, NULL);
+}
+
+EINTERN Eina_Bool
+e_blender_init(void)
+{
+ E_Blender *blender;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp_wl, EINA_FALSE);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp_wl->wl.disp, EINA_FALSE);
+
+ if (_blender) return EINA_TRUE;
+
+ blender = E_NEW(E_Blender, 1);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(blender, EINA_FALSE);
+
+ blender->global = wl_global_create(e_comp_wl->wl.disp,
+ &wtz_blender_interface,
+ 1,
+ blender,
+ _e_blender_cb_bind);
+ EINA_SAFETY_ON_NULL_GOTO(blender->global, fail);
+
+ _blender = blender;
+
+ return EINA_TRUE;
+
+fail:
+ if (blender->global)
+ wl_global_destroy(blender->global);
+
+ E_FREE(blender);
+
+ return EINA_FALSE;
+}
+
+EINTERN void
+e_blender_shutdown(void)
+{
+ E_Blender *blender;
+
+ blender = _blender;
+ if (!blender) return;
+
+ wl_global_destroy(blender->global);
+ E_FREE(blender);
+
+ _blender = NULL;
+}