#include <string.h>
#include <uuid.h>
#include <wtz-video-shell-server-protocol.h>
+#include <Evas.h>
#include <Eina.h>
#ifdef VS_ERR
E_Video_Shell *shell;
E_Video_Viewport_Source *source;
+ Evas_Object *border;
+
E_Video_Viewport_State pending, cache, current;
uuid_t handle;
struct wl_listener parent_map;
struct wl_listener parent_unmap;
struct wl_listener source_destroy;
+ struct wl_listener reposition;
Eina_Bool parent_mapped;
Eina_Bool mapped;
};
static const char *e_video_surface_role_name = "wtz_video_surface";
+static Eina_Bool border_enabled = EINA_FALSE;
static void _source_viewport_destroyed(E_Video_Viewport_Source *source);
static void _source_viewport_committed(E_Video_Viewport_Source *source);
static void _source_viewport_map_state_changed(E_Video_Viewport_Source *source);
static void _source_surface_link(E_Video_Viewport_Source *source, E_Video_Surface *surface);
+static void _viewport_border_init(E_Video_Viewport *viewport);
+static void _viewport_border_finish(E_Video_Viewport *viewport);
+static void _viewport_border_geometry_update(E_Video_Viewport *viewport);
static void
_viewport_cb_source_destroy(struct wl_listener *listener, void *data)
eina_hash_del_by_data(viewport->shell->viewports, viewport);
e_object_unref(E_OBJECT(viewport->shell));
+ _viewport_border_finish(viewport);
wl_resource_set_user_data(viewport->resource, NULL);
wl_list_remove(&viewport->parent_map.link);
wl_list_remove(&viewport->parent_unmap.link);
wl_list_remove(&viewport->precommit_from_cache.link);
wl_list_remove(&viewport->precommit_from_pending.link);
wl_list_remove(&viewport->precommit_to_cache.link);
+ wl_list_remove(&viewport->reposition.link);
wl_list_remove(&viewport->destroy.link);
free(viewport);
}
if (viewport->parent_mapped && viewport->current.map)
{
viewport->mapped = EINA_TRUE;
+
+ if (viewport->border)
+ evas_object_show(viewport->border);
+
if (viewport->source)
_source_viewport_map_state_changed(viewport->source);
}
return;
viewport->mapped = EINA_FALSE;
+
+ if (viewport->border)
+ evas_object_hide(viewport->border);
+
if (viewport->source)
_source_viewport_map_state_changed(viewport->source);
}
_viewport_unmap(viewport);
}
+ if (viewport->current.committed & E_VIDEO_VIEWPORT_STATE_DESTINATION)
+ _viewport_border_geometry_update(viewport);
+
if (viewport->source)
_source_viewport_committed(viewport->source);
}
}
static void
+_viewport_cb_reposition(struct wl_listener *listener, void *data)
+{
+ E_Video_Viewport *viewport = wl_container_of(listener, viewport, reposition);
+ int x, y;
+
+ e_subsurface_coord_get(viewport->subsurface, &x, &y);
+
+ VS_INF("VIEWPORT %p| Reposition: coord (%d, %d)", viewport, x, y);
+
+ _viewport_border_geometry_update(viewport);
+}
+
+static void
_viewport_cb_parent_map(struct wl_listener *listener, void *data)
{
E_Video_Viewport *viewport = wl_container_of(listener, viewport, parent_map);
viewport->precommit_from_pending.notify = _viewport_cb_precommit_from_pending;
e_surface_precommit_from_pending_listener_add(surface, &viewport->precommit_from_pending);
+ viewport->reposition.notify = _viewport_cb_reposition;
+ e_subsurface_reposition_listener_add(viewport->subsurface, &viewport->reposition);
+
parent_surface = e_subsurface_parent_get(viewport->subsurface);
viewport->parent_map.notify = _viewport_cb_parent_map;
_viewport_export_handle_generate(viewport);
_viewport_name_init(viewport);
+ if (border_enabled)
+ _viewport_border_init(viewport);
+
VS_INF("VIEWPORT %p| Created with E_Subsurface(%p)", viewport, viewport->subsurface);
}
return shell;
}
+
+EINTERN void
+e_video_shell_border_enabled_set(Eina_Bool enabled)
+{
+ border_enabled = enabled;
+}
+
+typedef enum
+{
+ TOP = 0,
+ BOTTOM,
+ LEFT,
+ RIGHT,
+ NUM_DIRECTIONS,
+} E_Video_Viewport_Border_Direction;
+
+typedef struct
+{
+ Evas_Object_Smart_Clipped_Data base;
+ Evas_Object *objs[NUM_DIRECTIONS];
+ Evas_Object *inner_obj;
+} E_Video_Viewport_Border_Smart_Data;
+
+EVAS_SMART_SUBCLASS_NEW("Viewport_Border", _viewport_border,
+ Evas_Smart_Class, Evas_Smart_Class,
+ evas_object_smart_clipped_class_get, NULL)
+
+static void
+_viewport_border_smart_add(Evas_Object *o)
+{
+ EVAS_SMART_DATA_ALLOC(o, E_Video_Viewport_Border_Smart_Data);
+
+ _viewport_border_parent_sc->add(o);
+
+ for (int i = 0; i < NUM_DIRECTIONS; i++)
+ {
+ priv->objs[i] = evas_object_rectangle_add(evas_object_evas_get(o));
+ evas_object_smart_member_add(priv->objs[i], o);
+ evas_object_show(priv->objs[i]);
+ }
+
+ priv->inner_obj = evas_object_rectangle_add(evas_object_evas_get(o));
+ evas_object_smart_member_add(priv->inner_obj, o);
+ evas_object_color_set(priv->inner_obj, 50, 50, 50, 50);
+ evas_object_show(priv->inner_obj);
+}
+
+static void
+_viewport_border_smart_resize(Evas_Object *o, Evas_Coord w, Evas_Coord h)
+{
+ E_Video_Viewport_Border_Smart_Data *priv = evas_object_smart_data_get(o);
+ Evas_Coord ox, oy, ow, oh;
+ const int BORDER_SIZE = 3;
+
+ evas_object_geometry_get(o, &ox, &oy, &ow, &oh);
+ if ((ow == w) && (oh == h)) return;
+
+ evas_object_resize(priv->objs[TOP], w, BORDER_SIZE);
+
+ evas_object_move(priv->objs[BOTTOM], ox, oy + (h - BORDER_SIZE));
+ evas_object_resize(priv->objs[BOTTOM], w, BORDER_SIZE);
+
+ evas_object_move(priv->objs[LEFT], ox, oy + BORDER_SIZE);
+ evas_object_resize(priv->objs[LEFT], BORDER_SIZE, h - (BORDER_SIZE * 2));
+
+ evas_object_move(priv->objs[RIGHT], ox + (w - BORDER_SIZE), oy + BORDER_SIZE);
+ evas_object_resize(priv->objs[RIGHT], BORDER_SIZE, h - (BORDER_SIZE * 2));
+
+ evas_object_resize(priv->inner_obj, w, h);
+}
+
+static void
+_viewport_border_smart_set_user(Evas_Smart_Class *sc)
+{
+ sc->add = _viewport_border_smart_add;
+ sc->resize = _viewport_border_smart_resize;
+}
+
+static void
+_viewport_border_cb_show(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED)
+{
+ E_Video_Viewport *viewport = data;
+
+ evas_object_show(viewport->border);
+}
+
+static void
+_viewport_border_cb_hide(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED)
+{
+ E_Video_Viewport *viewport = data;
+
+ evas_object_show(viewport->border);
+}
+
+static void
+_viewport_border_cb_restack(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj, void *event EINA_UNUSED)
+{
+ E_Video_Viewport *viewport = data;
+
+ evas_object_layer_set(viewport->border, evas_object_layer_get(obj));
+ evas_object_stack_above(viewport->border, obj);
+}
+
+static void
+_viewport_border_init(E_Video_Viewport *viewport)
+{
+ E_Client *ec;
+ E_Client *parent_ec;
+
+ if (viewport->border)
+ return;
+
+ if (viewport->source && viewport->source->subsurface)
+ ec = e_surface_ec_get(e_subsurface_surface_get(viewport->source->subsurface));
+ else
+ ec = e_surface_ec_get(e_subsurface_surface_get(viewport->subsurface));
+
+ viewport->border = evas_object_smart_add(evas_object_evas_get(ec->frame), _viewport_border_smart_class_new());
+ evas_object_color_set(viewport->border, 255, 0, 0, 255);
+ evas_object_layer_set(viewport->border, evas_object_layer_get(ec->frame));
+ evas_object_stack_above(viewport->border, ec->frame);
+
+ parent_ec = e_surface_ec_get(e_subsurface_parent_get(viewport->subsurface));
+ if (evas_object_visible_get(parent_ec->frame))
+ evas_object_show(viewport->border);
+
+ evas_object_event_callback_add(parent_ec->frame, EVAS_CALLBACK_SHOW, _viewport_border_cb_show, viewport);
+ evas_object_event_callback_add(parent_ec->frame, EVAS_CALLBACK_HIDE, _viewport_border_cb_hide, viewport);
+ evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_RESTACK, _viewport_border_cb_restack, viewport);
+}
+
+static void
+_viewport_border_finish(E_Video_Viewport *viewport)
+{
+ E_Surface *parent_surface;
+ E_Client *ec, *parent_ec;
+
+ if (!viewport->border)
+ return;
+
+ if (viewport->source && viewport->source->subsurface)
+ ec = e_surface_ec_get(e_subsurface_surface_get(viewport->source->subsurface));
+ else
+ ec = e_surface_ec_get(e_subsurface_surface_get(viewport->subsurface));
+
+ parent_surface = e_subsurface_parent_get(viewport->subsurface);
+ if (parent_surface)
+ {
+ parent_ec = e_surface_ec_get(parent_surface);
+ evas_object_event_callback_del(parent_ec->frame, EVAS_CALLBACK_SHOW, _viewport_border_cb_show);
+ evas_object_event_callback_del(parent_ec->frame, EVAS_CALLBACK_HIDE, _viewport_border_cb_hide);
+ }
+
+ evas_object_event_callback_del(ec->frame, EVAS_CALLBACK_RESTACK, _viewport_border_cb_restack);
+ evas_object_del(viewport->border);
+ viewport->border = NULL;
+}
+
+static void
+_viewport_border_geometry_update(E_Video_Viewport *viewport)
+{
+ int x, y;
+
+ if (!viewport->border)
+ return;
+
+ e_subsurface_coord_get(viewport->subsurface, &x, &y);
+ evas_object_move(viewport->border, x, y);
+ evas_object_resize(viewport->border, viewport->current.width, viewport->current.height);
+}