Elementary support for EWS, with simplistic window manager.
authorbarbieri <barbieri@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Wed, 5 Oct 2011 22:18:22 +0000 (22:18 +0000)
committerbarbieri <barbieri@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Wed, 5 Oct 2011 22:18:22 +0000 (22:18 +0000)
This contains a very simple and stupid window manager to be used in
FB, PS3 or similar single-window engines. Everybody is welcome to
improve it, particularly:
 * Edje: better border decoration theme
 * Edje: nice background
 * C + Edje: taskbar with minimized items.
 * C + Edje: find a better protocol to determine window size,
   accounting border decoration without account shadow! Right now I'm
   taking everything :-P
 * C: window management keys (Alt+F4 and like)

How to use: export ELM_ENGINE=ews
How to configure backing store: export ECORE_EVAS_EWS=engine:x:y:w:h:options
Example:
{{{
export ECORE_EVAS_EWS=software_x11:0:0:1024:768
export ELM_ENGINE=ews
elementary_test
}}}

Bugs: maybe many, but so far seems it wouldn't take mouse events for
secondary windows. Will check it later.

git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/elementary@63849 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

data/themes/Makefile.am
data/themes/default.edc
data/themes/ews.edc [new file with mode: 0644]
src/lib/Elementary.h.in
src/lib/Makefile.am
src/lib/elm_config.c
src/lib/elm_main.c
src/lib/elm_priv.h
src/lib/elm_theme.c
src/lib/elm_win.c
src/lib/elu_ews_wm.c [new file with mode: 0644]

index f145f6f..7496bfc 100644 (file)
@@ -60,6 +60,7 @@ widgets/win.edc \
 widgets/entry.edc \
 widgets/map.edc \
 widgets/scroller.edc \
+ews.edc \
 arrow_down.png \
 arrow_up.png \
 bar_shine.png \
index d362756..f24beb0 100644 (file)
@@ -365,4 +365,6 @@ collections {
 #include "widgets/video.edc"
 #include "widgets/naviframe.edc"
 
+#include "ews.edc"
+
 }
