raster pushed a commit to branch master. http://git.enlightenment.org/core/enlightenment.git/commit/?id=5ec93f15ffa57d10fa513edbb1661450e1ec2fff
commit 5ec93f15ffa57d10fa513edbb1661450e1ec2fff Author: Carsten Haitzler (Rasterman) <ras...@rasterman.com> Date: Tue Aug 29 20:31:30 2017 +0900 e actions - add actions for moving focus around - feature request was simple. winlist already had it. added action to focus next/prev or up/down/left/right. useful for tiling... :) @feature --- src/bin/e_actions.c | 212 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 212 insertions(+) diff --git a/src/bin/e_actions.c b/src/bin/e_actions.c index 0252b5354..718455b9a 100644 --- a/src/bin/e_actions.c +++ b/src/bin/e_actions.c @@ -2991,6 +2991,197 @@ ACT_FN_GO(screen_redo, EINA_UNUSED) #endif } +/***************************************************************************/ +static Eina_Bool +_skip_win(E_Client *ec, E_Zone *zone, E_Desk *desk) +{ + if ((!ec->icccm.accepts_focus) && (!ec->icccm.take_focus)) return EINA_TRUE; + if (ec->netwm.state.skip_taskbar) return EINA_TRUE; + if (ec->user_skip_winlist) return EINA_TRUE; + if (ec->iconic) return EINA_TRUE; + if (ec->zone != zone) return EINA_TRUE; + if (!((ec->sticky) || (ec->desk == desk))) return EINA_TRUE; + return EINA_FALSE; +} + +static int +_point_line_dist(int x, int y, int lx1, int ly1, int lx2, int ly2) +{ + int xx, yy, dx, dy; + int a = x - lx1; + int b = y - ly1; + int c = lx2 - lx1; + int d = ly2 - ly1; + int dot = (a * c) + (b * d); + int len_sq = (c * c) + (d * d); + double dist, param = -1.0; + + // if line is 0 length + if (len_sq) param = (double)dot / len_sq; + + if (param < 0) + { + xx = lx1; + yy = ly1; + } + else if (param > 1) + { + xx = lx2; + yy = ly2; + } + else + { + xx = lx1 + lround(param * c); + yy = ly1 + lround(param * d); + } + + dx = x - xx; + dy = y - yy; + dist = sqrt((dx * dx) + (dy * dy)); + return lround(dist); +} + +ACT_FN_GO(window_focus, EINA_UNUSED) +{ + E_Zone *zone = e_zone_current_get(); + E_Desk *desk = e_desk_current_get(zone); + E_Client *ec, *ec_orig, + *ec_prev = NULL, *ec_last = NULL, *ec_first = NULL, *ec_next = NULL; + Eina_List *l; + int distance = INT_MAX, cx, cy, dir = -1, found = 0; + + if (!params) return; + ec_orig = e_client_focused_get(); + if (!ec_orig) + { + // XXX: just pick any window to focus + EINA_LIST_FOREACH(e_client_focus_stack_get(), l, ec) + { + if (_skip_win(ec, zone, desk)) continue; + e_client_focus_set_with_pointer(ec); + return; + } + return; + } + + if (!strcmp(params, "next")) dir = -1; + else if (!strcmp(params, "prev")) dir = -2; + else if (!strcmp(params, "up")) dir = 0; + else if (!strcmp(params, "down")) dir = 1; + else if (!strcmp(params, "left")) dir = 2; + else if (!strcmp(params, "right")) dir = 3; + else + { + e_util_dialog_show(_("Error: window_focus action"), + _("Invalid parameter: %s"), params); + return; + } + if (dir < 0) + { + EINA_LIST_FOREACH(e_client_focus_stack_get(), l, ec) + { + if (_skip_win(ec, zone, desk)) continue; + + if (ec == ec_orig) + { + found = 1; + return; + } + else if (!found) ec_prev = ec; + else if ((found) && (!ec_next)) ec_next = ec; + + if (!ec_first) ec_first = ec; + ec_last = ec; + } + if (dir == -1) /* next */ + { + if (ec_next) e_client_focus_set_with_pointer(ec_next); + else if (ec_first) e_client_focus_set_with_pointer(ec_first); + } + else if (dir == -2) + { + if (ec_prev) e_client_focus_set_with_pointer(ec_prev); + else if (ec_last) e_client_focus_set_with_pointer(ec_last); + } + return; + } + + cx = ec_orig->x + (ec_orig->w / 2); + cy = ec_orig->y + (ec_orig->h / 2); + + EINA_LIST_FOREACH(e_client_focus_stack_get(), l, ec) + { + int a = 0, d = 0; + + if (ec == ec_orig) continue; + if (_skip_win(ec, zone, desk)) continue; + + switch (dir) + { + case 0: /* up */ + d = _point_line_dist(cx, cy, + ec->x, ec->y + ec->h, + ec->x + ec->w, ec->y + ec->h); + if (d >= distance) continue; + d = _point_line_dist(cx, cy, + ec->x, ec->y + (ec->h / 2), + ec->x + ec->w, ec->y + (ec->h / 2)); + if (d >= distance) continue; + if (cy <= (ec->y + (ec->h / 2))) continue; + a = abs(cx - (ec->x + (ec->w / 2))); + d += (a * a) / d; + if (d >= distance) continue; + break; + case 1: /* down */ + d = _point_line_dist(cx, cy, + ec->x, ec->y, + ec->x + ec->w, ec->y); + if (d >= distance) continue; + d = _point_line_dist(cx, cy, + ec->x, ec->y + (ec->h / 2), + ec->x + ec->w, ec->y + (ec->h / 2)); + if (d >= distance) continue; + if (cy >= (ec->y + (ec->h / 2))) continue; + a = abs(cx - (ec->x + (ec->w / 2))); + d += (a * a) / d; + if (d >= distance) continue; + break; + case 2: /* left */ + d = _point_line_dist(cx, cy, + ec->x + ec->w, ec->y, + ec->x + ec->w, ec->y + ec->h); + if (d >= distance) continue; + d = _point_line_dist(cx, cy, + ec->x + (ec->w / 2), ec->y, + ec->x + (ec->w / 2), ec->y + ec->h); + if (d >= distance) continue; + if (cx <= (ec->x + (ec->w / 2))) continue; + a = abs(cy - (ec->y + (ec->h / 2))); + d += (a * a) / d; + if (d >= distance) continue; + break; + case 3: /* right */ + d = _point_line_dist(cx, cy, + ec->x, ec->y, + ec->x, ec->y + ec->h); + if (d >= distance) continue; + d = _point_line_dist(cx, cy, + ec->x + (ec->w / 2), ec->y, + ec->x + (ec->w / 2), ec->y + ec->h); + if (d >= distance) continue; + if (cx >= (ec->x + (ec->w / 2))) continue; + a = abs(cy - (ec->y + (ec->h / 2))); + d += (a * a) / d; + if (d >= distance) continue; + break; + } + ec_next = ec; + distance = d; + } + + if (ec_next) e_client_focus_set_with_pointer(ec_next); +} + /* local subsystem globals */ static Eina_Hash *actions = NULL; static Eina_List *action_list = NULL; @@ -3440,6 +3631,27 @@ e_actions_init(void) e_action_predef_name_set(N_("Window : Moving"), N_("To Previous Screen"), "window_zone_move_by", "-1", NULL, 0); + /* Move window focus somewhere */ + ACT_GO(window_focus); + e_action_predef_name_set(N_("Window : Focus"), + N_("Focus next window"), + "window_focus", "next", NULL, 0); + e_action_predef_name_set(N_("Window : Focus"), + N_("Focus previous window"), + "window_focus", "prev", NULL, 0); + e_action_predef_name_set(N_("Window : Focus"), + N_("Focus window above"), + "window_focus", "up", NULL, 0); + e_action_predef_name_set(N_("Window : Focus"), + N_("Focus window below"), + "window_focus", "down", NULL, 0); + e_action_predef_name_set(N_("Window : Focus"), + N_("Focus window left"), + "window_focus", "left", NULL, 0); + e_action_predef_name_set(N_("Window : Focus"), + N_("Focus window right"), + "window_focus", "right", NULL, 0); + /* menu_show */ ACT_GO(menu_show); e_action_predef_name_set(N_("Menu"), N_("Show Main Menu"), --