add deskmirror, a new widget which breaks evas in a number of terrifying ways
authorMike Blumenkrantz <m.blumenkran@samsung.com>
Thu, 25 Apr 2013 10:21:22 +0000 (11:21 +0100)
committerMike Blumenkrantz <m.blumenkran@samsung.com>
Thu, 25 Apr 2013 10:21:22 +0000 (11:21 +0100)
to experience the terror, uncomment the define in e_deskmirror.h

ChangeLog
NEWS
data/themes/Makefile.am
data/themes/default.edc
data/themes/edc/deskmirror.edc [new file with mode: 0644]
src/bin/Makefile.am
src/bin/e_deskmirror.c [new file with mode: 0644]
src/bin/e_deskmirror.h [new file with mode: 0644]
src/bin/e_includes.h
src/bin/e_int_border_menu.c
src/bin/e_test.c

index a93d47a..bc6af85 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2013-04-25 Mike Blumenkrantz
+
+        * added deskmirror
+
 2013-04-19 Mike Blumenkrantz
 
         * deskpreview renamed to bgpreview
diff --git a/NEWS b/NEWS
index 548fb0b..fa51040 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -34,6 +34,7 @@ Additions:
         * added e_object_ref_debug_set
         * added e_gadcon_repopulate
         * added e_comp_win_effect* api
+        * added deskmirror
     Config:
         * Added option for disabling icons in menus
         * Added option for disabling pointer warping when performing directional focus changes using winlist
index 0be183e..8018c67 100644 (file)
@@ -37,6 +37,7 @@ edc/connman.edc \
 edc/cpufreq.edc \
 edc/cslider.edc \
 edc/desklock.edc \
+edc/deskmirror.edc \
 edc/deskpreview.edc \
 edc/dialog.edc \
 edc/edgebindings.edc \
