video_shell: Add border of viewport 90/315090/1
authorSeunghun Lee <shiin.lee@samsung.com>
Fri, 19 Jul 2024 03:22:30 +0000 (12:22 +0900)
committerTizen Window System <tizen.windowsystem@gmail.com>
Thu, 25 Jul 2024 02:44:10 +0000 (11:44 +0900)
The border of viewport is a rectangle drawn by the geometry of viewport.
With this border, you can see the geometry set by client on the screen.

Change-Id: I426182617f19fd6fd5597c61cf022290f01a7beb

src/bin/server/e_compositor.c
src/bin/server/e_compositor_intern.h
src/bin/server/e_video_shell.c
src/bin/server/e_video_shell_intern.h

index 2f7cda1..aeb98a3 100644 (file)
@@ -82,6 +82,7 @@ struct _E_Subsurface
    struct
      {
         struct wl_signal destroy;
+        struct wl_signal reposition;
      } events;
 
    Eina_Bool internal;
@@ -1614,6 +1615,7 @@ _e_subsurface_create(struct ds_subsurface *ds_subsurface, E_Surface *parent_surf
      }
 
    wl_signal_init(&sub->events.destroy);
+   wl_signal_init(&sub->events.reposition);
 
    sub->ds_subsurface = ds_subsurface;
    sub->destroy.notify = _e_subsurface_cb_destroy;
@@ -1779,6 +1781,8 @@ _e_subsurface_cb_request_move(struct wl_listener *listener, void *data)
    sub->base.position.y = ds_subsurface->current.y;
 
    e_subsurface_view_reposition(sub);
+
+   wl_signal_emit(&sub->events.reposition, sub);
 }
 
 static void
@@ -1896,6 +1900,14 @@ e_subsurface_destroy_listener_add(E_Subsurface *subsurface, struct wl_listener *
 }
 
 EINTERN void
+e_subsurface_reposition_listener_add(E_Subsurface *subsurface, struct wl_listener *listener)
+{
+   EINA_SAFETY_ON_NULL_RETURN(subsurface);
+   assert(!subsurface->internal);
+   wl_signal_add(&subsurface->events.reposition, listener);
+}
+
+EINTERN void
 e_subsurface_coord_get(E_Subsurface *subsurface, int *x, int *y)
 {
    E_Subsurface *iter = subsurface;
index 21dcec0..bc9f886 100644 (file)
@@ -45,6 +45,7 @@ EINTERN E_Subsurface *e_subsurface_from_surface(E_Surface *surface);
 EINTERN E_Subsurface *e_subsurface_from_ec(E_Client *ec);
 EINTERN Eina_Bool e_subsurface_position_set(E_Subsurface *subsurface, int x, int y);
 EINTERN void e_subsurface_destroy_listener_add(E_Subsurface *subsurface, struct wl_listener *listener);
+EINTERN void e_subsurface_reposition_listener_add(E_Subsurface *subsurface, struct wl_listener *listener);
 EINTERN void e_subsurface_stand_alone_mode_set(E_Subsurface *sub);
 EINTERN void e_subsurface_stand_alone_mode_unset(E_Subsurface *sub);
 EINTERN void e_subsurface_coord_get(E_Subsurface *subsurface, int *x, int *y);
index f5bebef..c9a1582 100644 (file)
@@ -16,6 +16,7 @@
 #include <string.h>
 #include <uuid.h>
 #include <wtz-video-shell-server-protocol.h>
+#include <Evas.h>
 #include <Eina.h>
 
 #ifdef VS_ERR
@@ -71,6 +72,8 @@ typedef struct
    E_Video_Shell *shell;
    E_Video_Viewport_Source *source;
 
+   Evas_Object *border;
+
    E_Video_Viewport_State pending, cache, current;
 
    uuid_t handle;
@@ -82,6 +85,7 @@ typedef struct
    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;
@@ -159,11 +163,15 @@ struct _E_Video_Viewport_Source
 };
 
 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)
@@ -345,12 +353,14 @@ _viewport_destroy(E_Video_Viewport *viewport)
    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);
 }
@@ -406,6 +416,10 @@ _viewport_consider_map(E_Video_Viewport *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);
      }
@@ -418,6 +432,10 @@ _viewport_unmap(E_Video_Viewport *viewport)
      return;
 
    viewport->mapped = EINA_FALSE;
+
+   if (viewport->border)
+     evas_object_hide(viewport->border);
+
    if (viewport->source)
      _source_viewport_map_state_changed(viewport->source);
 }
@@ -439,6 +457,9 @@ _viewport_state_commit(E_Video_Viewport *viewport, E_Video_Viewport_State *next)
           _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);
 }
@@ -478,6 +499,19 @@ _viewport_cb_precommit_from_pending(struct wl_listener *listener, void *data)
 }
 
 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);
@@ -572,6 +606,9 @@ _video_shell_cb_export_viewport(struct wl_client *client, struct wl_resource *re
    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;
@@ -586,6 +623,9 @@ _video_shell_cb_export_viewport(struct wl_client *client, struct wl_resource *re
    _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);
 }
 
@@ -1728,3 +1768,173 @@ e_video_shell_create(struct wl_display *display)
 
    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);
+}
index 8f3dd9c..8dc87de 100644 (file)
@@ -1,9 +1,12 @@
 #ifndef E_VIDEO_SHELL_INTERN_H
 #define E_VIDEO_SHELL_INTERN_H
 
+#include <Eina.h>
+
 struct E_Video_Shell;
 typedef struct E_Video_Shell E_Video_Shell;
 
 E_Video_Shell *e_video_shell_create(struct wl_display *display);
+void e_video_shell_border_enabled_set(Eina_Bool enabled);
 
 #endif