raster pushed a commit to branch master.

http://git.enlightenment.org/core/enlightenment.git/commit/?id=5c38609e0ee6990ecfa3dab2af2c5c050638c4bd

commit 5c38609e0ee6990ecfa3dab2af2c5c050638c4bd
Author: Carsten Haitzler (Rasterman) <ras...@rasterman.com>
Date:   Mon Dec 12 12:20:26 2016 +0900

    client handling - add support for window stacks needed for views/manager
    
    this adds core basic handling for window stacks where windows behave
    correctly as a single unified stack something like what naviframe does
    but out-of-window so you can including multiple processes. only on x11
    right now as it's being supported/worked on.
    
    as we dont plan to kepe naviframe in future, this is the way to go.
    naviframe "pages" will be windows in a stack. the wm should do the
    nice thing. in e this will be very nice. for now elsewhere we use
    transient_for so a wm would treat this like a bunch of dialogs with a
    single parent window. i guess in a desktop thats probably what you
    might expect. e will be a little more "finesse" filled.
    
    need to make ibar, tasks,m win menu and winlist (alt-tab) respect this
    and only show the top member of a stack.
    
    need to send messages to clients when they are "top" or "middle" or
    "bottom" or "alone" in the stack or something so decorations can change.
    
    should add soem new border signals in theme (for both SSD and CSD) to
    make this look nice. will need some config additions for that and
    ability for e comp to do the right thing
    
    but this is a solid start
---
 src/bin/e_client.c      | 511 +++++++++++++++++++++++++++++++++++++++++-------
 src/bin/e_client.h      |  18 +-
 src/bin/e_comp_object.c |  54 +++--
 src/bin/e_comp_wl.c     |  25 ++-
 src/bin/e_comp_x.c      |  17 ++
 src/bin/e_desk.c        |   3 +-
 6 files changed, 536 insertions(+), 92 deletions(-)

diff --git a/src/bin/e_client.c b/src/bin/e_client.c
index 74a781b..9561cdf 100644
--- a/src/bin/e_client.c
+++ b/src/bin/e_client.c
@@ -430,14 +430,34 @@ _e_client_revert_focus(E_Client *ec)
    E_Desk *desk;
 
    if (stopping) return;
+
    if (!ec->focused) return;
    if (!ec->zone) return;
+
    desk = e_desk_current_get(ec->zone);
    if (ec->desk == desk)
      evas_object_focus_set(ec->frame, 0);
 
-   if ((ec->parent) &&
-       (ec->parent->desk == desk) && (ec->parent->modal == ec))
+   if (ec->stack.prev)
+     {
+        ec->stack.focus_skip = 1;
+        pec = e_client_stack_active_adjust(ec);
+        ec->stack.focus_skip = 0;
+        if ((pec != ec) && (!pec->iconic))
+          evas_object_focus_set(pec->frame, 1);
+        else
+          {
+             if ((e_object_is_del(E_OBJECT(ec))) || (ec->iconic))
+               {
+                  Eina_Bool unlock = ec->lock_focus_out;
+                  ec->lock_focus_out = 1;
+                  pec = e_desk_last_focused_focus(desk);
+                  ec->lock_focus_out = unlock;
+               }
+          }
+     }
+   else if ((ec->parent) &&
+            (ec->parent->desk == desk) && (ec->parent->modal == ec))
      {
         evas_object_focus_set(ec->parent->frame, 1);
         if (e_config->raise_on_revert_focus)
@@ -447,7 +467,7 @@ _e_client_revert_focus(E_Client *ec)
      {
         Eina_Bool unlock = ec->lock_focus_out;
         ec->lock_focus_out = 1;
-        e_desk_last_focused_focus(desk);
+        pec = e_desk_last_focused_focus(desk);
         ec->lock_focus_out = unlock;
      }
    else if (e_config->focus_policy == E_FOCUS_MOUSE)
@@ -567,6 +587,9 @@ _e_client_free(E_Client *ec)
         ec->e.state.profile.wait_desk_delfn = NULL;
         e_object_unref(E_OBJECT(ec->e.state.profile.wait_desk));
      }
+   if (ec->stack.prev) ec->stack.prev->stack.next = ec->stack.next;
+   if (ec->stack.next) ec->stack.next->stack.prev = ec->stack.prev;
+
    ec->e.state.profile.wait_desk = NULL;
    evas_object_del(ec->frame);
    E_OBJECT(ec)->references--;
@@ -580,6 +603,8 @@ _e_client_del(E_Client *ec)
    E_Client *child;
    E_Client_Volume_Sink *sink;
 
+   for (child = ec->stack.next; child; child = child->stack.next)
+     e_client_act_close_begin(child);
    ec->changed = 0;
    focus_stack = eina_list_remove(focus_stack, ec);
    raise_stack = eina_list_remove(raise_stack, ec);