diff --git a/data/themes/ews.edc b/data/themes/ews.edc
new file mode 100644 (file)
index 0000000..c3e70fe
--- /dev/null
@@ -0,0 +1,317 @@
+group { name: "elm/ews/background/default";
+   parts {
+      part { name: "base";
+         type: RECT;
+         mouse_events:  0;
+         description { state: "default" 0.0;
+            color: 64 64 64 255;
+         }
+      }
+   }
+}
+
+/*
+  Border Decorations Protocol:
+
+  Receive Signals: all use "elm" as source
+   - elm,state,focus,{on,off}
+   - elm,state,iconified,{on,off}
+   - elm,state,maximized,{on,off}
+   - elm,state,fullscreen,{on,off}
+   - elm,state,alpha,{on,off}
+
+  Send Signals:
+   - elm,action,focus
+   - elm,action,iconify
+   - elm,action,maximize
+   - elm,action,fullscreen
+   - elm,action,restore     - remove iconified, maximized or fullscreen
+   - elm,action,close
+   - elm,action,menu
+   - elm,action,move,start
+   - elm,action,move,stop
+
+  Parts:
+   - elm.text.title
+   - elm.text.name
+   - elm.text.class
+ */
+
+images {
+   image: "shadow.png" COMP;
+   image: "icon_close.png" COMP;
+   image: "icon_arrow_up_right.png" COMP;
+   image: "icon_arrow_down_left.png" COMP;
+}
+
+group { name: "elm/ews/decoration/borderless";
+   parts {
+      part { name: "shadow";
+         type: IMAGE;
+         mouse_events:  0;
+         description { state: "default" 0.0;
+            image {
+               normal: "shadow.png";
+               border: 13 13 13 13;
+               middle: 0;
+            }
+            rel1 {
+               to: "base";
+               offset: -11 -9;
+            }
+            rel2 {
+               to: "base";
+               offset: 11 11;
+            }
+            fill.smooth: 0;
+         }
+         description { state: "hidden" 0.0;
+            inherit: "default" 0.0;
+            visible: 0;
+         }
+      }
+      programs {
+         program { signal: "elm,state,alpha,on";
+            source: "elm";
+            action: STATE_SET "hidden" 0.0;
+            target: "shadow";
+         }
+         program { signal: "elm,state,alpha,off";
+            source: "elm";
+            action: STATE_SET "visible" 0.0;
+            target: "shadow";
+         }
+      }
+
+      part { name: "base";
+         type: RECT;
+         mouse_events: 0;
+         description { state: "default" 0.0;
+            color: 0 0 0 255;
+         }
+      }
+   }
+}
+
+group { name: "elm/ews/decoration/default";
+   parts {
+      part { name: "shadow";
+         type: IMAGE;
+         mouse_events:  0;
+         description { state: "default" 0.0;
+            image {
+               normal: "shadow.png";
+               border: 13 13 13 13;
+               middle: 0;
+            }
+            rel1 {
+               to: "base";
+               offset: -11 -9;
+            }
+            rel2 {
+               to: "base";
+               offset: 11 11;
+            }
+            fill.smooth: 0;
+         }
+         description { state: "hidden" 0.0;
+            inherit: "default" 0.0;
+            visible: 0;
+         }
+      }
+      programs {
+         program { signal: "elm,state,alpha,on";
+            source: "elm";
+            action: STATE_SET "hidden" 0.0;
+            target: "shadow";
+         }
+         program { signal: "elm,state,alpha,off";
+            source: "elm";
+            action: STATE_SET "visible" 0.0;
+            target: "shadow";
+         }
+      }
+
+      part { name: "base";
+         type: RECT;
+         mouse_events: 0;
+         description { state: "default" 0.0;
+            // TODO: make me a nice image!
+            color: 200 200 200 255;
+            rel1.offset: -2 -32;
+            rel2.offset: 1 1;
+         }
+      }
+
+      part { name: "base-text";
+         type: RECT;
+         mouse_events: 1;
+         description { state: "default" 0.0;
+            color: 0 0 0 0;
+            rel1.to: "base";
+            rel2 {
+               offset: -2 -1;
+               relative: 0.0 0.0;
+               to_x: "base-buttons";
+            }
+         }
+      }
+      programs {
+         program { signal: "mouse,down,1";
+            source: "base-text";
+            action: SIGNAL_EMIT "elm,action,move,start" "elm";
+         }
+         program { signal: "mouse,up,1";
+            source: "base-text";
+            action: SIGNAL_EMIT "elm,action,move,stop" "elm";
+         }
+      }
+
+      part { name: "elm.text.title";
+         type: TEXT;
+         effect: SHADOW;
+         mouse_events: 0;
+         description { state: "default" 0.0;
+            color: 255 255 255 255;
+            color3: 0 0 0 255;
+            rel1 {
+               to: "base-text";
+               offset: 5 2;
+            }
+            rel2 {
+               to: "base-text";
+               offset: -6 -3;
+            }
+            text {
+               font: "Sans:style=Bold";
+               size: 12;
+               align: 0.0 0.5;
+            }
+         }
+      }
+
+      part { name: "base-buttons";
+         type: RECT;
+         mouse_events: 0;
+         description { state: "default" 0.0;
+            color: 255 255 255 0;
+            rel1 {
+               to: "base";
+               relative: 1.0 0.0;
+               offset: (-24 * 3 -1) 0;
+            }
+            rel2 {
+               relative: 1.0 0.0;
+               offset: -1 -1;
+            }
+         }
+      }
+
+      part { name: "restore";
+         type: IMAGE;
+         mouse_events: 1;
+         description { state: "default" 0.0;
+            image.normal: "icon_arrow_down_left.png";
+            min: 24 24;
+            max: 24 24;
+            rel1 {
+               to: "base-buttons";
+               relative: 1.0 0.0;
+               offset: (-24 * 3 - 1) 0;
+            }
+            rel2 {
+               to: "base-buttons";
+               relative: 1.0 1.0;
+               offset: (-24 * 2 - 1) 0;
+            }
+         }
+      }
+      programs {
+         program { signal: "mouse,clicked,1";
+            source: "restore";
+            action: SIGNAL_EMIT "elm,action,restore" "elm";
+         }
+      }
+
+      part { name: "maximize";
+         type: IMAGE;
+         mouse_events: 0;
+         description { state: "default" 0.0;
+            image.normal: "icon_arrow_up_right.png";
+            min: 24 24;
+            max: 24 24;
+            rel1 {
+               to: "base-buttons";
+               relative: 1.0 0.0;
+               offset: (-24 * 2 - 1) 0;
+            }
+            rel2 {
+               to: "base-buttons";
+               relative: 1.0 1.0;
+               offset: (-24 * 1 - 1) 0;
+            }
+         }
+         description { state: "maximized" 0.0;
+            inherit: "default" 0.0;
+            color: 255 255 255 96;
+         }
+      }
+      part { name: "maximize-eventarea";
+         type: RECT;
+         mouse_events: 1;
+         description { state: "default" 0.0;
+            color: 0 0 0 0;
+            rel1.to: "maximize";
+            rel2.to: "maximize";
+         }
+         description { state: "maximized" 0.0;
+            inherit: "default" 0.0;
+            visible: 0;
+         }
+      }
+      programs {
+         program { signal: "mouse,clicked,1";
+            source: "maximize-eventarea";
+            action: SIGNAL_EMIT "elm,action,maximize" "elm";
+         }
+         program { signal: "elm,state,maximized,on";
+            source: "elm";
+            action: STATE_SET "maximized" 0.0;
+            target: "maximize-eventarea";
+            target: "maximize";
+         }
+         program { signal: "elm,state,maximized,off";
+            source: "elm";
+            action: STATE_SET "default" 0.0;
+            target: "maximize-eventarea";
+            target: "maximize";
+         }
+      }
+
+      part { name: "close";
+         type: IMAGE;
+         mouse_events: 1;
+         description { state: "default" 0.0;
+            image.normal: "icon_close.png";
+            min: 24 24;
+            max: 24 24;
+            rel1 {
+               to: "base-buttons";
+               relative: 1.0 0.0;
+               offset: (-24 * 1 - 1) 0;
+            }
+            rel2 {
+               to: "base-buttons";
+               relative: 1.0 1.0;
+               offset: (-24 * 0 - 1) 0;
+            }
+         }
+      }
+      programs {
+         program { signal: "mouse,clicked,1";
+            source: "close";
+            action: SIGNAL_EMIT "elm,action,close" "elm";
+         }
+      }
+   }
+}
index 372687c..b37ae53 100644 (file)
@@ -1889,6 +1889,7 @@ extern "C" {
     * @li "software_16_sdl"
     * @li "opengl_sdl"
     * @li "buffer"
+    * @li "ews"
     *
     * @{
     */
@@ -3518,6 +3519,7 @@ extern "C" {
     * (Windows CE rendering via GDI with 16bit software renderer)
     * @li "sdl-16", "software-16-sdl", "software_16_sdl" (Rendering to SDL
     * buffer with 16bit software renderer)
+    * @li "ews" (rendering to EWS - Ecore + Evas Single Process Windowing System)
     *
     * All engines use a simple string to select the engine to render, EXCEPT
     * the "shot" engine. This actually encodes the output of the virtual
index 941ce64..c6b02dd 100644 (file)
@@ -125,7 +125,8 @@ els_pan.c \
 els_pan.h \
 els_scroller.c \
 els_scroller.h \
-els_tooltip.c
+els_tooltip.c \
+elu_ews_wm.c
 
 libelementary_la_CFLAGS =
 libelementary_la_LIBADD = \
index a6c76f3..59aec78 100644 (file)
@@ -31,6 +31,7 @@ const char *_elm_engines[] = {
    "software_16_sdl",
    "opengl_sdl",
    "buffer",
+   "ews",
    NULL
 };
 
@@ -1469,6 +1470,8 @@ _env_get(void)
           eina_stringshare_replace(&_elm_config->engine, ELM_BUFFER);
         else if ((!strncmp(s, "shot:", 5)))
           eina_stringshare_replace(&_elm_config->engine, s);
+        else if ((!strcasecmp(s, "ews")))
+          eina_stringshare_replace(&_elm_config->engine, ELM_EWS);
      }
 
    s = getenv("ELM_VSYNC");
index 5f19d5d..ebb01ee 100644 (file)
@@ -79,6 +79,7 @@ _elm_rescale(void)
 {
    edje_scale_set(_elm_config->scale);
    _elm_win_rescale(NULL, EINA_FALSE);
+   _elm_ews_wm_rescale(NULL, EINA_FALSE);
 }
 
 static void *app_mainfunc = NULL;
@@ -425,6 +426,7 @@ elm_quicklaunch_sub_init(int    argc,
         ecore_imf_init();
         ecore_con_init();
         ecore_con_url_init();
+        _elm_ews_wm_init();
      }
    return _elm_sub_init_count;
 }
@@ -444,6 +446,7 @@ elm_quicklaunch_sub_shutdown(void)
      {
         _elm_win_shutdown();
         _elm_module_shutdown();
+        _elm_ews_wm_shutdown();
         ecore_con_url_shutdown();
         ecore_con_shutdown();
         ecore_imf_shutdown();
@@ -458,7 +461,8 @@ elm_quicklaunch_sub_shutdown(void)
             ENGINE_COMPARE(ELM_SOFTWARE_16_SDL) ||
             ENGINE_COMPARE(ELM_OPENGL_SDL) ||
             ENGINE_COMPARE(ELM_SOFTWARE_WIN32) ||
-            ENGINE_COMPARE(ELM_SOFTWARE_16_WINCE))
+            ENGINE_COMPARE(ELM_SOFTWARE_16_WINCE) ||
+            ENGINE_COMPARE(ELM_EWS))
 #undef ENGINE_COMPARE
           evas_cserve_disconnect();
         edje_shutdown();