index c90f99b..39c566b 100644 (file)
@@ -4,6 +4,7 @@ collections {
 #include "colorclasses.edc"
 // desktop in general
 #include "edc/comp.edc"
+#include "edc/deskmirror.edc"
 #include "edc/background.edc"
 #include "edc/shelf.edc"
 #include "edc/border.edc"
diff --git a/data/themes/edc/deskmirror.edc b/data/themes/edc/deskmirror.edc
new file mode 100644 (file)
index 0000000..e79de03
--- /dev/null
@@ -0,0 +1,406 @@
+group { name: "e/deskmirror/frame/default";
+   alias: "e/deskmirror/frame/dialog";
+   script {
+      public message(Msg_Type:type, id, ...) {
+         /* set scale */
+         new sc;
+
+         sc = getarg(2);
+         custom_state(PART:"title2", "default", 0.0);
+         custom_state(PART:"top", "default", 0.0);
+         custom_state(PART:"e.text.title", "default", 0.0);
+         custom_state(PART:"bottom", "default", 0.0);
+         set_state_val(PART:"title2", STATE_REL1, 0, 0.0 - sc);
+         set_state_val(PART:"top", STATE_REL1, 0, 0.0 - sc);
+         set_state_val(PART:"e.text.title", STATE_REL1, 0, 0.0 - sc);
+         set_state_val(PART:"bottom", STATE_REL2, 1, sc);
+         set_state(PART:"title2", "custom", 0.0);
+         set_state(PART:"top", "custom", 0.0);
+         set_state(PART:"e.text.title", "custom", 0.0);
+         set_state(PART:"e.swallow.client", "custom", 0.0);
+         set_state(PART:"bottom", "custom", 0.0);
+      }
+   }
+   parts {
+      part { name: "client_clip"; type: RECT;
+         description { state: "default" 0.0;
+            rel1.to_y: "e.swallow.client";
+            rel2.to_y: "e.swallow.client";
+         }
+      }
+      part { name: "e.swallow.client"; type: SWALLOW;
+         clip_to: "client_clip";
+         description { state: "default" 0.0;
+            rel1.to_y: "top";
+            rel1.relative: 0 1;
+         }
+      }
+      part { name: "top";
+         description { state: "default" 0.0;
+            color_class: "border_top";
+            image.normal: "vgrad_med_lighter.png";
+            fill.smooth: 0;
+            TILED_HORIZ(120)
+            rel2.to_y: "title2";
+            rel2.offset: -1 -4;
+            min: 0 1;
+         }
+      }
+      part { name: "bevel"; mouse_events: 0;
+         description { state: "default" 0.0;
+            image.normal: "bevel_out.png";
+            image.border: 1 1 1 1;
+            image.middle: 0;
+            rel1.to: "top";
+            rel2.to: "top";
+            fill.smooth: 0;
+         }
+      }
+      part { name: "e.text.title"; type: TEXT; mouse_events: 0;
+         scale: 1;
+         effect: SHADOW BOTTOM;
+         description { state: "default" 0.0;
+            color_class: "border_title";
+            rel1.offset: 1 3;
+            rel2.relative: 1.0 0.0;
+            rel2.offset: -2 3;
+            align: 0.5 0.0;
+            color: 21 21 21 255;
+            color3: 255 255 255 25;
+            text { font: "Sans:style=Bold";
+               fit: 0 1;
+               text_class: "title_bar";
+               align: 0.5 0.0;
+               min: 0 1;
+            }
+            fixed: 0 1;
+         }
+      }
+      part { name: "title2"; type: TEXT; mouse_events: 0;
+         scale: 1;
+         effect: SOFT_SHADOW BOTTOM;
+         description { state: "default" 0.0;
+            color_class: "border_title_active";
+            rel1.offset: 1 2;
+            rel2.relative: 1.0 0.0;
+            rel2.offset: -1 2;
+            align: 0.5 0.0;
+            color: 255 255 255 255;
+            color3: 0 0 0 18;
+            text { font: "Sans:style=Bold";
+               fit: 0 1;
+               text_source: "e.text.title";
+               text_class: "title_bar";
+               align: 0.5 0.0;
+               min: 0 1;
+            }
+            visible: 0;
+            fixed: 0 1;
+         }
+      }
+      part { name: "bottom"; type: RECT; mouse_events: 0;
+         description { state: "default" 0.0;
+            color_class: "border_bottom";
+            rel1.to_y: "e.swallow.client";
+            rel1.relative: 0.0 1.0;
+            rel1.offset: 0 -3;
+            min: 0 1;
+            color: 64 64 64 255;
+            fixed: 0 1;
+         }
+      }
+      part { name: "bevel2"; mouse_events: 0;
+         description { state: "default" 0.0;
+            image.normal: "bevel_dark_out.png";
+            image.border: 1 1 1 1;
+            image.middle: 0;
+            rel1.to: "bottom";
+            rel2.to: "bottom";
+            fill.smooth: 0;
+         }
+      }
+      part { name: "shadow";
+         mouse_events: 0;
+         description { state: "default" 0.0;
+            image.normal: "win_shadow.png";
+            image.border: 14 14 14 14;
+            image.middle: 0;
+            rel1.to: "top";
+            rel1.offset: -7 -3;
+            rel2.to: "bottom";
+            rel2.offset: 6 11;
+            fill.smooth: 0;
+         }
+      }
+   }
+   programs {
+      program { name: "shon";
+         signal: "e,state,shadow,on"; source: "e";
+         script {
+            custom_state(PART:"shadow", "default", 0.0);
+            set_state_val(PART:"shadow", STATE_VISIBLE, 1);
+            set_state(PART:"shadow", "custom", 0.0);
+         }
+      }
+      program { name: "shoff";
+         signal: "e,state,shadow,off"; source: "e";
+         script {
+            custom_state(PART:"shadow", "default", 0.0);
+            set_state_val(PART:"shadow", STATE_VISIBLE, 0);
+            set_state(PART:"shadow", "custom", 0.0);
+         }
+      }
+      program {
+         name: "focus";
+         signal: "e,state,focused"; source: "e";
+         script {
+            custom_state(PART:"top", "default", 0.0);
+            set_state_val(PART:"top", STATE_IMAGE, get_image_id("vgrad_med_dark.png"));
+            set_state(PART:"top", "custom", 0.0);
+            custom_state(PART:"title2", "default", 0.0);
+            set_state_val(PART:"title2", STATE_VISIBLE, 1);
+            set_state(PART:"title2", "custom", 0.0);
+            custom_state(PART:"e.text.title", "default", 0.0);
+            set_state_val(PART:"e.text.title", STATE_VISIBLE, 0);
+            set_state(PART:"e.text.title", "custom", 0.0);
+         }
+      }
+      program {
+         name: "unfocus";
+         signal: "e,state,unfocused"; source: "e";
+         script {
+            custom_state(PART:"top", "default", 0.0);
+            set_state_val(PART:"top", STATE_IMAGE, get_image_id("vgrad_med_lighter.png"));
+            set_state(PART:"top", "custom", 0.0);
+            custom_state(PART:"title2", "default", 0.0);
+            set_state_val(PART:"title2", STATE_VISIBLE, 0);
+            set_state(PART:"title2", "custom", 0.0);
+            custom_state(PART:"e.text.title", "default", 0.0);
+            set_state_val(PART:"e.text.title", STATE_VISIBLE, 1);
+            set_state(PART:"e.text.title", "custom", 0.0);
+         }
+      }
+      program {
+         name: "shade";
+         signal: "e,state,shaded"; source: "e";
+         script {
+            custom_state(PART:"e.swallow.client", "default", 0.0);
+            set_state_val(PART:"e.swallow.client", STATE_MAX, 1, 1);
+            set_state_val(PART:"e.swallow.client", STATE_VISIBLE, 0);
+            set_state(PART:"e.swallow.client", "custom", 0.0);
+            custom_state(PART:"client_clip", "default", 0.0);
+            set_state_val(PART:"client_clip", STATE_REL1_TO, get_part_id("top"), get_part_id("top"));
+            set_state_val(PART:"client_clip", STATE_REL2_TO, get_part_id("top"), get_part_id("top"));
+            set_state(PART:"client_clip", "custom", 0.0);
+            custom_state(PART:"bottom", "default", 0.0);
+            set_state_val(PART:"bottom", STATE_VISIBLE, 0);
+            set_state_val(PART:"bottom", STATE_MIN, 0, 0);
+            set_state_val(PART:"bottom", STATE_REL1_OFFSET, 0, 0);
+            set_state(PART:"bottom", "custom", 0.0);
+            custom_state(PART:"bevel2", "default", 0.0);
+            set_state_val(PART:"bevel2", STATE_VISIBLE, 0);
+            set_state_val(PART:"bevel2", STATE_MIN, 0, 0);
+            set_state(PART:"bevel2", "custom", 0.0);
+            custom_state(PART:"shadow", "default", 0.0);
+            set_state_val(PART:"shadow", STATE_REL2_TO, get_part_id("top"), get_part_id("top"));
+            set_state(PART:"shadow", "custom", 0.0);
+         }
+      }
+      program {
+         signal: "e,state,maximize*"; source: "e";
+         script {
+            custom_state(PART:"bottom", "default", 0.0);
+            set_state_val(PART:"bottom", STATE_VISIBLE, 0);
+            set_state_val(PART:"bottom", STATE_MIN, 0, 0);
+            set_state_val(PART:"bottom", STATE_REL1_OFFSET, 0, 0);
+            set_state(PART:"bottom", "custom", 0.0);
+            custom_state(PART:"bevel2", "default", 0.0);
+            set_state_val(PART:"bevel2", STATE_VISIBLE, 0);
+            set_state_val(PART:"bevel2", STATE_MIN, 0, 0);
+            set_state(PART:"bevel2", "custom", 0.0);
+         }
+      }
+      program {
+         signal: "e,state,unmaximize*"; source: "e";
+         after: "unshade";
+      }
+      program {
+         signal: "e,state,unshaded"; source: "e";
+         after: "unshade";
+      }
+      program {
+         name: "unshade";
+         signal: "e,state,unshading"; source: "e";
+         script {
+            custom_state(PART:"e.swallow.client", "default", 0.0);
+            set_state_val(PART:"e.swallow.client", STATE_MAX, 99999, 99999);
+            set_state_val(PART:"e.swallow.client", STATE_VISIBLE, 1);
+            set_state(PART:"e.swallow.client", "custom", 0.0);
+            custom_state(PART:"client_clip", "default", 0.0);
+            set_state_val(PART:"client_clip", STATE_REL1_TO, get_part_id("e.swallow.client"), get_part_id("e.swallow.client"));
+            set_state_val(PART:"client_clip", STATE_REL2_TO, get_part_id("e.swallow.client"), get_part_id("e.swallow.client"));
+            set_state(PART:"client_clip", "custom", 0.0);
+            custom_state(PART:"bottom", "default", 0.0);
+            set_state_val(PART:"bottom", STATE_VISIBLE, 1);
+            set_state_val(PART:"bottom", STATE_MIN, 0, 1);
+            set_state_val(PART:"bottom", STATE_REL1_OFFSET, 0, -3);
+            set_state(PART:"bottom", "custom", 0.0);
+            custom_state(PART:"bevel2", "default", 0.0);
+            set_state_val(PART:"bevel2", STATE_VISIBLE, 1);
+            set_state_val(PART:"bevel2", STATE_MIN, 0, 1);
+            set_state(PART:"bevel2", "custom", 0.0);
+            custom_state(PART:"shadow", "default", 0.0);
+            set_state_val(PART:"shadow", STATE_REL2_TO, get_part_id("bottom"), get_part_id("bottom"));
+            set_state(PART:"shadow", "custom", 0.0);
+         }
+      }
+      program {
+         signal: "e,action,maximize*"; source: "e";
+         action: STATE_SET "max" 0.0;
+         target: "e.swallow.client";
+         target: "bottom";
+         target: "bevel2";
+      }
+      program {
+         signal: "e,action,unmaximize*"; source: "e";
+         action: STATE_SET "default" 0.0;
+         target: "e.swallow.client";
+         target: "bottom";
+         target: "bevel2";
+      }
+   }
+}
+
+group { name: "e/deskmirror/frame/noresize";
+   inherit: "e/deskmirror/frame/default";
+   parts {
+      part { name: "e.swallow.client"; type: SWALLOW;
+         description { state: "default" 0.0;
+            rel2.relative: 1.0 1.0;
+         }
+      }
+      part { name: "bottom"; type: RECT;
+         description { state: "default" 0.0;
+            color_class: "border_bottom";
+            rel1.relative: 0.0 1.0;
+            rel1.offset: 0 -1;
+            rel2.relative: 1.0 1.0;
+            min: 0 0;
+            fixed: 0 1;
+            visible: 0;
+         }
+      }
+      part { name: "bevel2";
+         description { state: "default" 0.0;
+            visible: 0;
+         }
+      }
+   }
+}
+
+group { name: "e/deskmirror/frame/noresize_dialog";
+   inherit: "e/deskmirror/frame/default";
+   parts {
+      part { name: "e.swallow.client"; type: SWALLOW;
+         description { state: "default" 0.0;
+            rel2.relative: 1.0 1.0;
+         }
+      }
+      part { name: "bottom"; type: RECT;
+         description { state: "default" 0.0;
+            color_class: "border_bottom";
+            rel1.relative: 0.0 1.0;
+            rel1.offset: 0 -1;
+            rel2.relative: 1.0 1.0;
+            min: 0 0;
+            fixed: 0 1;
+            visible: 0;
+         }
+      }
+      part { name: "bevel2";
+         description { state: "default" 0.0;
+            visible: 0;
+         }
+      }
+   }
+}
+
+group { name: "e/deskmirror/frame/pixel";
+   parts {
+      part { name: "client_clip"; type: RECT;
+         description { state: "default" 0.0;
+            rel1.to_y: "e.swallow.client";
+            rel2.to_y: "e.swallow.client";
+         }
+      }
+      part { name: "e.swallow.client"; type: SWALLOW;
+         clip_to: "client_clip";
+         description { state: "default" 0.0;
+            rel1.offset: 1 1;
+            rel2.offset: -2 -2;
+         }
+      }
+      part { name: "top"; type: RECT;
+         description { state: "default" 0.0;
+            color: 0 0 0 255;
+            align: 0.0 0.0;
+            max: 99999 1;
+         }
+         description { state: "focused" 0.0;
+            inherit: "default" 0.0;
+            color: 51 153 255 255;
+         }
+      }
+      part { name: "bottom"; type: RECT;
+         description { state: "default" 0.0;
+            color: 0 0 0 255;
+            align: 0.0 1.0;
+            max: 99999 1;
+         }
+         description { state: "focused" 0.0;
+            inherit: "default" 0.0;
+            color: 51 153 255 255;
+         }
+      }
+      part { name: "left"; type: RECT;
+         description { state: "default" 0.0;
+            color: 0 0 0 255;
+            align: 0.0 0.0;
+            max: 1 99999;
+         }
+         description { state: "focused" 0.0;
+            inherit: "default" 0.0;
+            color: 51 153 255 255;
+         }
+      }
+      part { name: "right"; type: RECT;
+         description { state: "default" 0.0;
+            color: 0 0 0 255;
+            align: 1.0 0.0;
+            max: 1 99999;
+         }
+         description { state: "focused" 0.0;
+            inherit: "default" 0.0;
+            color: 51 153 255 255;
+         }
+      }
+   }
+   programs {
+      program {
+         signal: "e,state,focused"; source: "e";
+         action: STATE_SET "focused" 0.0;
+         target: "top";
+         target: "bottom";
+         target: "left";
+         target: "right";
+      }
+      program {
+         signal: "e,state,unfocused"; source: "e";
+         action: STATE_SET "default" 0.0;
+         target: "top";
+         target: "bottom";
+         target: "left";
+         target: "right";
+      }
+   }
+}
index 0987d89..098f439 100644 (file)
@@ -71,6 +71,7 @@ e_dbusmenu.h \
 e_desk.h \
 e_deskenv.h \
 e_desklock.h \
+e_deskmirror.h \
 e_dialog.h \
 e_dnd.h \
 e_dpms.h \
@@ -241,6 +242,7 @@ e_dbusmenu.c \
 e_desk.c \
 e_deskenv.c \
 e_desklock.c \
+e_deskmirror.c \
 e_dialog.c \
 e_dnd.c \
 e_dpms.c \
diff --git a/src/bin/e_deskmirror.c b/src/bin/e_deskmirror.c
new file mode 100644 (file)
index 0000000..6306f96
--- /dev/null
@@ -0,0 +1,627 @@
+#include "e.h"
+
+#define INTERNAL_ENTRY E_Smart_Data * sd; sd = evas_object_smart_data_get(obj); if (!sd) return;
+
+typedef struct E_Smart_Data
+{
+   Evas *e;
+   Evas_Object *obj;
+   Evas_Object *clip;
+   Evas_Object *bgpreview;
+   Evas_Object *layout;
+   Eina_Inlist *mirrors;
+   Eina_Hash *mirror_hash;
+
+   Eina_List *handlers;
+
+   Evas_Coord x, y;
+   int w, h;
+
+   E_Desk *desk;
+   E_Object_Delfn *desk_delfn;
+
+   Eina_Bool pager : 1;
+   Eina_Bool taskbar : 1;
+
+   Eina_Bool resize : 1;
+} E_Smart_Data;
+
+typedef struct Mirror
+{
+   EINA_INLIST;
+   E_Smart_Data *sd;
+   E_Comp_Win *cw;
+   Evas_Object *mirror;
+   int x, y, w, h;
+   Eina_Bool frame : 1;
+} Mirror;
+
+typedef struct Mirror_Border
+{
+   Mirror *m;
+   Evas_Object *mirror;
+   Evas_Object *frame;
+   Evas_Object *obj;
+} Mirror_Border;
+
+/* local subsystem globals */
+static Evas_Smart *_e_deskmirror_smart = NULL;
+static Evas_Smart *_mirror_border_smart = NULL;
+
+/* local subsystem functions */
+static void
+_mirror_scale_set(Mirror *m, float sc)
+{
+   Edje_Message_Float_Set msg;
+   Mirror_Border *mb;
+
+   if (!m->frame) return;
+
+   mb = evas_object_smart_data_get(m->mirror);
+   msg.count = 1;
+   msg.val[0] = sc;
+   edje_object_message_send(mb->frame, EDJE_MESSAGE_FLOAT_SET, 0, &msg);
+}
+
+static void
+_e_deskmirror_smart_reconfigure(E_Smart_Data *sd)
+{
+   e_layout_freeze(sd->layout);
+   evas_object_move(sd->clip, sd->x, sd->y);
+   evas_object_move(sd->bgpreview, sd->x, sd->y);
+   evas_object_move(sd->layout, sd->x, sd->y);
+
+   if (sd->resize)
+     {
+        Mirror *m;
+
+        evas_object_resize(sd->clip, sd->w, sd->h);
+        evas_object_resize(sd->bgpreview, sd->w, sd->h);
+        evas_object_resize(sd->layout, sd->w, sd->h);
+        EINA_INLIST_FOREACH(sd->mirrors, m)
+          _mirror_scale_set(m, (float)sd->h / (float)sd->desk->zone->h);
+     }
+   e_layout_thaw(sd->layout);
+   sd->resize = 0;
+}
+
+///////////////////////////////////////////////
+
+static void
+_e_deskmirror_smart_add(Evas_Object *obj)
+{
+   E_Smart_Data *sd;
+
+   sd = E_NEW(E_Smart_Data, 1);
+   if (!sd) return;
+   sd->obj = obj;
+   sd->e = evas_object_evas_get(obj);
+   sd->x = sd->y = sd->w = sd->h = 0;
+   sd->clip = evas_object_rectangle_add(sd->e);
+   evas_object_smart_member_add(sd->clip, sd->obj);
+   evas_object_smart_data_set(obj, sd);
+}
+
+static void
+_e_deskmirror_smart_del(Evas_Object *obj)
+{
+   INTERNAL_ENTRY;
+   if (sd->desk_delfn)
+     {
+        e_object_delfn_del(E_OBJECT(sd->desk), sd->desk_delfn);
+        sd->desk_delfn = NULL;
+        sd->desk = NULL;
+     }
+   E_FREE_LIST(sd->handlers, ecore_event_handler_del);
+   eina_hash_free(sd->mirror_hash);
+   free(sd);
+}
+
+static void
+_e_deskmirror_smart_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
+{
+   INTERNAL_ENTRY;
+   sd->x = x;
+   sd->y = y;
+   _e_deskmirror_smart_reconfigure(sd);
+}
+
+static void
+_e_deskmirror_smart_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h)
+{
+   INTERNAL_ENTRY;
+   sd->w = w;
+   sd->h = h;
+   sd->resize = 1;
+   _e_deskmirror_smart_reconfigure(sd);
+}
+
+static void
+_e_deskmirror_smart_show(Evas_Object *obj)
+{
+   INTERNAL_ENTRY;
+   evas_object_show(sd->clip);
+}
+
+static void
+_e_deskmirror_smart_hide(Evas_Object *obj)
+{
+   INTERNAL_ENTRY;
+   evas_object_hide(sd->clip);
+}
+
+static void
+_e_deskmirror_smart_color_set(Evas_Object *obj, int r, int g, int b, int a)
+{
+   INTERNAL_ENTRY;
+   evas_object_color_set(sd->clip, r, g, b, a);
+}
+
+static void
+_e_deskmirror_smart_clip_set(Evas_Object *obj, Evas_Object *clip)
+{
+   INTERNAL_ENTRY;
+   evas_object_clip_set(sd->clip, clip);
+}
+
+static void
+_e_deskmirror_smart_clip_unset(Evas_Object *obj)
+{
+   INTERNAL_ENTRY;
+   evas_object_clip_unset(sd->clip);
+}
+
+////////////////////////////////////////////////////////
+
+static void
+_e_deskmirror_mirror_frame_del_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+   Mirror_Border *mb = data;
+
+   if (mb->m->cw->bd && (!e_object_is_del(E_OBJECT(mb->m->cw->bd))))
+     {
+        evas_object_smart_member_del(mb->mirror);
+        mb->m->mirror = mb->mirror;
+        mb->m->frame = 0;
+     }
+   else
+     mb->m->cw = NULL;
+   evas_object_del(mb->obj);
+}
+
+static void
+_mirror_border_smart_add(Evas_Object *obj)
+{
+   Mirror_Border *mb;
+
+   mb = E_NEW(Mirror_Border, 1);
+   mb->obj = obj;
+   evas_object_smart_data_set(obj, mb);
+}
+
+static void
+_mirror_border_signal_cb(void *data, Evas_Object *obj EINA_UNUSED, const char *emission, const char *src)
+{
+   Mirror_Border *mb = data;
+   edje_object_signal_emit(mb->frame, emission, src);
+   edje_object_message_signal_process(mb->frame);
+   edje_object_calc_force(mb->frame);
+}
+
+static void
+_mirror_border_smart_del(Evas_Object *obj)
+{
+   Mirror_Border *mb = evas_object_smart_data_get(obj);
+   if (mb->m->cw && mb->m->cw->bd)
+     {
+        evas_object_event_callback_del_full(mb->m->cw->bd->bg_object, EVAS_CALLBACK_DEL, _e_deskmirror_mirror_frame_del_cb, mb);
+        edje_object_signal_callback_del_full(mb->m->cw->bd->bg_object, "*", "*", _mirror_border_signal_cb, mb);
+     }
+   free(mb);
+}
+
+static void
+_mirror_border_smart_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
+{
+   Mirror_Border *mb = evas_object_smart_data_get(obj);
+
+   evas_object_move(mb->frame, x, y);
+}
+
+static void
+_mirror_border_smart_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h)
+{
+   Mirror_Border *mb = evas_object_smart_data_get(obj);
+   evas_object_resize(mb->frame, w, h);
+}
+
+static void
+_mirror_border_smart_show(Evas_Object *obj)
+{
+   Mirror_Border *mb = evas_object_smart_data_get(obj);
+   evas_object_show(mb->frame);
+   evas_object_show(mb->mirror);
+}
+
+static void
+_mirror_border_smart_hide(Evas_Object *obj)
+{
+   Mirror_Border *mb = evas_object_smart_data_get(obj);
+   evas_object_hide(mb->frame);
+   evas_object_hide(mb->mirror);
+}
+
+static void
+_mirror_border_smart_color_set(Evas_Object *obj, int r, int g, int b, int a)
+{
+   Mirror_Border *mb = evas_object_smart_data_get(obj);
+   evas_object_color_set(mb->frame, r, g, b, a);
+   evas_object_color_set(mb->mirror, r, g, b, a);
+}
+
+static void
+_mirror_border_smart_clip_set(Evas_Object *obj, Evas_Object *clip)
+{
+   Mirror_Border *mb = evas_object_smart_data_get(obj);
+   evas_object_clip_set(mb->frame, clip);
+   evas_object_clip_set(mb->mirror, clip);
+}
+
+static void
+_mirror_border_smart_clip_unset(Evas_Object *obj)
+{
+   Mirror_Border *mb = evas_object_smart_data_get(obj);
+   evas_object_clip_unset(mb->frame);
+   evas_object_clip_unset(mb->mirror);
+}
+
+static void
+_mirror_border_smart_init(void)
+{
+   static const Evas_Smart_Class sc =
+     {
+        "mirror_border", EVAS_SMART_CLASS_VERSION,
+        _mirror_border_smart_add, _mirror_border_smart_del, _mirror_border_smart_move, _mirror_border_smart_resize,
+        _mirror_border_smart_show, _mirror_border_smart_hide, _mirror_border_smart_color_set, _mirror_border_smart_clip_set,
+        _mirror_border_smart_clip_unset, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+     };
+   if (_mirror_border_smart) return;
+   _mirror_border_smart = evas_smart_class_new(&sc);
+}
+
+static void
+_e_deskmirror_smart_init(void)
+{
+   static const Evas_Smart_Class sc =
+     {
+        "e_deskmirror", EVAS_SMART_CLASS_VERSION,
+        _e_deskmirror_smart_add, _e_deskmirror_smart_del, _e_deskmirror_smart_move, _e_deskmirror_smart_resize,
+        _e_deskmirror_smart_show, _e_deskmirror_smart_hide, _e_deskmirror_smart_color_set, _e_deskmirror_smart_clip_set,
+        _e_deskmirror_smart_clip_unset, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+     };
+   if (_e_deskmirror_smart) return;
+   _e_deskmirror_smart = evas_smart_class_new(&sc);
+}
+
+static void
+_e_deskmirror_delfn(E_Smart_Data *sd, void *desk EINA_UNUSED)
+{
+   sd->desk_delfn = NULL;
+   sd->desk = NULL;
+   evas_object_del(sd->obj);
+}
+
+static Eina_Bool
+_e_deskmirror_win_visible_get(E_Smart_Data *sd, E_Comp_Win *cw)
+{
+   Eina_Bool visible = cw->visible;
+   if (cw->bd)
+     {
+        if (visible)
+          {
+             if (sd->pager)
+               visible = !cw->bd->client.netwm.state.skip_pager;
+             if (visible && sd->taskbar)
+               visible = !cw->bd->client.netwm.state.skip_taskbar;
+          }
+     }
+   return visible;
+}
+
+static void
+_e_deskmirror_mirror_del(Mirror *m)
+{
+   eina_hash_del_by_key(m->sd->mirror_hash, &m->cw);
+}
+
+static void
+_e_deskmirror_mirror_del_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+   _e_deskmirror_mirror_del(data);
+}
+
+static void
+_e_deskmirror_mirror_del_hash(Mirror *m)
+{
+   m->sd->mirrors = eina_inlist_remove(m->sd->mirrors, EINA_INLIST_GET(m));
+   evas_object_event_callback_del_full(m->mirror, EVAS_CALLBACK_DEL, _e_deskmirror_mirror_del_cb, m);
+   evas_object_del(m->mirror);
+   free(m);
+}
+
+static void
+_e_deskmirror_mirror_geometry_get(Mirror *m)
+{
+   if (m->cw->bd)
+     {
+        m->x = m->cw->bd->x;
+        m->y = m->cw->bd->y;
+        m->w = m->cw->bd->w;
+        if (m->cw->bd->shaded)
+          m->h = m->cw->bd->client_inset.t;
+        else
+          m->h = m->cw->bd->h;
+     }
+   else if (m->cw->not_in_layout)
+     evas_object_geometry_get(m->cw->effect_obj, &m->x, &m->y, &m->w, &m->h);
+   else
+     e_layout_child_geometry_get(m->cw->effect_obj, &m->x, &m->y, &m->w, &m->h);
+   /* double check here if we get zeroes */
+   if ((!m->w) || (!m->h))
+     {
+        m->w = m->cw->w, m->h = m->cw->h;
+        m->x = m->cw->x, m->y = m->cw->y;
+     }
+}
+
+static void
+_e_deskmirror_mirror_reconfigure(Mirror *m)
+{
+   _e_deskmirror_mirror_geometry_get(m);
+   e_layout_child_move(m->mirror, m->x, m->y);
+   e_layout_child_resize(m->mirror, m->w, m->h);
+   if (_e_deskmirror_win_visible_get(m->sd, m->cw) && m->w && m->h)
+     evas_object_show(m->mirror);
+   else
+     evas_object_hide(m->mirror);
+}
+
+static Evas_Object *
+_mirror_border_new(Mirror *m)
+{
+   Evas_Object *o;
+   Mirror_Border *mb;
+   char buf[4096];
+
+   _mirror_border_smart_init();
+   o = evas_object_smart_add(m->sd->e, _mirror_border_smart);
+   mb = evas_object_smart_data_get(o);
+   mb->m = m;
+   mb->frame = edje_object_add(m->sd->e);
+   evas_object_name_set(mb->frame, "mirror_border");
+   snprintf(buf, sizeof(buf), "e/deskmirror/frame/%s", m->cw->bd->client.border.name);
+   e_theme_edje_object_set(mb->frame, "base/theme/borders", buf);
+   if (e_util_border_shadow_state_get(m->cw->bd))
+     edje_object_signal_emit(mb->frame, "e,state,shadow,on", "e");
+   else
+     edje_object_signal_emit(mb->frame, "e,state,shadow,off", "e");
+   edje_object_signal_callback_add(mb->m->cw->bd->bg_object, "*", "*", _mirror_border_signal_cb, mb);
+   if (e_border_focused_get() == mb->m->cw->bd)
+     edje_object_signal_emit(mb->frame, "e,state,focused", "e");
+   if (mb->m->cw->bd->shaded)
+     edje_object_signal_emit(mb->frame, "e,state,shaded", "e");
+   if (mb->m->cw->bd->maximized)
+     edje_object_signal_emit(mb->frame, "e,action,maximize", "e");
+   if (mb->m->cw->bd->sticky)
+     edje_object_signal_emit(mb->frame, "e,state,sticky", "e");
+
+   mb->mirror = m->mirror;
+   evas_object_smart_member_add(mb->frame, o);
+   evas_object_name_set(mb->mirror, "mirror");
+   evas_object_smart_member_add(mb->mirror, o);
+   edje_object_part_swallow(mb->frame, "e.swallow.client", m->mirror);
+   edje_object_part_text_set(mb->frame, "e.text.title", m->cw->bd->client.netwm.name ?: m->cw->bd->client.icccm.name);
+   _mirror_scale_set(m, (double)m->sd->h / (double)m->sd->desk->zone->h);
+   evas_object_event_callback_add(m->cw->bd->bg_object, EVAS_CALLBACK_DEL, _e_deskmirror_mirror_frame_del_cb, mb);
+   return o;
+}
+
+static void
+_e_deskmirror_mirror_setup(Mirror *m)
+{
+   if (!m->mirror) return;
+   if (m->cw->bd && m->cw->bd->bg_object)
+     {
+        m->mirror = _mirror_border_new(m);
+        m->frame = 1;
+     }
+   else
+     evas_object_pass_events_set(m->mirror, 1);
+   e_layout_pack(m->sd->layout, m->mirror);
+   evas_object_event_callback_add(m->mirror, EVAS_CALLBACK_DEL, _e_deskmirror_mirror_del_cb, m);
+   _e_deskmirror_mirror_reconfigure(m);
+}
+
+static Mirror *
+_e_deskmirror_mirror_add(E_Smart_Data *sd, E_Comp_Win *cw)
+{
+   Mirror *m;
+   Evas_Object *o = NULL;
+
+   if (cw->bd)
+     {
+        if ((cw->bd->zone != sd->desk->zone) || ((cw->bd->desk != sd->desk) && (!cw->bd->sticky)))
+          return NULL;
+     }
+   else
+     {
+        int x, y;
+
+        if (!sd->desk->visible) return NULL;
+        if (cw->not_in_layout)
+          evas_object_geometry_get(cw->effect_obj, &x, &y, NULL, NULL);
+        else
+          e_layout_child_geometry_get(cw->effect_obj, &x, &y, NULL, NULL);
+        if (!E_INSIDE(x, y, sd->desk->zone->x, sd->desk->zone->y, sd->desk->zone->w, sd->desk->zone->h)) return NULL;
+     }
+   if ((cw->w > 1) && (cw->h > 1))
+     {
+        o = e_comp_win_image_mirror_add(cw);
+        if (!o) return NULL;
+     }
+   m = calloc(1, sizeof(Mirror));
+   m->cw = cw;
+   m->sd = sd;
+   m->mirror = o;
+   sd->mirrors = eina_inlist_append(sd->mirrors, EINA_INLIST_GET(m));
+   eina_hash_direct_add(sd->mirror_hash, &m->cw, m);
+   _e_deskmirror_mirror_setup(m);
+   return m;
+}
+
+static Eina_Bool
+_comp_source_add(E_Smart_Data *sd, int type EINA_UNUSED, E_Event_Comp *ev)
+{
+   if (eina_hash_find(sd->mirror_hash, &ev->cw)) return ECORE_CALLBACK_RENEW;
+   _e_deskmirror_mirror_add(sd, ev->cw);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_comp_source_visible(E_Smart_Data *sd, int type EINA_UNUSED, E_Event_Comp *ev)
+{
+   Mirror *m;
+
+   m = eina_hash_find(sd->mirror_hash, &ev->cw);
+   if (!m) return ECORE_CALLBACK_RENEW;
+   if (!m->mirror)
+     {
+        if ((m->cw->w < 2) || (m->cw->h < 2)) return ECORE_CALLBACK_RENEW;
+        m->mirror = e_comp_win_image_mirror_add(m->cw);
+        _e_deskmirror_mirror_setup(m);
+     }
+   if (_e_deskmirror_win_visible_get(m->sd, m->cw))
+     evas_object_show(m->mirror);
+   else
+     evas_object_hide(m->mirror);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_comp_source_stack(E_Smart_Data *sd, int type EINA_UNUSED, E_Event_Comp *ev)
+{
+   Mirror *m, *m2;
+   E_Comp_Win *cw;
+
+   m = eina_hash_find(sd->mirror_hash, &ev->cw);
+   if (!m) return ECORE_CALLBACK_RENEW;
+   if (!m->mirror)
+     {
+        if ((m->cw->w < 2) || (m->cw->h < 2)) return ECORE_CALLBACK_RENEW;
+        m->mirror = e_comp_win_image_mirror_add(m->cw);
+        _e_deskmirror_mirror_setup(m);
+     }
+   if (!EINA_INLIST_GET(ev->cw)->next)
+     e_layout_child_raise(m->mirror);
+   else if (!EINA_INLIST_GET(ev->cw)->prev)
+     e_layout_child_lower(m->mirror);
+   else
+     {
+        EINA_INLIST_FOREACH(EINA_INLIST_GET(ev->cw)->next, cw)
+          {
+             m2 = eina_hash_find(sd->mirror_hash, &cw);
+             if ((!m2) || (!m2->mirror)) continue;
+             e_layout_child_lower_below(m->mirror, m2->mirror);
+             return ECORE_CALLBACK_RENEW;
+          }
+        e_layout_child_raise(m->mirror);
+     }
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_comp_source_configure(E_Smart_Data *sd, int type EINA_UNUSED, E_Event_Comp *ev)
+{
+   Mirror *m;
+
+   m = eina_hash_find(sd->mirror_hash, &ev->cw);
+   if (m)
+     {
+        if (!m->mirror)
+          {
+             if ((m->cw->w < 2) || (m->cw->h < 2)) return ECORE_CALLBACK_RENEW;
+             m->mirror = e_comp_win_image_mirror_add(m->cw);
+             _e_deskmirror_mirror_setup(m);
+          }
+        _e_deskmirror_mirror_reconfigure(m);
+     }
+   return ECORE_CALLBACK_RENEW;
+}
+
+/* externally accessible functions */
+EAPI Evas_Object *
+e_deskmirror_add(E_Desk *desk)
+{
+   E_Smart_Data *sd;
+   Evas_Object *o;
+   Evas *e;
+   E_Comp_Win *cw;
+
+   e = e_comp_get(desk)->evas;
+   _e_deskmirror_smart_init();
+   o = evas_object_smart_add(e, _e_deskmirror_smart);
+   sd = evas_object_smart_data_get(o);
+   sd->desk = desk;
+   sd->mirror_hash = eina_hash_pointer_new((Eina_Free_Cb)_e_deskmirror_mirror_del_hash);
+   sd->desk_delfn = e_object_delfn_add(E_OBJECT(desk), (Ecore_End_Cb)_e_deskmirror_delfn, sd);
+   sd->bgpreview = e_widget_bgpreview_desk_add(e, desk->zone, desk->x, desk->y);
+   evas_object_clip_set(sd->bgpreview, sd->clip);
+   evas_object_smart_member_add(sd->bgpreview, o);
+   evas_object_show(sd->bgpreview);
+   sd->layout = e_layout_add(e);
+   evas_object_clip_set(sd->layout, sd->clip);
+   e_layout_virtual_size_set(sd->layout, desk->zone->w, desk->zone->h);
+   evas_object_smart_member_add(sd->layout, o);
+   evas_object_show(sd->layout);
+
+   e_layout_freeze(sd->layout);
+
+   EINA_INLIST_FOREACH(e_comp_get(desk)->wins, cw)
+     {
+        Mirror *m;
+
+        m = _e_deskmirror_mirror_add(sd, cw);
+        if (m) e_layout_child_raise(m->mirror);
+     }
+
+   e_layout_thaw(sd->layout);
+
+   E_LIST_HANDLER_APPEND(sd->handlers, E_EVENT_COMP_SOURCE_ADD, _comp_source_add, sd);
+   E_LIST_HANDLER_APPEND(sd->handlers, E_EVENT_COMP_SOURCE_CONFIGURE, _comp_source_configure, sd);
+   E_LIST_HANDLER_APPEND(sd->handlers, E_EVENT_COMP_SOURCE_STACK, _comp_source_stack, sd);
+   E_LIST_HANDLER_APPEND(sd->handlers, E_EVENT_COMP_SOURCE_VISIBILITY, _comp_source_visible, sd);
+   return o;
+}
+
+EAPI void
+e_deskmirror_util_wins_print(Evas_Object *obj)
+{
+   E_Smart_Data *sd;
+   Mirror *m;
+
+   EINA_SAFETY_ON_NULL_RETURN(obj);
+   sd = evas_object_smart_data_get(obj);
+   EINA_INLIST_FOREACH(sd->mirrors, m)
+     {
+        if (m->cw->bd)
+          fprintf(stderr, "MIRROR BD:  %p - %u '%s:%s'\n", m->cw, m->cw->win, m->cw->bd->client.icccm.name, m->cw->bd->client.icccm.class);
+        else if (m->cw->pop)
+          fprintf(stderr, "MIRROR POP: %p - %s\n", m->cw, m->cw->pop->name);
+        else if (m->cw->menu)
+          fprintf(stderr, "MIRROR MENU: %p - %s\n", m->cw, m->cw->menu->header.title);
+        else if (m->cw->real_obj)
+          fprintf(stderr, "MIRROR OBJ: %p - %s\n", m->cw, evas_object_name_get(m->cw->obj));
+        else
+          fprintf(stderr, "MIRROR WIN: %p - %u%s\n", m->cw, m->cw->win, m->cw->input_only ? " INPUT" : "");
+     }
+}
diff --git a/src/bin/e_deskmirror.h b/src/bin/e_deskmirror.h
new file mode 100644 (file)
index 0000000..aabbc77
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef E_WIDGET_DESKMIRROR_H
+#define E_WIDGET_DESKMIRROR_H
+
+EAPI Evas_Object *e_deskmirror_add(E_Desk *desk);
+EAPI void e_deskmirror_util_wins_print(Evas_Object *obj);
+//#define DESKMIRROR_TEST
+
+#endif
index 809caa7..68b7278 100644 (file)
 #include "e_filereg.h"
 #include "e_widget_aspect.h"
 #include "e_widget_bgpreview.h"
+#include "e_deskmirror.h"
 #include "e_fm_prop.h"
 #include "e_mouse.h"
 #include "e_order.h"
index a8faaa6..3586a1b 100644 (file)
@@ -31,7 +31,6 @@ static void _e_border_menu_cb_fullscreen(void *data, E_Menu *m, E_Menu_Item *mi)
 static void _e_border_menu_cb_skip_winlist(void *data, E_Menu *m, E_Menu_Item *mi);
 static void _e_border_menu_cb_skip_pager(void *data, E_Menu *m, E_Menu_Item *mi);
 static void _e_border_menu_cb_skip_taskbar(void *data, E_Menu *m, E_Menu_Item *mi);
-static void _e_border_menu_cb_sendto_icon_pre(void *data, E_Menu *m, E_Menu_Item *mi);
 static void _e_border_menu_cb_sendto_pre(void *data, E_Menu *m, E_Menu_Item *mi);
 static void _e_border_menu_cb_sendto(void *data, E_Menu *m, E_Menu_Item *mi);
 static void _e_border_menu_cb_pin(void *data, E_Menu *m, E_Menu_Item *mi);
@@ -881,7 +880,8 @@ _e_border_menu_cb_skip_taskbar(void *data, E_Menu *m __UNUSED__, E_Menu_Item *mi
    e_remember_update(bd);
 }
 
-static void
+#ifndef DESKMIRROR_TEST
+ static void
 _e_border_menu_cb_sendto_icon_pre(void *data, E_Menu *m, E_Menu_Item *mi)
 {
    E_Desk *desk = NULL;
@@ -903,6 +903,7 @@ _e_border_menu_cb_sendto_icon_pre(void *data, E_Menu *m, E_Menu_Item *mi)
    e_thumb_icon_begin(o);
    mi->icon_object = o;
 }
+#endif
 
 static void
 _e_border_menu_cb_sendto_pre(void *data, E_Menu *m __UNUSED__, E_Menu_Item *mi)
@@ -935,24 +936,35 @@ _e_border_menu_cb_sendto_pre(void *data, E_Menu *m __UNUSED__, E_Menu_Item *mi)
              e_menu_item_disabled_set(submi, EINA_TRUE);
           }
 
-// FIXME: Remove labels and add bgpreview to menu.
-// Evas_Object *o = e_widget_bgpreview_add(m->evas, 4, 2);
-
         for (i = 0; i < zone->desk_x_count * zone->desk_y_count; i++)
           {
              E_Desk *desk;
-
+#ifdef DESKMIRROR_TEST
+             int tw = 50, th;
+#endif
              desk = zone->desks[i];
+#ifdef DESKMIRROR_TEST
+             th = (tw * desk->zone->h) / desk->zone->w;
+#endif
              submi = e_menu_item_new(subm);
              e_menu_item_label_set(submi, desk->name);
              e_menu_item_radio_set(submi, 1);
              e_menu_item_radio_group_set(submi, 2);
+#ifdef DESKMIRROR_TEST
+             e_menu_item_icon_file_set(submi, "sup");
+#endif
              if ((bd->zone == zone) && (desk_cur == desk))
                e_menu_item_toggle_set(submi, 1);
              else
                e_menu_item_callback_set(submi, _e_border_menu_cb_sendto, desk);
+#ifdef DESKMIRROR_TEST
+             submi->icon_object = e_deskmirror_add(desk);
+             edje_extern_object_min_size_set(submi->icon_object, tw, th);
+             evas_object_show(submi->icon_object);
+#else
              e_menu_item_realize_callback_set(submi, _e_border_menu_cb_sendto_icon_pre,
                                               desk);
+#endif
           }
      }
 }
index 8a5fe34..4d9a14c 100644 (file)
@@ -2,6 +2,25 @@
 
 static void _e_test_internal(E_Container *con);
 
+#ifdef DESKMIRROR_TEST
+
+static Eina_Bool
+deskmirror_test(void *d EINA_UNUSED)
+{
+   E_Zone *zone;
+   Evas_Object *o;
+   E_Popup *pop;
+
+   zone = e_util_zone_current_get(e_manager_current_get());
+   pop = e_popup_new(zone, zone->x + zone->w / 4, zone->y + zone->h / 4, zone->w / 2, zone->h / 2);
+   o = e_deskmirror_add(e_desk_current_get(zone));
+   e_popup_content_set(pop, o);
+   e_popup_show(pop);
+   return EINA_FALSE;
+}
+
+#endif
+
 EAPI void
 e_test(void)
 {
@@ -16,6 +35,10 @@ e_test(void)
              _e_test_internal(con);
           }
      }
+
+#ifdef DESKMIRROR_TEST
+   ecore_timer_add(2.0, deskmirror_test, NULL);
+#endif
 }
 
 #if 0