@@ -1390,6 +1415,78 @@ _e_client_zone_update(E_Client *ec)
 
 ////////////////////////////////////////////////
 
+E_API Eina_List *
+e_client_stack_list_prepare(E_Client *ec)
+{
+   E_Client *ec2;
+   Eina_List *list = NULL;
+
+   for (ec2 = ec->stack.prev; ec2; ec2 = ec2->stack.prev)
+     {
+        ec2->stack.ignore++;
+        list = eina_list_prepend(list, ec2);
+     }
+   ec->stack.ignore++;
+   list = eina_list_append(list, ec);
+   for (ec2 = ec->stack.next; ec2; ec2 = ec2->stack.next)
+     {
+        ec2->stack.ignore++;
+        list = eina_list_append(list, ec2);
+     }
+   return list;
+}
+
+E_API void
+e_client_stack_list_finish(Eina_List *list)
+{
+   E_Client *ec;
+
+   EINA_LIST_FREE(list, ec) ec->stack.ignore--;
+}
+
+E_API E_Client *
+e_client_stack_top_get(E_Client *ec)
+{
+   E_Client *ec2;
+
+   for (ec2 = ec; ec2; ec2 = ec2->stack.next)
+     {
+        if (!ec2->stack.next) return ec2;
+     }
+   return ec;
+}
+
+E_API E_Client *
+e_client_stack_bottom_get(E_Client *ec)
+{
+   E_Client *ec2;
+
+   for (ec2 = ec; ec2; ec2 = ec2->stack.prev)
+     {
+        if (!ec2->stack.prev) return ec2;
+     }
+   return ec;
+}
+
+E_API E_Client *
+e_client_stack_active_adjust(E_Client *ec)
+{
+   E_Client *pec = ec;
+   if ((!ec->stack.prev) && (!ec->stack.next)) return ec;
+   ec = e_client_stack_top_get(ec);
+   for (; ec; ec = ec->stack.prev)
+     {
+        if (e_object_is_del(E_OBJECT(ec))) continue;
+        if (ec->stack.focus_skip) continue;
+        if (ec->iconic) continue;
+        if (ec->visible) break;
+     }
+   if (!ec) ec = pec;
+   return ec;
+}
+
+////////////////////////////////////////////////
+
 static void
 _e_client_cb_evas_hide(void *data, Evas *e EINA_UNUSED, Evas_Object *obj 
EINA_UNUSED, void *event_info EINA_UNUSED)
 {
@@ -1444,16 +1541,44 @@ _e_client_cb_evas_move(void *data, Evas *e EINA_UNUSED, 
Evas_Object *obj EINA_UN
 
    _e_client_zone_update(ec);
    evas_object_geometry_get(ec->frame, &x, &y, NULL, NULL);
-   if ((e_config->transient.move) && (ec->transients))
+   if (ec->stack.prev || ec->stack.next)
      {
-        Eina_List *list = eina_list_clone(ec->transients);
-        E_Client *child;
-
-        EINA_LIST_FREE(list, child)
+        if (ec->stack.ignore == 0)
           {
-             evas_object_move(child->frame,
-                              child->x + x - ec->pre_cb.x,
-                              child->y + y - ec->pre_cb.y);
+             Eina_List *l, *list = e_client_stack_list_prepare(ec);
+             E_Client *child;
+             Evas_Coord bx, by, bw, bh, cw, ch, dx, dy;
+
+             child = e_client_stack_bottom_get(ec);
+             dx = x - ec->pre_cb.x;
+             dy = y - ec->pre_cb.y;
+             if (child != ec)
+               evas_object_move(child->frame, child->x + dx, child->y + dy);
+             evas_object_geometry_get(child->frame, &bx, &by, &bw, &bh);
+             EINA_LIST_FOREACH(list->next, l, child)
+               {
+                  if (child == ec) continue;
+                  evas_object_geometry_get(child->frame, NULL, NULL, &cw, &ch);
+                  evas_object_move(child->frame,
+                                   bx + ((bw - cw) / 2),
+                                   by + ((bh - ch) / 2));
+               }
+             e_client_stack_list_finish(list);
+          }
+     }
+   else
+     {
+        if ((e_config->transient.move) && (ec->transients))
+          {
+             Eina_List *list = eina_list_clone(ec->transients);
+             E_Client *child;
+
+             EINA_LIST_FREE(list, child)
+               {
+                  evas_object_move(child->frame,
+                                   child->x + x - ec->pre_cb.x,
+                                   child->y + y - ec->pre_cb.y);
+               }
           }
      }
    if (ec->moving || (ecmove == ec))
@@ -1476,24 +1601,105 @@ _e_client_cb_evas_resize(void *data, Evas *e 
EINA_UNUSED, Evas_Object *obj EINA_
 
    _e_client_zone_update(ec);
    evas_object_geometry_get(ec->frame, &x, &y, &w, &h);
-   if ((e_config->transient.resize) && (ec->transients))
+   if (ec->stack.prev || ec->stack.next)
      {
-        Eina_List *list = eina_list_clone(ec->transients);
-        E_Client *child;
+        if (ec->stack.ignore == 0)
+          {
+             Eina_List *l, *list = e_client_stack_list_prepare(ec);
+             E_Client *child;
+             Evas_Coord bx, by, bw, bh, cw, ch;
 
-        EINA_LIST_FREE(list, child)
+             if (e_client_util_resizing_get(ec))
+               {
+                  if (ec->dialog)
+                    {
+                       child = list->data;
+                       evas_object_geometry_get(child->frame, &bx, &by, &bw, 
&bh);
+                       EINA_LIST_FOREACH(list, l, child)
+                         {
+                            if (child == ec) continue;
+                            if (!ec->dialog)
+                              {
+                                 evas_object_resize(child->frame, bw, bh);
+                                 cw = bw;
+                                 ch = bh;
+                              }
+                            else
+                              evas_object_geometry_get(child->frame, NULL, 
NULL, &cw, &ch);
+                            evas_object_move(child->frame,
+                                             bx + ((bw - cw) / 2),
+                                             by + ((bh - ch) / 2));
+                         }
+                    }
+                  else
+                    {
+                       child = e_client_stack_bottom_get(ec);
+                       evas_object_move(child->frame, x, y);
+                       evas_object_resize(child->frame, w, h);
+                       EINA_LIST_FOREACH(list->next, l, child)
+                         {
+                            if (child == ec) continue;
+                            if (!ec->dialog)
+                              {
+                                 evas_object_move(child->frame, x, y);
+                                 evas_object_resize(child->frame, w, h);
+                                 cw = w;
+                                 ch = h;
+                              }
+                            else
+                              evas_object_geometry_get(child->frame, NULL, 
NULL, &cw, &ch);
+                            evas_object_move(child->frame,
+                                             x + ((w - cw) / 2),
+                                             y + ((h - ch) / 2));
+                         }
+                    }
+               }
+             else
+               {
+                  if (ec == e_client_stack_bottom_get(ec))
+                    {
+                       EINA_LIST_FOREACH(list->next, l, child)
+                         {
+                            if (child == ec) continue;
+                            if (!ec->dialog)
+                              {
+                                 evas_object_move(child->frame, x, y);
+                                 evas_object_resize(child->frame, w, h);
+                                 cw = w;
+                                 ch = h;
+                              }
+                            else
+                              evas_object_geometry_get(child->frame, NULL, 
NULL, &cw, &ch);
+                            evas_object_move(child->frame,
+                                             x + ((w - cw) / 2),
+                                             y + ((h - ch) / 2));
+                         }
+                    }
+               }
+             e_client_stack_list_finish(list);
+          }
+     }
+   else
+     {
+        if ((e_config->transient.resize) && (ec->transients))
           {
-             Evas_Coord nx, ny, nw, nh;
+             Eina_List *list = eina_list_clone(ec->transients);
+             E_Client *child;
 
-             if ((ec->pre_cb.w > 0) && (ec->pre_cb.h > 0))
+             EINA_LIST_FREE(list, child)
                {
-                  nx = x + (((child->x - x) * w) / ec->pre_cb.w);
-                  ny = y + (((child->y - y) * h) / ec->pre_cb.h);
-                  nw = (child->w * w) / ec->pre_cb.w;
-                  nh = (child->h * h) / ec->pre_cb.h;
-                  nx += ((nw - child->w) / 2);
-                  ny += ((nh - child->h) / 2);
-                  evas_object_move(child->frame, nx, ny);
+                  Evas_Coord nx, ny, nw, nh;
+
+                  if ((ec->pre_cb.w > 0) && (ec->pre_cb.h > 0))
+                    {
+                       nx = x + (((child->x - x) * w) / ec->pre_cb.w);
+                       ny = y + (((child->y - y) * h) / ec->pre_cb.h);
+                       nw = (child->w * w) / ec->pre_cb.w;
+                       nh = (child->h * h) / ec->pre_cb.h;
+                       nx += ((nw - child->w) / 2);
+                       ny += ((nh - child->h) / 2);
+                       evas_object_move(child->frame, nx, ny);
+                    }
                }
           }
      }
@@ -1518,22 +1724,45 @@ _e_client_cb_evas_restack(void *data, Evas *e 
EINA_UNUSED, Evas_Object *obj EINA
    E_Client *ec = data;
 
    if (ec->layer_block) return;
-   if (e_config->transient.raise && ec->transients)
+   if (ec->stack.prev || ec->stack.next)
      {
-        Eina_List *list = eina_list_clone(ec->transients);
-        E_Client *child, *below = NULL;
+        if (ec->stack.ignore == 0)
+          {
+             Eina_List *l, *list = e_client_stack_list_prepare(ec);
+             E_Client *child;
 
-        E_LIST_REVERSE_FREE(list, child)
+             EINA_LIST_FOREACH(list, l, child)
+               {
+                  if (child == ec) break;
+                  evas_object_stack_below(child->frame, ec->frame);
+               }
+             EINA_LIST_REVERSE_FOREACH(list, l, child)
+               {
+                  if (child == ec) break;
+                  evas_object_stack_above(child->frame, ec->frame);
+               }
+             e_client_stack_list_finish(list);
+          }
+     }
+   else
+     {
+        if (e_config->transient.raise && ec->transients)
           {
-             /* Don't stack iconic transients. If the user wants these shown,
-              * that's another option.
-              */
-             if (child->iconic) continue;
-             if (below)
-               evas_object_stack_below(child->frame, below->frame);
-             else
-               evas_object_stack_above(child->frame, ec->frame);
-             below = child;
+             Eina_List *list = eina_list_clone(ec->transients);
+             E_Client *child, *below = NULL;
+
+             E_LIST_REVERSE_FREE(list, child)
+               {
+                  /* Don't stack iconic transients. If the user wants these 
shown,
+                   * that's another option.
+                   */
+                  if (child->iconic) continue;
+                  if (below)
+                    evas_object_stack_below(child->frame, below->frame);
+                  else
+                    evas_object_stack_above(child->frame, ec->frame);
+                  below = child;
+               }
           }
      }
    if (ec->unredirected_single) return;
@@ -1608,6 +1837,16 @@ _e_client_eval(E_Client *ec)
              ec->placed = 1;
              ec->pre_cb.x = ec->x; ec->pre_cb.y = ec->y;
           }
+
+        if ((ec->stack.prev) && (!ec->dialog))
+          {
+             E_Client *ec2 = e_client_stack_bottom_get(ec);
+
+             ec->stack.ignore++;
+             evas_object_move(ec->frame, ec2->x, ec2->y);
+             evas_object_resize(ec->frame, ec2->w, ec2->h);
+             ec->stack.ignore--;
+          }
         if (!ec->placed)
           {
              if (ec->parent)
@@ -2088,7 +2327,12 @@ _e_client_eval(E_Client *ec)
        ((ec->take_focus) || (ec->want_focus)))
      {
         ec->take_focus = 0;
-        if ((e_config->focus_setting == E_FOCUS_NEW_WINDOW) || 
(ec->want_focus))
+        if ((ec->stack.prev) && (!ec->stack.next) &&
+            (ec->stack.prev == e_client_focused_get()))
+          {
+             e_client_focus_set_with_pointer(ec);
+          }
+        else if ((e_config->focus_setting == E_FOCUS_NEW_WINDOW) || 
(ec->want_focus))
           {
              ec->want_focus = 0;
              e_client_focus_set_with_pointer(ec);
@@ -2580,6 +2824,8 @@ e_client_desk_set(E_Client *ec, E_Desk *desk)
    e_comp_object_effect_set(ec->frame, NULL);
    if (desk->visible || ec->sticky)
      {
+        // force visibility if its a stack window going onto this desktop
+        if (ec->stack.prev || ec->stack.next) ec->hidden = 0;
         if ((!ec->hidden) && (!ec->iconic))
           evas_object_show(ec->frame);
      }
@@ -2611,13 +2857,38 @@ e_client_desk_set(E_Client *ec, E_Desk *desk)
           }
      }
 
-   if (e_config->transient.desktop)
+   if (ec->stack.prev || ec->stack.next)
      {
-        E_Client *child;
-        const Eina_List *l;
+        if (ec->stack.ignore == 0)
+          {
+             Eina_List *l, *list = e_client_stack_list_prepare(ec);
+             E_Client *child;
+
+             EINA_LIST_FOREACH(list, l, child)
+               {
+                  if (child == ec) break;
+                  e_client_desk_set(child, ec->desk);
+                  evas_object_stack_below(child->frame, ec->frame);
+               }
+             EINA_LIST_REVERSE_FOREACH(list, l, child)
+               {
+                  if (child == ec) break;
+                  e_client_desk_set(child, ec->desk);
+                  evas_object_stack_above(child->frame, ec->frame);
+               }
+             e_client_stack_list_finish(list);
+          }
+     }
+   else
+     {
+        if (e_config->transient.desktop)
+          {
+             E_Client *child;
+             const Eina_List *l;
 
-        EINA_LIST_FOREACH(ec->transients, l, child)
-          e_client_desk_set(child, ec->desk);
+             EINA_LIST_FOREACH(ec->transients, l, child)
+               e_client_desk_set(child, ec->desk);
+          }
      }
 
    e_remember_update(ec);
@@ -3344,6 +3615,7 @@ e_client_focus_set_with_pointer(E_Client *ec)
         if ((!ec->icccm.accepts_focus) &&
             (!ec->icccm.take_focus)) return;
      }
+   ec = e_client_stack_active_adjust(ec);
    if (ec->lock_focus_out) return;
    if (ec == focused) return;
    evas_object_focus_set(ec->frame, 1);
@@ -3466,6 +3738,7 @@ e_client_activate(E_Client *ec, Eina_Bool just_do_it)
 {
    E_OBJECT_CHECK(ec);
    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
+   ec = e_client_stack_active_adjust(ec);
    if ((e_config->focus_setting == E_FOCUS_NEW_WINDOW) ||
        ((ec->parent) &&
         ((e_config->focus_setting == E_FOCUS_NEW_DIALOG) ||
@@ -4160,28 +4433,60 @@ e_client_iconify(E_Client *ec)
    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
    if (!ec->zone) return;
    if (ec->shading || ec->iconic) return;
+   if (((ec->stack.prev || ec->stack.next)) && (!ec->stack.ignore))
+     {
+        Eina_List *l, *list = e_client_stack_list_prepare(ec);
+        E_Client *child;
+
+        EINA_LIST_FOREACH(list, l, child)
+          {
+             e_client_iconify(child);
+          }
+        e_client_stack_list_finish(list);
+        E_Client *pec;
+        E_Desk *desk;
+
+        desk = e_desk_current_get(ec->zone);
+        pec = e_desk_last_focused_focus(desk);
+        if (pec) evas_object_focus_set(pec->frame, 1);
+        return;
+     }
    ec->iconic = 1;
    ec->want_focus = ec->take_focus = 0;
    ec->changes.visible = 0;
    if (ec->fullscreen)
      ec->desk->fullscreen_clients = 
eina_list_remove(ec->desk->fullscreen_clients, ec);
    e_client_comp_hidden_set(ec, 1);
-   if (!ec->new_client)
+   if (!ec->stack.ignore)
      {
-        _e_client_revert_focus(ec);
-        evas_object_hide(ec->frame);
+        if (!ec->new_client)
+          {
+             _e_client_revert_focus(ec);
+             evas_object_hide(ec->frame);
+          }
+        e_client_urgent_set(ec, ec->icccm.urgent);
+     }
+   else
+     {
+        if (!ec->new_client)
+          evas_object_hide(ec->frame);
+        e_client_urgent_set(ec, ec->icccm.urgent);
+        if (ec->focused)
+          evas_object_focus_set(ec->frame, 0);
      }
-   e_client_urgent_set(ec, ec->icccm.urgent);
 
    _e_client_event_simple(ec, E_EVENT_CLIENT_ICONIFY);
 
-   if (e_config->transient.iconify)
+   if (!ec->stack.prev && !ec->stack.next)
      {
-        E_Client *child;
-        Eina_List *list = eina_list_clone(ec->transients);
+        if (e_config->transient.iconify)
+          {
+             E_Client *child;
+             Eina_List *list = eina_list_clone(ec->transients);
 
-        EINA_LIST_FREE(list, child)
-          e_client_iconify(child);
+             EINA_LIST_FREE(list, child)
+               e_client_iconify(child);
+          }
      }
    e_remember_update(ec);
 }
@@ -4195,23 +4500,44 @@ e_client_uniconify(E_Client *ec)
    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
    if (!ec->zone) return;
    if (ec->shading || (!ec->iconic)) return;
+
+   if (((ec->stack.prev || ec->stack.next)) && (!ec->stack.ignore))
+     {
+        Eina_List *l, *list = e_client_stack_list_prepare(ec);
+        E_Client *child, *ec_focus = NULL;
+
+        EINA_LIST_FOREACH(list, l, child)
+          {
+             e_client_uniconify(child);
+             if (!l->next) ec_focus = child;
+          }
+        e_client_stack_list_finish(list);
+        evas_object_raise(ec_focus->frame);
+        evas_object_focus_set(ec_focus->frame, 1);
+        return;
+     }
    desk = e_desk_current_get(ec->desk->zone);
    e_client_desk_set(ec, desk);
-   evas_object_raise(ec->frame);
+   if (!ec->stack.ignore)
+     evas_object_raise(ec->frame);
    evas_object_show(ec->frame);
    e_client_comp_hidden_set(ec, 0);
    ec->deskshow = ec->iconic = 0;
-   evas_object_focus_set(ec->frame, 1);
+   if (!ec->stack.ignore)
+     evas_object_focus_set(ec->frame, 1);
 
    _e_client_event_simple(ec, E_EVENT_CLIENT_UNICONIFY);
 
-   if (e_config->transient.iconify)
+   if (!ec->stack.prev && !ec->stack.next)
      {
-        E_Client *child;
-        Eina_List *list = eina_list_clone(ec->transients);
+        if (e_config->transient.iconify)
+          {
+             E_Client *child;
+             Eina_List *list = eina_list_clone(ec->transients);
 
-        EINA_LIST_FREE(list, child)
-          e_client_uniconify(child);
+             EINA_LIST_FREE(list, child)
+               e_client_uniconify(child);
+          }
      }
    e_remember_update(ec);
 }
@@ -4267,16 +4593,36 @@ e_client_stick(E_Client *ec)
    e_client_desk_set(ec, desk);
    evas_object_smart_callback_call(ec->frame, "stick", NULL);
 
-   if (e_config->transient.desktop)
+   if (ec->stack.prev || ec->stack.next)
      {
-        E_Client *child;
-        Eina_List *list = eina_list_clone(ec->transients);
+        if (ec->stack.ignore == 0)
+          {
+             Eina_List *l, *list = e_client_stack_list_prepare(ec);
+             E_Client *child;
 
-        EINA_LIST_FREE(list, child)
+             EINA_LIST_FOREACH(list, l, child)
+               {
+                  if (child == ec) continue;
+                  child->sticky = 1;
+                  e_hints_window_sticky_set(child, 1);
+                  evas_object_show(ec->frame);
+               }
+             e_client_stack_list_finish(list);
+          }
+     }
+   else
+     {
+        if (e_config->transient.desktop)
           {
-             child->sticky = 1;
-             e_hints_window_sticky_set(child, 1);
-             evas_object_show(ec->frame);
+             E_Client *child;
+             Eina_List *list = eina_list_clone(ec->transients);
+
+             EINA_LIST_FREE(list, child)
+               {
+                  child->sticky = 1;
+                  e_hints_window_sticky_set(child, 1);
+                  evas_object_show(ec->frame);
+               }
           }
      }
 
@@ -4301,15 +4647,34 @@ e_client_unstick(E_Client *ec)
    e_client_desk_set(ec, desk);
    evas_object_smart_callback_call(ec->frame, "unstick", NULL);
 
-   if (e_config->transient.desktop)
+   if (ec->stack.prev || ec->stack.next)
      {
-        E_Client *child;
-        Eina_List *list = eina_list_clone(ec->transients);
+        if (ec->stack.ignore == 0)
+          {
+             Eina_List *l, *list = e_client_stack_list_prepare(ec);
+             E_Client *child;
 
-        EINA_LIST_FREE(list, child)
+             EINA_LIST_FOREACH(list, l, child)
+               {
+                  if (child == ec) continue;
+                  child->sticky = 1;
+                  e_hints_window_sticky_set(child, 0);
+               }
+             e_client_stack_list_finish(list);
+          }
+     }
+   else
+     {
+        if (e_config->transient.desktop)
           {
-             child->sticky = 0;
-             e_hints_window_sticky_set(child, 0);
+             E_Client *child;
+             Eina_List *list = eina_list_clone(ec->transients);
+
+             EINA_LIST_FREE(list, child)
+               {
+                  child->sticky = 0;
+                  e_hints_window_sticky_set(child, 0);
+               }
           }
      }
 
@@ -5030,6 +5395,7 @@ e_client_pointer_warp_to_center(E_Client *ec)
    int x, y;
    E_Client *cec = NULL;
 
+   ec = e_client_stack_active_adjust(ec);
    if (!ec->zone) return 0;
    if (e_config->disable_all_pointer_warps) return 0;
    /* Only warp the pointer if it is not already in the area of
@@ -5039,6 +5405,7 @@ e_client_pointer_warp_to_center(E_Client *ec)
        (y >= ec->y) && (y <= (ec->y + ec->h)))
      {
         cec = _e_client_under_pointer_helper(ec->desk, ec, x, y);
+        cec = e_client_stack_active_adjust(cec);
         if (cec == ec) return 0;
      }
 
diff --git a/src/bin/e_client.h b/src/bin/e_client.h
index 7e6e954..54f1381 100644
--- a/src/bin/e_client.h
+++ b/src/bin/e_client.h
@@ -266,6 +266,13 @@ struct E_Client
 
    E_Action                  *cur_mouse_action;
 
+   struct {
+      E_Client               *next;
+      E_Client               *prev;
+      int                     ignore;
+      Eina_Bool               focus_skip : 1;
+   } stack;
+
    int               border_size; //size of client's border
 
    struct
@@ -518,8 +525,9 @@ struct E_Client
             unsigned char     wait_for_done : 1;
             unsigned char     use : 1;
          } profile;
-         unsigned char  centered : 1;
-         unsigned char  video : 1;
+         Ecore_X_Stack_Type stack;
+         unsigned char      centered : 1;
+         unsigned char      video : 1;
       } state;
 
       struct
@@ -528,6 +536,7 @@ struct E_Client
          unsigned char video_parent : 1;
          unsigned char video_position : 1;
          unsigned char profile : 1;
+         unsigned char stack : 1;
       } fetch;
    } e;
 
@@ -840,6 +849,11 @@ E_API Eina_Bool e_client_has_xwindow(const E_Client *ec);
 E_API Eina_Bool e_client_desk_window_profile_available_check(E_Client *ec, 
const char *profile);
 E_API void      e_client_desk_window_profile_wait_desk_set(E_Client *ec, 
E_Desk *desk);
 E_API void      e_client_layout_cb_set(E_Client_Layout_Cb cb);
+E_API Eina_List *e_client_stack_list_prepare(E_Client *ec);
+E_API void       e_client_stack_list_finish(Eina_List *list);
+E_API E_Client  *e_client_stack_top_get(E_Client *ec);
+E_API E_Client  *e_client_stack_bottom_get(E_Client *ec);
+E_API E_Client  *e_client_stack_active_adjust(E_Client *ec);
 
 YOLO E_API void e_client_focus_stack_set(Eina_List *l);
 
diff --git a/src/bin/e_comp_object.c b/src/bin/e_comp_object.c
index be4eb0a..acfcd41 100644
--- a/src/bin/e_comp_object.c
+++ b/src/bin/e_comp_object.c
@@ -1318,6 +1318,7 @@ _e_comp_intercept_layer_set(void *data, Evas_Object *obj, 
int layer)
    E_Comp_Object *cw = data;
    unsigned int l = e_comp_canvas_layer_map(layer);
    int oldraise;
+   E_Client *ec;
 
    if (cw->ec->layer_block)
      {
@@ -1362,20 +1363,40 @@ _e_comp_intercept_layer_set(void *data, Evas_Object 
*obj, int layer)
    _e_comp_object_layers_remove(cw);
    /* clamp to valid client layer */
    layer = e_comp_canvas_client_layer_map_nearest(layer);
-   cw->ec->layer = layer;
-   if (e_config->transient.layer)
+   ec = cw->ec;
+   ec->layer = layer;
+   if (ec->stack.prev || ec->stack.next)
      {
-        E_Client *child;
-        Eina_List *list = eina_list_clone(cw->ec->transients);
+        if (ec->stack.ignore == 0)
+          {
+             Eina_List *l, *list = e_client_stack_list_prepare(ec);
+             E_Client *child;
 
-        /* We need to set raise to one, else the child wont
-         * follow to the new layer. It should be like this,
-         * even if the user usually doesn't want to raise
-         * the transients.
-         */
-        e_config->transient.raise = 1;
-        EINA_LIST_FREE(list, child)
-          evas_object_layer_set(child->frame, layer);
+             EINA_LIST_FOREACH(list, l, child)
+               {
+                  if (child == ec) continue;
+                  evas_object_layer_set(child->frame, layer);
+               }
+             e_client_stack_list_finish(list);
+             evas_object_raise(ec->frame);
+          }
+     }
+   else
+     {
+        if (e_config->transient.layer)
+          {
+             E_Client *child;
+             Eina_List *list = eina_list_clone(cw->ec->transients);
+
+             /* We need to set raise to one, else the child wont
+              * follow to the new layer. It should be like this,
+              * even if the user usually doesn't want to raise
+              * the transients.
+              */
+             e_config->transient.raise = 1;
+             EINA_LIST_FREE(list, child)
+               evas_object_layer_set(child->frame, layer);
+          }
      }
    if (!cw->ec->override)
      {
@@ -1780,9 +1801,14 @@ static void
 _e_comp_intercept_focus(void *data, Evas_Object *obj, Eina_Bool focus)
 {
    E_Comp_Object *cw = data;
-   E_Client *ec;
+   E_Client *ec = cw->ec;
 
-   ec = cw->ec;
+   if (focus)
+     {
+        ec = e_client_stack_active_adjust(ec);
+        obj = ec->frame;
+        cw = evas_object_data_get(obj, "comp_obj");
+     }
    /* note: this is here as it seems there are enough apps that do not even
     * expect us to emulate a look of focus but not actually set x input
     * focus as we do - so simply abort any focus set on such windows */
diff --git a/src/bin/e_comp_wl.c b/src/bin/e_comp_wl.c
index 2d2c6aa..f96ad08 100644
--- a/src/bin/e_comp_wl.c
+++ b/src/bin/e_comp_wl.c
@@ -719,10 +719,29 @@ _e_comp_wl_evas_cb_restack(void *data, Evas *e 
EINA_UNUSED, Evas_Object *obj EIN
 
    if (e_object_is_del(E_OBJECT(ec))) return;
    if (e_client_has_xwindow(ec)) return;
-   EINA_LIST_FOREACH(ec->transients, l, sec)
+   if (ec->stack.prev || ec->stack.next)
      {
-        evas_object_layer_set(sec->frame, evas_object_layer_get(ec->frame));
-        evas_object_stack_above(sec->frame, ec->frame);
+        if (ec->stack.ignore == 0)
+          {
+             Eina_List *l, *list = e_client_stack_list_prepare(ec);
+             E_Client *child;
+
+             EINA_LIST_FOREACH(list, l, child)
+               {
+                  if (child == ec) continue;
+                  evas_object_layer_set(child->frame, layer);
+               }
+             e_client_stack_list_finish(list);
+             evas_object_raise(ec->frame);
+          }
+     }
+   else
+     {
+        EINA_LIST_FOREACH(ec->transients, l, sec)
+          {
+             evas_object_layer_set(sec->frame, 
evas_object_layer_get(ec->frame));
+             evas_object_stack_above(sec->frame, ec->frame);
+          }
      }
    if (!ec->comp_data->sub.list) return;
    EINA_LIST_FOREACH(ec->comp_data->sub.list, l, sec)
diff --git a/src/bin/e_comp_x.c b/src/bin/e_comp_x.c
index 714431c..069e1b2 100644
--- a/src/bin/e_comp_x.c
+++ b/src/bin/e_comp_x.c
@@ -519,6 +519,8 @@ _e_comp_x_client_new_helper(E_Client *ec)
              /* loop to check for window profile list atom */
              else if (atoms[i] == ECORE_X_ATOM_E_WINDOW_PROFILE_SUPPORTED)
                ec->e.fetch.profile = 1;
+             else if (atoms[i] == ECORE_X_ATOM_E_STACK_TYPE)
+               ec->e.fetch.stack = 1;
              else if (atoms[i] == ATM_GTK_FRAME_EXTENTS)
                ec->comp_data->fetch_gtk_frame_extents = 1;
           }
@@ -3406,6 +3408,11 @@ _e_comp_x_hook_client_fetch(void *d EINA_UNUSED, 
E_Client *ec)
         ec->e.fetch.state = 0;
         rem_change = 1;
      }
+   if (ec->e.fetch.stack)
+     {
+        ec->e.state.stack = ecore_x_e_stack_type_get(win);
+        ec->e.fetch.stack = 0;
+     }
    if (ec->e.fetch.profile)
      {
         const char **list = NULL;
@@ -3847,6 +3854,16 @@ _e_comp_x_hook_client_fetch(void *d EINA_UNUSED, 
E_Client *ec)
                  (ec->parent->focused && (e_config->focus_setting == 
E_FOCUS_NEW_DIALOG_IF_OWNER_FOCUSED)))
                ec->take_focus = 1;
           }
+        if ((ec_parent) && (ec->e.state.stack != ECORE_X_STACK_NONE))
+          {
+             E_Client *ec2;
+
+             // find last one
+             for (ec2 = ec_parent; ec2->stack.next; ec2 = ec2->stack.next);
+             ec->stack.prev = ec2;
+             ec->stack.next = NULL;
+             ec->stack.prev->stack.next = ec;
+          }
         ec->icccm.fetch.transient_for = 0;
         rem_change = 1;
      }
diff --git a/src/bin/e_desk.c b/src/bin/e_desk.c
index bc8604b..68d32a0 100644
--- a/src/bin/e_desk.c
+++ b/src/bin/e_desk.c
@@ -409,7 +409,8 @@ e_desk_last_focused_focus(E_Desk *desk)
             (ec->netwm.type != E_WINDOW_TYPE_TOOLBAR) &&
             (ec->netwm.type != E_WINDOW_TYPE_MENU) &&
             (ec->netwm.type != E_WINDOW_TYPE_SPLASH) &&
-            (ec->netwm.type != E_WINDOW_TYPE_DESKTOP))
+            (ec->netwm.type != E_WINDOW_TYPE_DESKTOP) &&
+            (!e_object_is_del(E_OBJECT(ec))))
           {
              /* this was the window last focused in this desktop */
              if (!ec->lock_focus_out)

-- 


Reply via email to