index 6575ff0..b2866fe 100644 (file)
@@ -80,6 +80,7 @@ extern const char *_elm_engines[];
 #define ELM_SOFTWARE_16_SDL   (_elm_engines[10])
 #define ELM_OPENGL_SDL        (_elm_engines[11])
 #define ELM_BUFFER            (_elm_engines[12])
+#define ELM_EWS               (_elm_engines[13])
 
 #define ELM_FONT_TOKEN_STYLE ":style="
 
@@ -167,6 +168,10 @@ struct _Elm_Module
    int          references;
 };
 
+int                 _elm_ews_wm_init(void);
+void                _elm_ews_wm_shutdown(void);
+void                _elm_ews_wm_rescale(Elm_Theme *th, Eina_Bool use_theme);
+
 void                _elm_win_shutdown(void);
 void                _elm_win_rescale(Elm_Theme *th, Eina_Bool use_theme);
 
index 04642c4..9d123b4 100644 (file)
@@ -570,6 +570,7 @@ elm_theme_flush(Elm_Theme *th)
    if (th->cache_data) eina_hash_free(th->cache_data);
    th->cache_data = eina_hash_string_superfast_new(EINA_FREE_CB(eina_stringshare_del));
    _elm_win_rescale(th, EINA_TRUE);
+   _elm_ews_wm_rescale(th, EINA_TRUE);
    if (th->referrers)
      {
         Eina_List *l;
index 337e231..aa00bd0 100644 (file)
@@ -1479,6 +1479,10 @@ elm_win_add(Evas_Object *parent, const char *name, Elm_Win_Type type)
           {
              win->ee = ecore_evas_buffer_new(1, 1);
           }
+        else if (ENGINE_COMPARE(ELM_EWS))
+          {
+             win->ee = ecore_evas_ews_new(0, 0, 1, 1);
+          }
         else if (!strncmp(_elm_config->engine, "shot:", 5))
           {
              win->ee = ecore_evas_buffer_new(1, 1);
diff --git a/src/lib/elu_ews_wm.c b/src/lib/elu_ews_wm.c
new file mode 100644 (file)
index 0000000..de8fcfa
--- /dev/null
@@ -0,0 +1,542 @@
+#include <Elementary.h>
+#include "elm_priv.h"
+
+static Eina_Bool _ews_used = EINA_FALSE;
+static Eina_List *_ews_ev_handlers = NULL;
+static Eina_Hash *_ews_borders = NULL;
+static Eina_Hash *_ews_borders_geo = NULL;
+static Evas_Object *_ews_bg = NULL;
+static Ecore_Animator *_ews_border_mover = NULL;
+static Evas_Object *_ews_border_mover_obj = NULL;
+static Evas_Point _ews_border_mover_off = {0, 0};
+
+static void
+_elm_ews_border_usable_screen_geometry_get(int *x, int *y, int *w, int *h)
+{
+   Ecore_Evas *ee = ecore_evas_ews_ecore_evas_get();
+   ecore_evas_geometry_get(ee, NULL, NULL, w, h);
+   if (x) *x = 0;
+   if (y) *y = 0;
+   // TODO: when add a shelf for iconified, subtract its area here.
+}
+
+static void
+_elm_ews_wm_border_del(void *data)
+{
+   Evas_Object *deco = data;
+   evas_object_del(deco);
+
+   if (_ews_border_mover_obj == deco)
+     {
+        if (_ews_border_mover)
+          {
+             ecore_animator_del(_ews_border_mover);
+             _ews_border_mover = NULL;
+          }
+        _ews_border_mover_obj = NULL;
+     }
+}
+
+static Evas_Object *
+_elm_ews_wm_border_find(const Ecore_Evas *ee)
+{
+   return eina_hash_find(_ews_borders, &ee);
+}
+
+static Eina_Rectangle *
+_elm_ews_wm_border_geo_find(const Ecore_Evas *ee)
+{
+   return eina_hash_find(_ews_borders_geo, &ee);
+}
+
+static void
+_elm_ews_border_geo_apply(Ecore_Evas *ee, Evas_Object *o)
+{
+   int x, y, w, h;
+   ecore_evas_geometry_get(ee, &x, &y, &w, &h);
+   evas_object_move(o, x, y);
+   evas_object_resize(o, w, h);
+}
+
+static void
+_elm_ews_border_focus_apply(Ecore_Evas *ee, Evas_Object *o)
+{
+   const char *sig;
+   if (ecore_evas_focus_get(ee))
+     sig = "elm,state,focus,on";
+   else
+     sig = "elm,state,focus,off";
+   edje_object_signal_emit(o, sig, "elm");
+}
+
+static void
+_elm_ews_border_stack_apply(Ecore_Evas *ee, Evas_Object *o)
+{
+   Evas_Object *bs_o = ecore_evas_ews_backing_store_get(ee);
+   evas_object_stack_below(o, bs_o);
+}
+
+static void
+_elm_ews_border_iconified_apply(Ecore_Evas *ee, Evas_Object *o)
+{
+   const char *sig;
+   if (ecore_evas_iconified_get(ee))
+     sig = "elm,state,iconified,on";
+   else
+     sig = "elm,state,iconified,off";
+   edje_object_signal_emit(o, sig, "elm");
+
+   // TODO: add to some taskbar? and actually hide it?
+   DBG("EWS does not implement iconified yet");
+}
+
+static void
+_elm_ews_border_maximized_apply(Ecore_Evas *ee, Evas_Object *o)
+{
+   int x, y, w, h;
+   if (ecore_evas_maximized_get(ee))
+     {
+        Eina_Rectangle *r;
+        int ex, ey, ew, eh;
+
+        edje_object_signal_emit(o, "elm,state,maximized,on", "elm");
+        edje_object_message_signal_process(o);
+        ecore_evas_geometry_get(ee, &x, &y, &w, &h);
+
+        r = _elm_ews_wm_border_geo_find(ee);
+        if (!r)
+          {
+             r = malloc(sizeof(Eina_Rectangle));
+             eina_hash_add(_ews_borders_geo, &ee, r);
+          }
+
+        r->x = x;
+        r->y = y;
+        r->w = w;
+        r->h = h;
+        _elm_ews_border_usable_screen_geometry_get(&x, &y, &w, &h);
+        edje_object_parts_extends_calc(o, &ex, &ey, &ew, &eh);
+        x -= ex;
+        y -= ey;
+        w -= ew - r->w;
+        h -= eh - r->h;
+     }
+   else
+     {
+        Eina_Rectangle *r = _elm_ews_wm_border_geo_find(ee);
+        edje_object_signal_emit(o, "elm,state,maximized,off", "elm");
+
+        if (!r) ecore_evas_geometry_get(ee, &x, &y, &w, &h);
+        else
+          {
+             x = r->x;
+             y = r->y;
+             w = r->w;
+             h = r->h;
+          }
+     }
+
+   ecore_evas_move_resize(ee, x, y, w, h);
+   _elm_ews_border_geo_apply(ee, o);
+}
+
+static void
+_elm_ews_border_layer_apply(Ecore_Evas *ee, Evas_Object *o)
+{
+   Evas_Object *bs_o = ecore_evas_ews_backing_store_get(ee);
+   evas_object_layer_set(o, evas_object_layer_get(bs_o));
+   _elm_ews_border_stack_apply(ee, o);
+}
+
+static void
+_elm_ews_border_fullscreen_apply(Ecore_Evas *ee, Evas_Object *o)
+{
+   const char *sig;
+   if (ecore_evas_fullscreen_get(ee))
+     sig = "elm,state,fullscreen,on";
+   else
+     sig = "elm,state,fullscreen,off";
+   edje_object_signal_emit(o, sig, "elm");
+   _elm_ews_border_geo_apply(ee, o);
+}
+
+static void
+_elm_ews_border_config_apply(Ecore_Evas *ee, Evas_Object *o, Elm_Theme *th)
+{
+   const char *title, *name = NULL, *class = NULL, *style = NULL;
+   const char *sig;
+
+   if (ecore_evas_borderless_get(ee))
+     style = "borderless";
+
+   _elm_theme_set(th, o, "ews", "decoration", style ? style : "default");
+
+   if (ecore_evas_shaped_get(ee) || ecore_evas_alpha_get(ee) ||
+       ecore_evas_transparent_get(ee))
+     sig = "elm,state,alpha,on";
+   else
+     sig = "elm,state,alpha,off";
+   edje_object_signal_emit(o, sig, "elm");
+
+   title = ecore_evas_title_get(ee);
+   ecore_evas_name_class_get(ee, &name, &class);
+   edje_object_part_text_set(o, "elm.text.title", title);
+   edje_object_part_text_set(o, "elm.text.name", name);
+   edje_object_part_text_set(o, "elm.text.class", class);
+
+   _elm_ews_border_geo_apply(ee, o);
+   _elm_ews_border_focus_apply(ee, o);
+   _elm_ews_border_stack_apply(ee, o);
+   _elm_ews_border_iconified_apply(ee, o);
+   _elm_ews_border_maximized_apply(ee, o);
+   _elm_ews_border_layer_apply(ee, o);
+   _elm_ews_border_fullscreen_apply(ee, o);
+}
+
+static Eina_Bool
+_elm_ews_wm_border_theme_set(Ecore_Evas *ee, Evas_Object *o, Elm_Theme *th)
+{
+   _elm_ews_border_config_apply(ee, o, th);
+   return EINA_TRUE;
+}
+
+static void
+_elm_ews_border_sig_focus(void *data, Evas_Object *o __UNUSED__, const char *sig __UNUSED__, const char *source __UNUSED__)
+{
+   Ecore_Evas *ee = data;
+   ecore_evas_focus_set(ee, EINA_TRUE);
+}
+
+static void
+_elm_ews_border_sig_iconify(void *data, Evas_Object *o __UNUSED__, const char *sig __UNUSED__, const char *source __UNUSED__)
+{
+   Ecore_Evas *ee = data;
+   ecore_evas_iconified_set(ee, EINA_TRUE);
+}
+
+static void
+_elm_ews_border_sig_maximize(void *data, Evas_Object *o __UNUSED__, const char *sig __UNUSED__, const char *source __UNUSED__)
+{
+   Ecore_Evas *ee = data;
+   ecore_evas_maximized_set(ee, EINA_TRUE);
+}
+
+static void
+_elm_ews_border_sig_fullscreen(void *data, Evas_Object *o __UNUSED__, const char *sig __UNUSED__, const char *source __UNUSED__)
+{
+   Ecore_Evas *ee = data;
+   ecore_evas_fullscreen_set(ee, EINA_TRUE);
+}
+
+static void
+_elm_ews_border_sig_restore(void *data, Evas_Object *o __UNUSED__, const char *sig __UNUSED__, const char *source __UNUSED__)
+{
+   Ecore_Evas *ee = data;
+   ecore_evas_iconified_set(ee, EINA_FALSE);
+   ecore_evas_maximized_set(ee, EINA_FALSE);
+   ecore_evas_fullscreen_set(ee, EINA_FALSE);
+}
+
+static void
+_elm_ews_border_sig_close(void *data, Evas_Object *o __UNUSED__, const char *sig __UNUSED__, const char *source __UNUSED__)
+{
+   Ecore_Evas *ee = data;
+   ecore_evas_ews_delete_request(ee);
+}
+
+static void
+_elm_ews_border_sig_menu(void *data, Evas_Object *o __UNUSED__, const char *sig __UNUSED__, const char *source __UNUSED__)
+{
+   // TODO: show some menu?
+   ERR("EWS does not implement menu yet");
+   (void)data;
+}
+
+static Eina_Bool
+_elm_ews_border_mover(void *data)
+{
+   Ecore_Evas *ee = data;
+   Evas_Object *o = _elm_ews_wm_border_find(ee);
+   int x, y;
+
+   evas_pointer_output_xy_get(ecore_evas_ews_evas_get(), &x, &y);
+   x -= _ews_border_mover_off.x;
+   y -= _ews_border_mover_off.y;
+   ecore_evas_move(ee, x, y);
+   evas_object_move(o, x, y);
+
+   return EINA_TRUE;
+}
+
+static void
+_elm_ews_border_sig_move_start(void *data, Evas_Object *o __UNUSED__, const char *sig __UNUSED__, const char *source __UNUSED__)
+{
+   Ecore_Evas *ee = data;
+   Evas_Object *bs_o = ecore_evas_ews_backing_store_get(ee);
+   int x, y, ox, oy;
+
+   if (_ews_border_mover) ecore_animator_del(_ews_border_mover);
+
+   evas_pointer_output_xy_get(evas_object_evas_get(bs_o), &x, &y);
+   evas_object_geometry_get(bs_o, &ox, &oy, NULL, NULL);
+   _ews_border_mover_off.x = x - ox;
+   _ews_border_mover_off.y = y - oy;
+   _ews_border_mover_obj = bs_o;
+   _ews_border_mover = ecore_animator_add(_elm_ews_border_mover, ee);
+}
+
+static void
+_elm_ews_border_sig_move_stop(void *data __UNUSED__, Evas_Object *o __UNUSED__, const char *sig __UNUSED__, const char *source __UNUSED__)
+{
+   if (!_ews_border_mover) return;
+   ecore_animator_del(_ews_border_mover);
+   _ews_border_mover = NULL;
+   _ews_border_mover_obj = NULL;
+}
+
+static Eina_Bool
+_elm_ews_wm_add_cb(void *data __UNUSED__, int type __UNUSED__, void *event_info)
+{
+   Ecore_Evas *ee = event_info;
+   Evas_Object *o = edje_object_add(ecore_evas_ews_evas_get());
+   Evas_Coord x, y, w, h, sw, sh;
+
+   edje_object_signal_callback_add
+     (o, "elm,action,focus", "elm", _elm_ews_border_sig_focus, ee);
+   edje_object_signal_callback_add
+     (o, "elm,action,iconify", "elm", _elm_ews_border_sig_iconify, ee);
+   edje_object_signal_callback_add
+     (o, "elm,action,maximize", "elm", _elm_ews_border_sig_maximize, ee);
+   edje_object_signal_callback_add
+     (o, "elm,action,fullscreen", "elm", _elm_ews_border_sig_fullscreen, ee);
+   edje_object_signal_callback_add
+     (o, "elm,action,restore", "elm", _elm_ews_border_sig_restore, ee);
+   edje_object_signal_callback_add
+     (o, "elm,action,close", "elm", _elm_ews_border_sig_close, ee);
+   edje_object_signal_callback_add
+     (o, "elm,action,menu", "elm", _elm_ews_border_sig_menu, ee);
+   edje_object_signal_callback_add
+     (o, "elm,action,move,start", "elm", _elm_ews_border_sig_move_start, ee);
+   edje_object_signal_callback_add
+     (o, "elm,action,move,stop", "elm", _elm_ews_border_sig_move_stop, ee);
+
+   eina_hash_add(_ews_borders, &ee, o);
+   _elm_ews_wm_border_theme_set(ee, o, NULL);
+
+   ecore_evas_screen_geometry_get(ee, NULL, NULL, &sw, &sh);
+   ecore_evas_geometry_get(ee, NULL, NULL, &w, &h);
+   x = (sw - w) / 2;
+   y = (sh - h) / 2;
+   ecore_evas_move(ee, x, y);
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_elm_ews_wm_del_cb(void *data __UNUSED__, int type __UNUSED__, void *event_info)
+{
+   Ecore_Evas *ee = event_info;
+   eina_hash_del(_ews_borders, &ee, NULL);
+   eina_hash_del(_ews_borders_geo, &ee, NULL);
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_elm_ews_wm_geo_cb(void *data __UNUSED__, int type __UNUSED__, void *event_info)
+{
+   Ecore_Evas *ee = event_info;
+   Evas_Object *o = _elm_ews_wm_border_find(ee);
+   _elm_ews_border_geo_apply(ee, o);
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_elm_ews_wm_show_cb(void *data __UNUSED__, int type __UNUSED__, void *event_info)
+{
+   Ecore_Evas *ee = event_info;
+   Evas_Object *o = _elm_ews_wm_border_find(ee);
+   evas_object_show(o);
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_elm_ews_wm_hide_cb(void *data __UNUSED__, int type __UNUSED__, void *event_info)
+{
+   Ecore_Evas *ee = event_info;
+   Evas_Object *o = _elm_ews_wm_border_find(ee);
+   evas_object_hide(o);
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_elm_ews_wm_focus_cb(void *data __UNUSED__, int type __UNUSED__, void *event_info)
+{
+   Ecore_Evas *ee = event_info;
+   Evas_Object *o = _elm_ews_wm_border_find(ee);
+   _elm_ews_border_focus_apply(ee, o);
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_elm_ews_wm_stack_cb(void *data __UNUSED__, int type __UNUSED__, void *event_info)
+{
+   Ecore_Evas *ee = event_info;
+   Evas_Object *o = _elm_ews_wm_border_find(ee);
+   _elm_ews_border_stack_apply(ee, o);
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_elm_ews_wm_iconified_change_cb(void *data __UNUSED__, int type __UNUSED__, void *event_info)
+{
+   Ecore_Evas *ee = event_info;
+   Evas_Object *o = _elm_ews_wm_border_find(ee);
+   _elm_ews_border_iconified_apply(ee, o);
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_elm_ews_wm_maximized_change_cb(void *data __UNUSED__, int type __UNUSED__, void *event_info)
+{
+   Ecore_Evas *ee = event_info;
+   Evas_Object *o = _elm_ews_wm_border_find(ee);
+   _elm_ews_border_maximized_apply(ee, o);
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_elm_ews_wm_layer_change_cb(void *data __UNUSED__, int type __UNUSED__, void *event_info)
+{
+   Ecore_Evas *ee = event_info;
+   Evas_Object *o = _elm_ews_wm_border_find(ee);
+   _elm_ews_border_layer_apply(ee, o);
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_elm_ews_wm_fullscreen_change_cb(void *data __UNUSED__, int type __UNUSED__, void *event_info)
+{
+   Ecore_Evas *ee = event_info;
+   Evas_Object *o = _elm_ews_wm_border_find(ee);
+   _elm_ews_border_fullscreen_apply(ee, o);
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_elm_ews_wm_config_change_cb(void *data __UNUSED__, int type __UNUSED__, void *event_info)
+{
+   Ecore_Evas *ee = event_info;
+   Evas_Object *o = _elm_ews_wm_border_find(ee);
+   _elm_ews_border_config_apply(ee, o, NULL);
+   return EINA_TRUE;
+}
+
+void
+_elm_ews_wm_rescale(Elm_Theme *th, Eina_Bool use_theme)
+{
+   Eina_Iterator *it = eina_hash_iterator_tuple_new(_ews_borders);
+   Eina_Hash_Tuple *tp = NULL;
+
+   if (!use_theme)
+     {
+        EINA_ITERATOR_FOREACH(it, tp)
+          _elm_ews_wm_border_theme_set((void*)tp->key, tp->data, NULL);
+
+        if (_ews_bg)
+          _elm_theme_set(NULL, _ews_bg, "ews", "background", "default");
+     }
+   else
+     {
+        EINA_ITERATOR_FOREACH(it, tp)
+          _elm_ews_wm_border_theme_set((void*)tp->key, tp->data, th);
+
+        if (_ews_bg)
+          _elm_theme_set(th, _ews_bg, "ews", "background", "default");
+     }
+
+   eina_iterator_free(it);
+}
+
+int
+_elm_ews_wm_init(void)
+{
+   Evas *e;
+   Evas_Object *o;
+
+   if (strcmp(_elm_config->engine, ELM_EWS) != 0)
+     {
+        _ews_used = EINA_FALSE;
+        return EINA_TRUE;
+     }
+
+   e = ecore_evas_ews_evas_get();
+   if (!e) return EINA_FALSE;
+   o = edje_object_add(e);
+   if (!o) return EINA_FALSE;
+
+   if (!_elm_theme_set(NULL, o, "ews", "background", "default"))
+     {
+        ERR("Could not set background theme, fallback to rectangle");
+        evas_object_del(o);
+        _ews_bg = o = NULL;
+     }
+   else
+     _ews_bg = o;
+   ecore_evas_ews_background_set(o);
+
+
+#define ADD_EH(ev, cb)                                          \
+   _ews_ev_handlers = eina_list_append                          \
+     (_ews_ev_handlers, ecore_event_handler_add(ev, cb, NULL))
+   ADD_EH(ECORE_EVAS_EWS_EVENT_ADD, _elm_ews_wm_add_cb);
+   ADD_EH(ECORE_EVAS_EWS_EVENT_DEL, _elm_ews_wm_del_cb);
+   ADD_EH(ECORE_EVAS_EWS_EVENT_RESIZE, _elm_ews_wm_geo_cb);
+   ADD_EH(ECORE_EVAS_EWS_EVENT_MOVE, _elm_ews_wm_geo_cb);
+   ADD_EH(ECORE_EVAS_EWS_EVENT_SHOW, _elm_ews_wm_show_cb);
+   ADD_EH(ECORE_EVAS_EWS_EVENT_HIDE, _elm_ews_wm_hide_cb);
+   ADD_EH(ECORE_EVAS_EWS_EVENT_FOCUS, _elm_ews_wm_focus_cb);
+   ADD_EH(ECORE_EVAS_EWS_EVENT_UNFOCUS, _elm_ews_wm_focus_cb);
+   ADD_EH(ECORE_EVAS_EWS_EVENT_RAISE, _elm_ews_wm_stack_cb);
+   ADD_EH(ECORE_EVAS_EWS_EVENT_LOWER, _elm_ews_wm_stack_cb);
+   ADD_EH(ECORE_EVAS_EWS_EVENT_ICONIFIED_CHANGE, _elm_ews_wm_iconified_change_cb);
+   ADD_EH(ECORE_EVAS_EWS_EVENT_MAXIMIZED_CHANGE, _elm_ews_wm_maximized_change_cb);
+   ADD_EH(ECORE_EVAS_EWS_EVENT_LAYER_CHANGE, _elm_ews_wm_layer_change_cb);
+   ADD_EH(ECORE_EVAS_EWS_EVENT_FULLSCREEN_CHANGE, _elm_ews_wm_fullscreen_change_cb);
+   ADD_EH(ECORE_EVAS_EWS_EVENT_CONFIG_CHANGE, _elm_ews_wm_config_change_cb);
+#undef ADD_EH
+
+   if (!_ews_borders)
+     _ews_borders = eina_hash_pointer_new(_elm_ews_wm_border_del);
+
+   if (!_ews_borders_geo)
+     _ews_borders_geo = eina_hash_pointer_new(free);
+
+   _ews_used = EINA_TRUE;
+   return EINA_TRUE;
+}
+
+void
+_elm_ews_wm_shutdown(void)
+{
+   Ecore_Event_Handler *eh;
+
+   if (_ews_border_mover)
+     {
+        ecore_animator_del(_ews_border_mover);
+        _ews_border_mover = NULL;
+     }
+   _ews_border_mover_obj = NULL;
+
+   EINA_LIST_FREE(_ews_ev_handlers, eh) ecore_event_handler_del(eh);
+   if (_ews_borders)
+     {
+        eina_hash_free(_ews_borders);
+        _ews_borders = NULL;
+     }
+   if (_ews_borders_geo)
+     {
+        eina_hash_free(_ews_borders_geo);
+        _ews_borders_geo = NULL;
+     }
+   _ews_bg = NULL;
+}