From 5c38609e0ee6990ecfa3dab2af2c5c050638c4bd Mon Sep 17 00:00:00 2001 From: "Carsten Haitzler (Rasterman)" Date: Mon, 12 Dec 2016 12:20:26 +0900 Subject: [PATCH] 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 | 519 ++++++++++++++++++++++++++++++++++------ 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, 540 insertions(+), 96 deletions(-) diff --git a/src/bin/e_client.c b/src/bin/e_client.c index 74a781b4f..9561cdf9e 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; - - EINA_LIST_FREE(list, child) + if (ec->stack.ignore == 0) { - Evas_Coord nx, ny, nw, nh; + Eina_List *l, *list = e_client_stack_list_prepare(ec); + E_Client *child; + Evas_Coord bx, by, bw, bh, cw, ch; - if ((ec->pre_cb.w > 0) && (ec->pre_cb.h > 0)) + if (e_client_util_resizing_get(ec)) { - 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); + 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)) + { + Eina_List *list = eina_list_clone(ec->transients); + E_Client *child; + + EINA_LIST_FREE(list, child) + { + 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; - - E_LIST_REVERSE_FREE(list, child) + if (ec->stack.ignore == 0) { - /* 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 *l, *list = e_client_stack_list_prepare(ec); + E_Client *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) + { + 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(ec->transients, l, child) - e_client_desk_set(child, ec->desk); + 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); + } } 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); - - EINA_LIST_FREE(list, child) + if (ec->stack.ignore == 0) { - child->sticky = 1; - e_hints_window_sticky_set(child, 1); - evas_object_show(ec->frame); + Eina_List *l, *list = e_client_stack_list_prepare(ec); + E_Client *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) + { + 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); - - EINA_LIST_FREE(list, child) + if (ec->stack.ignore == 0) { - child->sticky = 0; - e_hints_window_sticky_set(child, 0); + Eina_List *l, *list = e_client_stack_list_prepare(ec); + E_Client *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) + { + 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 7e6e95414..54f1381d3 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 be4eb0a0d..acfcd419b 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 2d2c6aade..f96ad0899 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 714431c85..069e1b260 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 bc8604ba1..68d32a0f4 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)