summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSeunghun Lee <shiin.lee@samsung.com>2014-07-16 10:54:57 -0400
committerMike Blumenkrantz <zmike@osg.samsung.com>2014-08-12 14:46:14 -0400
commit007a9fcdbc5efb9461205e136b7225d06647f5cc (patch)
treeb7e99e2350090a97b8074aff98a07e972f4ca24b
parent82840173d0388ea64e8fb91a1536150b89e141c5 (diff)
downloadenlightenment-007a9fcdbc5efb9461205e136b7225d06647f5cc.tar.gz
Implement wayland subsurface support based on E_Client.
Summary: Support subsurface interface of wayland. Test Plan: 1. Build enlightenment on devs/devilhorns/e_comp_wl branch. 2. Run enlightenment. 3. Run weston-subsurfaces - should be built after removing code of gl surface (not yet implemented) - just comment out the line egl_state_create in function of demoapp_create() Reviewers: gwanglim, devilhorns Subscribers: cedric Differential Revision: https://phab.enlightenment.org/D1182
-rw-r--r--src/bin/e_comp_wl.c897
-rw-r--r--src/bin/e_comp_wl.h37
2 files changed, 850 insertions, 84 deletions
diff --git a/src/bin/e_comp_wl.c b/src/bin/e_comp_wl.c
index 2366715c5b..ada808ce9f 100644
--- a/src/bin/e_comp_wl.c
+++ b/src/bin/e_comp_wl.c
@@ -9,9 +9,11 @@
/* local variables */
static Eina_List *handlers = NULL;
+static Eina_List *subcomp_handlers = NULL;
static Eina_Hash *clients_win_hash = NULL;
static Ecore_Idle_Enterer *_client_idler = NULL;
static Eina_List *_idle_clients = NULL;
+static Eina_Bool restacking = EINA_FALSE;
static void
_e_comp_wl_focus_down_set(E_Client *ec)
@@ -130,6 +132,25 @@ _e_comp_wl_surface_cb_destroy(struct wl_client *client EINA_UNUSED, struct wl_re
wl_resource_destroy(resource);
}
+static E_Comp_Wl_Subsurf *
+_e_comp_wl_client_subsurf_data_get(E_Client *ec)
+{
+ if (!ec->wl_comp_data) return NULL;
+
+ return ec->wl_comp_data->sub.cdata;
+}
+
+static E_Client *
+_e_comp_wl_subsurface_parent_get(E_Client *ec)
+{
+ E_Comp_Wl_Subsurf *sub_cdata;
+
+ if (!ec->wl_comp_data) return NULL;
+ if (!(sub_cdata = _e_comp_wl_client_subsurf_data_get(ec))) return NULL;
+
+ return sub_cdata->parent;
+}
+
static void
_e_comp_wl_surface_cb_attach(struct wl_client *client, struct wl_resource *resource, struct wl_resource *buffer_resource, int32_t sx, int32_t sy)
{
@@ -316,26 +337,255 @@ _e_comp_wl_surface_cb_input_region_set(struct wl_client *client EINA_UNUSED, str
}
}
-static void
-_e_comp_wl_surface_cb_commit(struct wl_client *client EINA_UNUSED, struct wl_resource *resource)
+static void
+_e_comp_wl_subsurface_destroy_internal(E_Client *ec)
+{
+ E_Comp_Wl_Subsurf *sub_cdata;
+
+ sub_cdata = _e_comp_wl_client_subsurf_data_get(ec);
+ if (!sub_cdata) return;
+
+ if (sub_cdata->resource)
+ {
+ if (sub_cdata->parent)
+ {
+ sub_cdata->parent->wl_comp_data->sub.list
+ = eina_list_remove(sub_cdata->parent->wl_comp_data->sub.list, ec);
+ sub_cdata->parent = NULL;
+ }
+
+ _e_comp_wl_buffer_reference(&sub_cdata->cached.buffer_ref, NULL);
+
+ if (sub_cdata->cached.damage)
+ eina_tiler_free(sub_cdata->cached.damage);
+ if (sub_cdata->cached.input)
+ eina_tiler_free(sub_cdata->cached.input);
+ if (sub_cdata->cached.opaque)
+ eina_tiler_free(sub_cdata->cached.opaque);
+ }
+
+ free(sub_cdata);
+ ec->wl_comp_data->sub.cdata = NULL;
+ e_object_del(E_OBJECT(ec));
+}
+
+static void
+_e_comp_wl_subsurface_destroy(struct wl_resource *resource)
{
- E_Pixmap *cp;
E_Client *ec;
+
+ if (!(ec = wl_resource_get_user_data(resource))) return;
+
+ _e_comp_wl_subsurface_destroy_internal(ec);
+}
+
+static E_Client *
+_e_comp_wl_subsurface_root_get(E_Client *ec)
+{
+ E_Client *parent = NULL;
+
+ if (!ec->wl_comp_data) return ec;
+ if (!_e_comp_wl_client_subsurf_data_get(ec)) return ec;
+ if (!(parent = _e_comp_wl_subsurface_parent_get(ec))) return ec;
+
+ return _e_comp_wl_subsurface_root_get(parent);
+}
+
+static Eina_Bool
+_e_comp_wl_subsurface_is_synchronized(E_Comp_Wl_Subsurf *sub_cdata)
+{
+ while(sub_cdata)
+ {
+ if (sub_cdata->synchronized) return EINA_TRUE;
+
+ if (!sub_cdata->parent) return EINA_FALSE;
+
+ sub_cdata = _e_comp_wl_client_subsurf_data_get(sub_cdata->parent);
+ }
+
+ return EINA_FALSE;
+}
+
+static void
+_e_comp_wl_subsurface_commit_to_cache(E_Client *ec)
+{
+ E_Comp_Wl_Client_Data *cdata;
+ E_Comp_Wl_Subsurf *sub_cdata;
+
+ if (!(cdata = ec->wl_comp_data)) return;
+ if (!(sub_cdata = cdata->sub.cdata)) return;
+
+ // copy pending damage to cache, and clear pending damage.
+ eina_tiler_union(sub_cdata->cached.damage, cdata->pending.damage);
+ eina_tiler_clear(cdata->pending.damage);
+
+ if (cdata->pending.new_attach)
+ {
+ sub_cdata->cached.new_attach = EINA_TRUE;
+ _e_comp_wl_buffer_reference(&sub_cdata->cached.buffer_ref,
+ cdata->pending.buffer);
+ }
+
+ sub_cdata->cached.x = cdata->pending.x;
+ sub_cdata->cached.y = cdata->pending.y;
+ cdata->pending.x = 0;
+ cdata->pending.y = 0;
+ cdata->pending.new_attach = EINA_FALSE;
+
+ sub_cdata->cached.opaque = eina_tiler_new(ec->w, ec->h);
+ eina_tiler_union(sub_cdata->cached.opaque, cdata->pending.opaque);
+
+ sub_cdata->cached.input = eina_tiler_new(ec->w, ec->h);
+ eina_tiler_union(sub_cdata->cached.input, cdata->pending.input);
+
+ sub_cdata->cached.has_data = EINA_TRUE;
+}
+
+static void
+_e_comp_wl_subsurface_commit_from_cache(E_Client *ec)
+{
+ E_Comp_Wl_Client_Data *cdata;
+ E_Comp_Wl_Subsurf *sub_cdata;
+ E_Pixmap *cp;
Eina_Tiler *src, *tmp;
- if (!(cp = wl_resource_get_user_data(resource))) return;
+ if (!(cdata = ec->wl_comp_data)) return;
+ if (!(sub_cdata = cdata->sub.cdata)) return;
+ if (!(cp = ec->pixmap)) return;
- /* try to find the E client for this surface */
- if (!(ec = e_pixmap_client_get(cp)))
- ec = e_pixmap_find_client(E_PIXMAP_TYPE_WL, e_pixmap_window_get(cp));
+ if (sub_cdata->cached.new_attach)
+ {
+ _e_comp_wl_buffer_reference(&cdata->buffer_ref,
+ sub_cdata->cached.buffer_ref.buffer);
+ e_pixmap_resource_set(cp, cdata->pending.buffer->resource);
+ e_pixmap_usable_set(cp, (cdata->pending.buffer != NULL));
+ }
- if ((!ec) || (e_object_is_del(E_OBJECT(ec)))) return;
+ e_pixmap_dirty(cp);
+ e_pixmap_refresh(cp);
+
+ if (sub_cdata->cached.new_attach)
+ {
+ if (sub_cdata->cached.buffer_ref.buffer)
+ {
+ if (cdata->mapped)
+ {
+ if ((cdata->shell.surface) &&
+ (cdata->shell.unmap))
+ cdata->shell.unmap(cdata->shell.surface);
+ }
+ }
+ else
+ {
+ if (!cdata->mapped)
+ {
+ if ((cdata->shell.surface) &&
+ (cdata->shell.map))
+ cdata->shell.map(cdata->shell.surface);
+ }
+ }
+ }
+
+ sub_cdata->cached.x = 0;
+ sub_cdata->cached.y = 0;
+ sub_cdata->cached.has_data = EINA_FALSE;
+ sub_cdata->cached.new_attach = EINA_FALSE;
+
+ if ((!ec->comp->nocomp) && (ec->frame))
+ {
+ tmp = eina_tiler_new(ec->w, ec->h);
+ eina_tiler_tile_size_set(tmp, 1, 1);
+ eina_tiler_rect_add(tmp,
+ &(Eina_Rectangle){0, 0, ec->client.w, ec->client.h});
+
+ src = eina_tiler_intersection(sub_cdata->cached.damage, tmp);
+ if (src)
+ {
+ Eina_Rectangle *rect;
+ Eina_Iterator *itr;
+
+ itr = eina_tiler_iterator_new(src);
+ EINA_ITERATOR_FOREACH(itr, rect)
+ {
+ e_comp_object_damage(ec->frame,
+ rect->x, rect->y, rect->w, rect->h);
+ }
+ eina_iterator_free(itr);
+ eina_tiler_free(src);
+ }
+ eina_tiler_free(tmp);
+ eina_tiler_clear(sub_cdata->cached.damage);
+ }
+
+ /* TODO !!! FIXME !!! */
+ /* handle surface opaque region */
+
+ tmp = eina_tiler_new(ec->w, ec->h);
+ eina_tiler_tile_size_set(tmp, 1, 1);
+ eina_tiler_rect_add(tmp, &(Eina_Rectangle){0, 0, ec->client.w, ec->client.h});
+
+ src = eina_tiler_intersection(sub_cdata->cached.input, tmp);
+ if (src)
+ {
+ Eina_Rectangle *rect;
+ Eina_Iterator *itr;
+ int i = 0;
+
+ ec->shape_input_rects_num = 0;
+
+ itr = eina_tiler_iterator_new(src);
+ EINA_ITERATOR_FOREACH(itr, rect)
+ {
+ ec->shape_input_rects_num += 1;
+ }
+
+ ec->shape_input_rects =
+ malloc(sizeof(Eina_Rectangle) * ec->shape_input_rects_num);
+
+ if (!ec->shape_input_rects)
+ {
+ eina_iterator_free(itr);
+ eina_tiler_free(src);
+ eina_tiler_free(tmp);
+ return;
+ }
+
+ EINA_ITERATOR_FOREACH(itr, rect)
+ {
+ ec->shape_input_rects[i] =
+ *(Eina_Rectangle *)((char *)rect);
+
+ ec->shape_input_rects[i].x = rect->x;
+ ec->shape_input_rects[i].y = rect->y;
+ ec->shape_input_rects[i].w = rect->w;
+ ec->shape_input_rects[i].h = rect->h;
+
+ i++;
+ }
+
+ eina_iterator_free(itr);
+ eina_tiler_free(src);
+ }
+
+ eina_tiler_free(tmp);
+ eina_tiler_clear(sub_cdata->cached.input);
+
+ ec->changes.shape_input = EINA_TRUE;
+ EC_CHANGED(ec);
+}
+
+static void
+_e_comp_wl_surface_commit(E_Client *ec)
+{
+ E_Pixmap *cp;
+ Eina_Tiler *src, *tmp;
if (!ec->wl_comp_data) return;
+ if (!(cp = ec->pixmap)) return;
if (ec->wl_comp_data->pending.new_attach)
{
- _e_comp_wl_buffer_reference(&ec->wl_comp_data->buffer_ref,
+ _e_comp_wl_buffer_reference(&ec->wl_comp_data->buffer_ref,
ec->wl_comp_data->pending.buffer);
e_pixmap_resource_set(cp, ec->wl_comp_data->pending.buffer->resource);
@@ -345,16 +595,16 @@ _e_comp_wl_surface_cb_commit(struct wl_client *client EINA_UNUSED, struct wl_res
e_pixmap_dirty(cp);
e_pixmap_refresh(cp);
- if ((ec->wl_comp_data->shell.surface) &&
+ if ((ec->wl_comp_data->shell.surface) &&
(ec->wl_comp_data->shell.configure))
{
if (ec->wl_comp_data->pending.new_attach)
{
- if ((ec->client.w != ec->wl_comp_data->pending.w) ||
+ if ((ec->client.w != ec->wl_comp_data->pending.w) ||
(ec->client.h != ec->wl_comp_data->pending.h))
- ec->wl_comp_data->shell.configure(ec->wl_comp_data->shell.surface,
- ec->client.x, ec->client.y,
- ec->wl_comp_data->pending.w,
+ ec->wl_comp_data->shell.configure(ec->wl_comp_data->shell.surface,
+ ec->client.x, ec->client.y,
+ ec->wl_comp_data->pending.w,
ec->wl_comp_data->pending.h);
}
}
@@ -365,7 +615,7 @@ _e_comp_wl_surface_cb_commit(struct wl_client *client EINA_UNUSED, struct wl_res
{
if (ec->wl_comp_data->mapped)
{
- if ((ec->wl_comp_data->shell.surface) &&
+ if ((ec->wl_comp_data->shell.surface) &&
(ec->wl_comp_data->shell.unmap))
ec->wl_comp_data->shell.unmap(ec->wl_comp_data->shell.surface);
}
@@ -374,7 +624,7 @@ _e_comp_wl_surface_cb_commit(struct wl_client *client EINA_UNUSED, struct wl_res
{
if (!ec->wl_comp_data->mapped)
{
- if ((ec->wl_comp_data->shell.surface) &&
+ if ((ec->wl_comp_data->shell.surface) &&
(ec->wl_comp_data->shell.map))
ec->wl_comp_data->shell.map(ec->wl_comp_data->shell.surface);
}
@@ -446,6 +696,14 @@ _e_comp_wl_surface_cb_commit(struct wl_client *client EINA_UNUSED, struct wl_res
ec->shape_input_rects =
malloc(sizeof(Eina_Rectangle) * ec->shape_input_rects_num);
+ if (!ec->shape_input_rects)
+ {
+ eina_iterator_free(itr);
+ eina_tiler_free(src);
+ eina_tiler_free(tmp);
+ return;
+ }
+
EINA_ITERATOR_FOREACH(itr, rect)
{
ec->shape_input_rects[i] =
@@ -459,10 +717,12 @@ _e_comp_wl_surface_cb_commit(struct wl_client *client EINA_UNUSED, struct wl_res
i++;
}
+ eina_iterator_free(itr);
eina_tiler_free(src);
}
eina_tiler_free(tmp);
+ eina_tiler_clear(ec->wl_comp_data->pending.input);
ec->changes.shape_input = EINA_TRUE;
EC_CHANGED(ec);
@@ -473,6 +733,115 @@ _e_comp_wl_surface_cb_commit(struct wl_client *client EINA_UNUSED, struct wl_res
/* #endif */
}
+static void
+_e_comp_wl_subsurface_parent_commit(E_Client *ec, Eina_Bool parent_is_synchronized)
+{
+ E_Client *parent, *subc;
+ E_Comp_Wl_Subsurf *sub_cdata;
+ Eina_List *l;
+
+ if (!(parent = _e_comp_wl_subsurface_parent_get(ec))) return;
+ if (!(sub_cdata = _e_comp_wl_client_subsurf_data_get(ec))) return;
+
+ if (sub_cdata->position.set)
+ {
+ evas_object_move(ec->frame,
+ parent->x + sub_cdata->position.x,
+ parent->y + sub_cdata->position.y);
+ sub_cdata->position.set = EINA_FALSE;
+ }
+
+ if ((parent_is_synchronized) || (sub_cdata->synchronized))
+ {
+ if (sub_cdata->cached.has_data)
+ _e_comp_wl_subsurface_commit_from_cache(ec);
+
+ EINA_LIST_FOREACH(ec->wl_comp_data->sub.list, l, subc)
+ {
+ if (ec != subc)
+ _e_comp_wl_subsurface_parent_commit(subc, EINA_TRUE);
+ }
+ }
+}
+
+static void
+_e_comp_wl_subsurface_commit(E_Client *ec)
+{
+ E_Client *subc;
+ E_Comp_Wl_Subsurf *sub_cdata;
+ Eina_List *l;
+ int w, h;
+
+ if (!ec->wl_comp_data) return;
+
+ sub_cdata = _e_comp_wl_client_subsurf_data_get(ec);
+ if (!sub_cdata) return;
+
+ ec->client.w = ec->wl_comp_data->pending.w;
+ ec->client.h = ec->wl_comp_data->pending.h;
+ evas_object_geometry_get(ec->frame, NULL, NULL, &w, &h);
+
+ if ((ec->client.w != w) || (ec->client.h != h))
+ evas_object_resize(ec->frame, ec->client.w, ec->client.h);
+
+ if ((!ec->iconic) &&
+ (!evas_object_visible_get(ec->frame)))
+ evas_object_show(ec->frame);
+
+ if (_e_comp_wl_subsurface_is_synchronized(sub_cdata))
+ _e_comp_wl_subsurface_commit_to_cache(ec);
+ else
+ {
+ if (sub_cdata->cached.has_data)
+ {
+ _e_comp_wl_subsurface_commit_to_cache(ec);
+ _e_comp_wl_subsurface_commit_from_cache(ec);
+ }
+ else _e_comp_wl_surface_commit(ec);
+
+ EINA_LIST_FOREACH(ec->wl_comp_data->sub.list, l, subc)
+ {
+ if (ec != subc)
+ _e_comp_wl_subsurface_parent_commit(subc, EINA_FALSE);
+ }
+ }
+}
+
+static void
+_e_comp_wl_surface_cb_commit(struct wl_client *client EINA_UNUSED, struct wl_resource *resource)
+{
+ E_Pixmap *cp;
+ E_Client *ec, *subc;
+ Eina_List *l;
+
+ if (!(cp = wl_resource_get_user_data(resource))) return;
+
+ /* try to find the E client for this surface */
+ if (!(ec = e_pixmap_client_get(cp)))
+ ec = e_pixmap_find_client(E_PIXMAP_TYPE_WL, e_pixmap_window_get(cp));
+
+ if ((!ec) || (e_object_is_del(E_OBJECT(ec))))
+ return;
+
+ if (!ec->wl_comp_data) return;
+
+ if (_e_comp_wl_client_subsurf_data_get(ec))
+ {
+ // ec for subsurface.
+ _e_comp_wl_subsurface_commit(ec);
+ return;
+ }
+
+ // ec for main surface.
+ _e_comp_wl_surface_commit(ec);
+
+ EINA_LIST_FOREACH(ec->wl_comp_data->sub.list, l, subc)
+ {
+ if (subc != ec)
+ _e_comp_wl_subsurface_parent_commit(subc, EINA_FALSE);
+ }
+}
+
static void
_e_comp_wl_surface_cb_buffer_transform_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource EINA_UNUSED, int32_t transform EINA_UNUSED)
{
@@ -635,48 +1004,86 @@ static void
_e_comp_wl_subcomp_cb_destroy(struct wl_client *client EINA_UNUSED, struct wl_resource *resource)
{
wl_resource_destroy(resource);
+
+ E_FREE_LIST(subcomp_handlers, ecore_event_handler_del);
}
-static void
-_e_comp_wl_subcomp_cb_subsurface_get(struct wl_client *client EINA_UNUSED, struct wl_resource *resource EINA_UNUSED, uint32_t id EINA_UNUSED, struct wl_resource *surface_resource EINA_UNUSED, struct wl_resource *parent_resource EINA_UNUSED)
+static void
+_e_comp_wl_evas_cb_move(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
- /* NB: Needs New Resource */
-#warning TODO Need to subcomp subsurface
+ E_Client *ec;
+ E_Client *subc;
+ Eina_List *l;
+ int x, y;
+
+ if (!(ec = data)) return;
+
+ EINA_LIST_FOREACH(ec->wl_comp_data->sub.list, l, subc)
+ {
+ x = ec->x + subc->wl_comp_data->sub.cdata->position.x;
+ y = ec->y + subc->wl_comp_data->sub.cdata->position.y;
+ evas_object_move(subc->frame, x, y);
+ }
}
-static const struct wl_compositor_interface _e_comp_interface =
+static Eina_Bool
+_e_comp_wl_cb_client_iconify(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
{
- _e_comp_wl_comp_cb_surface_create,
- _e_comp_wl_comp_cb_region_create
-};
+ E_Event_Client *ev;
+ E_Client *ec, *subc;
+ Eina_List *l;
-static const struct wl_subcompositor_interface _e_subcomp_interface =
-{
- _e_comp_wl_subcomp_cb_destroy,
- _e_comp_wl_subcomp_cb_subsurface_get
-};
+ ev = event;
+ if (!(ec = ev->ec)) return ECORE_CALLBACK_PASS_ON;
-static void
-_e_comp_wl_cb_bind_compositor(struct wl_client *client, void *data, uint32_t version, uint32_t id)
+ if (_e_comp_wl_client_subsurf_data_get(ec))
+ {
+ ec = _e_comp_wl_subsurface_root_get(ec);
+ if (!ec->iconic) e_client_iconify(ec);
+ }
+
+ EINA_LIST_FOREACH(ec->wl_comp_data->sub.list, l, subc)
+ {
+ if (subc->iconic) continue;
+ e_client_iconify(subc);
+ }
+
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_e_comp_wl_cb_client_uniconify(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
{
- E_Comp *comp;
- struct wl_resource *res;
+ E_Event_Client *ev;
+ E_Client *ec, *subc;
+ Eina_List *l;
- if (!(comp = data)) return;
+ ev = event;
+ if (!(ec = ev->ec)) return ECORE_CALLBACK_PASS_ON;
- res =
- wl_resource_create(client, &wl_compositor_interface, MIN(version, 3), id);
- if (!res)
+ if (_e_comp_wl_client_subsurf_data_get(ec))
{
- wl_client_post_no_memory(client);
- return;
+ ec = _e_comp_wl_subsurface_root_get(ec);
+ if (ec->iconic) e_client_uniconify(ec);
}
- wl_resource_set_implementation(res, &_e_comp_interface, comp, NULL);
+ EINA_LIST_FOREACH(ec->wl_comp_data->sub.list, l, subc)
+ {
+ if (!subc->iconic) continue;
+ e_client_uniconify(subc);
+ }
+
+ return ECORE_CALLBACK_PASS_ON;
}
+static const struct wl_compositor_interface _e_comp_interface =
+{
+ _e_comp_wl_comp_cb_surface_create,
+ _e_comp_wl_comp_cb_region_create
+};
+
static void
-_e_comp_wl_cb_bind_subcompositor(struct wl_client *client, void *data, uint32_t version, uint32_t id)
+_e_comp_wl_cb_bind_compositor(struct wl_client *client, void *data, uint32_t version, uint32_t id)
{
E_Comp *comp;
struct wl_resource *res;
@@ -684,15 +1091,14 @@ _e_comp_wl_cb_bind_subcompositor(struct wl_client *client, void *data, uint32_t
if (!(comp = data)) return;
res =
- wl_resource_create(client, &wl_subcompositor_interface,
- MIN(version, 1), id);
+ wl_resource_create(client, &wl_compositor_interface, MIN(version, 3), id);
if (!res)
{
wl_client_post_no_memory(client);
return;
}
- wl_resource_set_implementation(res, &_e_subcomp_interface, comp, NULL);
+ wl_resource_set_implementation(res, &_e_comp_interface, comp, NULL);
}
static void
@@ -822,6 +1228,361 @@ _e_comp_wl_cb_first_draw(void *data)
return EINA_FALSE;
}
+static void
+_e_comp_wl_subsurface_restack(E_Client *ec)
+{
+ E_Client *subc, *below = NULL;
+ Eina_List *l;
+
+ if (!ec->wl_comp_data->sub.list) return;
+
+ EINA_LIST_REVERSE_FOREACH(ec->wl_comp_data->sub.list, l, subc)
+ {
+ if (subc->iconic) continue;
+ if (below)
+ evas_object_stack_below(subc->frame, below->frame);
+ else
+ evas_object_stack_above(subc->frame, ec->frame);
+ below = subc;
+
+ if (subc->wl_comp_data->sub.list)
+ _e_comp_wl_subsurface_restack(subc);
+ }
+}
+
+static Eina_Bool
+_e_comp_wl_client_idler(void *data EINA_UNUSED)
+{
+ E_Client *ec;
+ E_Comp *comp;
+ const Eina_List *l;
+
+ EINA_LIST_FREE(_idle_clients, ec)
+ {
+ if ((e_object_is_del(E_OBJECT(ec))) || (!ec->wl_comp_data)) continue;
+
+ ec->post_move = 0;
+ ec->post_resize = 0;
+
+ if (ec->wl_comp_data->sub.restack_target)
+ {
+ if (ec->layer_block) continue;
+
+ // for blocking evas object restack callback.
+ restacking = EINA_TRUE;
+ if (ec->wl_comp_data->sub.restack_target != ec)
+ evas_object_stack_below(ec->frame, ec->wl_comp_data->sub.restack_target->frame);
+ _e_comp_wl_subsurface_restack(ec);
+ ec->wl_comp_data->sub.restack_target = NULL;
+ restacking = EINA_FALSE;
+ }
+ }
+
+ EINA_LIST_FOREACH(e_comp_list(), l, comp)
+ {
+ if ((comp->wl_comp_data->restack) && (!comp->new_clients))
+ {
+ e_hints_client_stacking_set();
+ comp->wl_comp_data->restack = EINA_FALSE;
+ }
+ }
+
+ _client_idler = NULL;
+ return EINA_FALSE;
+}
+
+static void
+_e_comp_wl_client_idler_add(E_Client *ec)
+{
+ if (!_client_idler)
+ _client_idler = ecore_idle_enterer_add(_e_comp_wl_client_idler, NULL);
+
+ if (!ec) CRI("ACK!");
+
+ if (!eina_list_data_find(_idle_clients, ec))
+ _idle_clients = eina_list_append(_idle_clients, ec);
+}
+
+static void
+_e_comp_wl_evas_cb_restack(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ E_Client *ec;
+ E_Client *parent;
+
+ if (restacking) return;
+ if (!(ec = data)) return;
+ if ((!ec->wl_comp_data->sub.list) &&
+ (!_e_comp_wl_client_subsurf_data_get(ec))) return;
+
+ parent = ec;
+ if (_e_comp_wl_client_subsurf_data_get(ec))
+ parent = _e_comp_wl_subsurface_root_get(ec);
+
+ parent->wl_comp_data->sub.restack_target = ec;
+ _e_comp_wl_client_idler_add(parent);
+}
+
+static void
+_e_comp_wl_subsurface_cb_destroy(struct wl_client *client EINA_UNUSED, struct wl_resource *resource)
+{
+ wl_resource_destroy(resource);
+}
+
+static void
+_e_comp_wl_subsurface_cb_position_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, int32_t x, int32_t y)
+{
+ E_Client *ec;
+ E_Comp_Wl_Subsurf *sub_cdata;
+
+ if (!(ec = wl_resource_get_user_data(resource))) return;
+ if (!(sub_cdata = _e_comp_wl_client_subsurf_data_get(ec))) return;
+
+ sub_cdata->position.x = x;
+ sub_cdata->position.y = y;
+ sub_cdata->position.set = EINA_TRUE;
+}
+
+static void
+_e_comp_wl_subsurface_cb_place_above(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, struct wl_resource *sibling_resource)
+{
+ E_Client *parent;
+ E_Client *ec;
+ E_Client *sibling;
+
+ if (!(ec = wl_resource_get_user_data(resource))) return;
+ if (!(sibling = wl_resource_get_user_data(sibling_resource))) return;
+ if ((!_e_comp_wl_client_subsurf_data_get(ec)) ||
+ (!_e_comp_wl_client_subsurf_data_get(sibling))) return;
+ if (_e_comp_wl_subsurface_parent_get(ec) !=
+ _e_comp_wl_subsurface_parent_get(sibling)) return;
+ if (!(parent = _e_comp_wl_subsurface_parent_get(ec))) return;
+
+ parent->wl_comp_data->sub.list =
+ eina_list_remove(parent->wl_comp_data->sub.list, ec);
+ parent->wl_comp_data->sub.list =
+ eina_list_append_relative(parent->wl_comp_data->sub.list, ec, sibling);
+ parent->wl_comp_data->sub.restack_target = parent;
+ _e_comp_wl_client_idler_add(parent);
+}
+
+static void
+_e_comp_wl_subsurface_cb_place_below(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, struct wl_resource *sibling_resource)
+{
+ E_Client *parent;
+ E_Client *ec;
+ E_Client *sibling;
+
+ if (!(ec = wl_resource_get_user_data(resource))) return;
+ if (!(sibling = wl_resource_get_user_data(sibling_resource))) return;
+ if ((!_e_comp_wl_client_subsurf_data_get(ec)) ||
+ (!_e_comp_wl_client_subsurf_data_get(sibling))) return;
+ if (_e_comp_wl_subsurface_parent_get(ec) !=
+ _e_comp_wl_subsurface_parent_get(sibling)) return;
+ if (!(parent = _e_comp_wl_subsurface_parent_get(ec))) return;
+
+ parent->wl_comp_data->sub.list =
+ eina_list_remove(parent->wl_comp_data->sub.list, ec);
+ parent->wl_comp_data->sub.list =
+ eina_list_prepend_relative(parent->wl_comp_data->sub.list, ec, sibling);
+ parent->wl_comp_data->sub.restack_target = parent;
+ _e_comp_wl_client_idler_add(parent);
+}
+
+static void
+_e_comp_wl_subsurface_cb_sync_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource)
+{
+ E_Client *ec;
+ E_Comp_Wl_Subsurf *sub_cdata;
+
+ if (!(ec = wl_resource_get_user_data(resource))) return;
+ if (!(sub_cdata = _e_comp_wl_client_subsurf_data_get(ec))) return;
+
+ sub_cdata->synchronized = EINA_TRUE;
+}
+
+static void
+_e_comp_wl_subsurface_cb_desync_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource)
+{
+ E_Client *ec;
+ E_Comp_Wl_Subsurf *sub_cdata;
+
+ if (!(ec = wl_resource_get_user_data(resource))) return;
+ if (!(sub_cdata = _e_comp_wl_client_subsurf_data_get(ec))) return;
+
+ sub_cdata->synchronized = EINA_FALSE;
+}
+
+static const struct wl_subsurface_interface _e_comp_wl_subsurface_interface =
+{
+ _e_comp_wl_subsurface_cb_destroy,
+ _e_comp_wl_subsurface_cb_position_set,
+ _e_comp_wl_subsurface_cb_place_above,
+ _e_comp_wl_subsurface_cb_place_below,
+ _e_comp_wl_subsurface_cb_sync_set,
+ _e_comp_wl_subsurface_cb_desync_set
+};
+
+static Eina_Bool
+_e_comp_wl_subsurface_create(E_Client *ec, E_Client *pc, uint32_t id, struct wl_resource *surface_resource)
+{
+ E_Comp_Wl_Subsurf *sub_cdata;
+ struct wl_client *client;
+
+ if (!(client = wl_resource_get_client(surface_resource))) return EINA_FALSE;
+
+ sub_cdata = E_NEW(E_Comp_Wl_Subsurf, 1);
+ if (!sub_cdata) return EINA_FALSE;
+
+ sub_cdata->resource = wl_resource_create(client, &wl_subsurface_interface, 1, id);
+ if (!sub_cdata->resource)
+ {
+ free(sub_cdata);
+ return EINA_FALSE;
+ }
+ wl_resource_set_implementation(sub_cdata->resource,
+ &_e_comp_wl_subsurface_interface, ec,
+ _e_comp_wl_subsurface_destroy);
+
+ sub_cdata->synchronized = EINA_TRUE;
+ sub_cdata->parent = pc;
+
+ sub_cdata->cached.damage = eina_tiler_new(1, 1);
+ eina_tiler_tile_size_set(sub_cdata->cached.damage, 1, 1);
+
+ sub_cdata->cached.input = eina_tiler_new(1, 1);
+ eina_tiler_tile_size_set(sub_cdata->cached.damage, 1, 1);
+
+ sub_cdata->cached.opaque = eina_tiler_new(1, 1);
+ eina_tiler_tile_size_set(sub_cdata->cached.damage, 1, 1);
+
+ ec->borderless = EINA_TRUE;
+ ec->argb = EINA_TRUE;
+ ec->lock_focus_in = ec->lock_focus_out = EINA_TRUE;
+ ec->netwm.state.skip_taskbar = EINA_TRUE;
+ ec->netwm.state.skip_pager = EINA_TRUE;
+ ec->wl_comp_data->surface = surface_resource;
+ ec->wl_comp_data->sub.cdata = sub_cdata;
+
+ evas_object_pass_events_set(ec->frame, EINA_TRUE);
+ evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_RESTACK,
+ _e_comp_wl_evas_cb_restack, ec);
+
+ if (pc)
+ {
+ E_Comp_Wl_Client_Data *cdata;
+
+ cdata = pc->wl_comp_data;
+ if (cdata)
+ cdata->sub.list = eina_list_append(cdata->sub.list, ec);
+
+ evas_object_event_callback_add(pc->frame, EVAS_CALLBACK_MOVE,
+ _e_comp_wl_evas_cb_move, pc);
+ evas_object_event_callback_add(pc->frame, EVAS_CALLBACK_RESTACK,
+ _e_comp_wl_evas_cb_restack, pc);
+ }
+
+ return EINA_TRUE;
+}
+
+static void
+_e_comp_wl_subcomp_cb_subsurface_get(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t id, struct wl_resource *surface_resource, struct wl_resource *parent_resource)
+{
+ E_Pixmap *pp, *ep;
+ E_Client *ec, *pc;
+ static const char where[] = "get_subsurface: wl_subsurface@";
+
+ if (!(pp = wl_resource_get_user_data(parent_resource)))
+ {
+ wl_resource_post_error(resource,
+ WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE,
+ "%s%d: wl_surface@%d is invalid.",
+ where, id, wl_resource_get_id(parent_resource));
+ return;
+ }
+
+ if (!(ep = wl_resource_get_user_data(surface_resource)))
+ {
+ wl_resource_post_error(resource,
+ WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE,
+ "%s%d: wl_surface@%d is invalid.",
+ where, id, wl_resource_get_id(surface_resource));
+ return;
+ }
+
+ if (pp == ep)
+ {
+ wl_resource_post_error(resource,
+ WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE,
+ "%s%d: wl_surface@%d cannot be its own parent",
+ where, id, wl_resource_get_id(surface_resource));
+ return;
+ }
+
+ if (!(ec = e_pixmap_client_get(ep)))
+ ec = e_pixmap_find_client(E_PIXMAP_TYPE_WL, e_pixmap_window_get(ep));
+
+ if (!ec)
+ {
+ if (!(ec = e_client_new(e_util_comp_current_get(), ep, 1, 0)))
+ {
+ wl_resource_post_no_memory(resource);
+ return;
+ }
+ }
+ else if (_e_comp_wl_client_subsurf_data_get(ec))
+ {
+ wl_resource_post_error(resource,
+ WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE,
+ "%s%d: wl_surface@%d is already a sub-surface",
+ where, id, wl_resource_get_id(surface_resource));
+ return;
+ }
+
+ if (!ec->wl_comp_data)
+ {
+ e_object_del(E_OBJECT(ec));
+ return;
+ }
+
+ pc = e_pixmap_client_get(pp);
+ if (!_e_comp_wl_subsurface_create(ec, pc, id, surface_resource))
+ {
+ e_object_del(E_OBJECT(ec));
+ return;
+ }
+}
+
+static const struct wl_subcompositor_interface _e_subcomp_interface =
+{
+ _e_comp_wl_subcomp_cb_destroy,
+ _e_comp_wl_subcomp_cb_subsurface_get
+};
+
+static void
+_e_comp_wl_cb_bind_subcompositor(struct wl_client *client, void *data, uint32_t version, uint32_t id)
+{
+ E_Comp *comp;
+ struct wl_resource *res;
+
+ if (!(comp = data)) return;
+
+ res =
+ wl_resource_create(client, &wl_subcompositor_interface,
+ MIN(version, 1), id);
+ if (!res)
+ {
+ wl_client_post_no_memory(client);
+ return;
+ }
+
+ wl_resource_set_implementation(res, &_e_subcomp_interface, comp, NULL);
+
+ E_LIST_HANDLER_APPEND(subcomp_handlers, E_EVENT_CLIENT_ICONIFY,
+ _e_comp_wl_cb_client_iconify, NULL);
+ E_LIST_HANDLER_APPEND(subcomp_handlers, E_EVENT_CLIENT_UNICONIFY,
+ _e_comp_wl_cb_client_uniconify, NULL);
+}
+
static Eina_Bool
_e_comp_wl_compositor_create(void)
{
@@ -986,46 +1747,6 @@ disp_err:
return EINA_FALSE;
}
-static Eina_Bool
-_e_comp_wl_client_idler(void *data EINA_UNUSED)
-{
- E_Client *ec;
- E_Comp *comp;
- const Eina_List *l;
-
- EINA_LIST_FREE(_idle_clients, ec)
- {
- if ((e_object_is_del(E_OBJECT(ec))) || (!ec->wl_comp_data)) continue;
-
- ec->post_move = 0;
- ec->post_resize = 0;
- }
-
- EINA_LIST_FOREACH(e_comp_list(), l, comp)
- {
- if ((comp->wl_comp_data->restack) && (!comp->new_clients))
- {
- e_hints_client_stacking_set();
- comp->wl_comp_data->restack = EINA_FALSE;
- }
- }
-
- _client_idler = NULL;
- return EINA_FALSE;
-}
-
-static void
-_e_comp_wl_client_idler_add(E_Client *ec)
-{
- if (!_client_idler)
- _client_idler = ecore_idle_enterer_add(_e_comp_wl_client_idler, NULL);
-
- if (!ec) CRI("ACK!");
-
- if (!eina_list_data_find(_idle_clients, ec))
- _idle_clients = eina_list_append(_idle_clients, ec);
-}
-
static void
_e_comp_wl_client_priority_adjust(int pid, int set, int adj, Eina_Bool use_adj, Eina_Bool adj_child, Eina_Bool do_child)
{
@@ -1855,6 +2576,14 @@ _e_comp_wl_cb_hook_client_del(void *data EINA_UNUSED, E_Client *ec)
ec->parent->modal = NULL;
}
+ if (ec->wl_comp_data->sub.list)
+ {
+ E_Client *subc;
+
+ EINA_LIST_FREE(ec->wl_comp_data->sub.list, subc)
+ _e_comp_wl_subsurface_destroy_internal(subc);
+ }
+
E_FREE_FUNC(ec->wl_comp_data->first_draw_tmr, ecore_timer_del);
E_FREE(ec->wl_comp_data);
diff --git a/src/bin/e_comp_wl.h b/src/bin/e_comp_wl.h
index 21043c92b0..74c5e3b8ba 100644
--- a/src/bin/e_comp_wl.h
+++ b/src/bin/e_comp_wl.h
@@ -36,6 +36,7 @@
typedef struct _E_Comp_Wl_Buffer E_Comp_Wl_Buffer;
typedef struct _E_Comp_Wl_Buffer_Ref E_Comp_Wl_Buffer_Ref;
+typedef struct _E_Comp_Wl_Subsurf E_Comp_Wl_Subsurf;
struct _E_Comp_Wl_Data
{
@@ -164,10 +165,46 @@ struct _E_Comp_Wl_Buffer_Ref
struct wl_listener destroy_listener;
};
+struct _E_Comp_Wl_Subsurf
+{
+ struct wl_resource *resource;
+
+ E_Client *parent;
+
+ struct
+ {
+ int x, y;
+ Eina_Bool set;
+ } position;
+
+ struct
+ {
+ int x, y;
+
+ Eina_Bool has_data;
+ Eina_Bool new_attach;
+
+ E_Comp_Wl_Buffer_Ref buffer_ref;
+
+ Eina_Tiler *damage;
+ Eina_Tiler *opaque;
+ Eina_Tiler *input;
+ } cached;
+
+ Eina_Bool synchronized;
+};
+
struct _E_Comp_Wl_Client_Data
{
Ecore_Timer *first_draw_tmr;
+ struct
+ {
+ E_Comp_Wl_Subsurf *cdata;
+ E_Client *restack_target;
+ Eina_List *list;
+ } sub;
+
/* regular surface resource (wl_compositor_create_surface) */
struct wl_resource *surface;