This patch fixes a few sloppy focus problems (mouse was over a window which doesn't have the focus,...). See bug #210.

Great work sECuRE!


SVN revision: 32892
This commit is contained in:
Miculcy Brian 2007-11-26 21:33:23 +00:00
parent c7bbdb6b68
commit 55760113f6
2 changed files with 203 additions and 5 deletions

View File

@ -115,11 +115,20 @@ static E_Border *move = NULL;
static int grabbed = 0;
static Evas_List *focus_stack = NULL;
static Evas_List *raise_stack = NULL;
static Ecore_X_Screen_Size screen_size = { -1, -1 };
static int focus_track_frozen = 0;
static int warp_to = 0;
static int warp_to_x = 0;
static int warp_to_y = 0;
static int warp_x = 0;
static int warp_y = 0;
static Ecore_X_Window warp_to_win;
static Ecore_Timer *warp_timer = NULL;
EAPI int E_EVENT_BORDER_ADD = 0;
EAPI int E_EVENT_BORDER_REMOVE = 0;
EAPI int E_EVENT_BORDER_ZONE_SET = 0;
@ -731,7 +740,7 @@ e_border_hide(E_Border *bd, int manage)
e_border_focus_set(bd, 0, 1);
if (manage != 2)
{
if (e_config->focus_revert_on_hide_or_close)
if (e_config->focus_policy == E_FOCUS_CLICK && e_config->focus_revert_on_hide_or_close)
e_desk_last_focused_focus(bd->desk);
}
}
@ -1077,6 +1086,7 @@ e_border_raise(E_Border *bd)
/* If we don't have any children, raise this border */
above = e_container_border_raise(bd);
e_border_raise_latest_set(bd);
if (above)
{
/* We ended up above a border */
@ -1309,6 +1319,58 @@ e_border_focus_latest_set(E_Border *bd)
focus_stack = evas_list_prepend(focus_stack, bd);
}
EAPI void
e_border_raise_latest_set(E_Border *bd)
{
raise_stack = evas_list_remove(raise_stack, bd);
raise_stack = evas_list_prepend(raise_stack, bd);
}
/*
* Sets the focus to the given border if necessary
* There are 3 cases of different focus_policy-configurations:
*
* - E_FOCUS_CLICK: just set the focus, the most simple one
*
* - E_FOCUS_MOUSE: focus is where the mouse is, so try to
* warp the pointer to the window. If this fails (because
* the pointer is already in the window), just set the focus.
*
* - E_FOCUS_SLOPPY: focus is where the mouse is or on the
* last window which was focused, if the mouse is on the
* desktop. So, we need to look if there is another window
* under the pointer and warp to pointer to the right
* one if so (also, we set the focus afterwards). In case
* there is no window under pointer, the pointer is on the
* desktop and so we just set the focus.
*
*
* This function is to be called when setting the focus was not
* explicitly triggered by the user (by moving the mouse or
* clicking for example), but implicitly (by closing a window,
* the last focused window should get focus).
*
*/
EAPI void
e_border_focus_set_with_pointer(E_Border *bd)
{
if (e_config->focus_policy == E_FOCUS_SLOPPY)
{
if (e_border_under_pointer_get(NULL, bd))
{
if (!e_border_pointer_warp_to_center(bd))
e_border_focus_set(bd, 1, 1);
}
else
e_border_focus_set(bd, 1, 1);
}
else if (e_config->focus_policy == E_FOCUS_CLICK)
e_border_focus_set(bd, 1, 1);
else
if (!e_border_pointer_warp_to_center(bd))
e_border_focus_set(bd, 1, 1);
}
EAPI void
e_border_focus_set(E_Border *bd, int focus, int set)
{
@ -2747,6 +2809,12 @@ e_border_focus_stack_get(void)
return focus_stack;
}
EAPI Evas_List *
e_border_raise_stack_get(void)
{
return raise_stack;
}
EAPI Evas_List *
e_border_lost_windows_get(E_Zone *zone)
{
@ -3252,6 +3320,7 @@ _e_border_free(E_Border *bd)
borders_hash = evas_hash_del(borders_hash, e_util_winid_str_get(bd->win), bd);
borders = evas_list_remove(borders, bd);
focus_stack = evas_list_remove(focus_stack, bd);
raise_stack = evas_list_remove(raise_stack, bd);
e_container_border_remove(bd);
free(bd);
@ -3441,7 +3510,19 @@ _e_border_cb_window_hide(void *data, int ev_type, void *ev)
}
else
{
E_Border *pbd;
e_border_hide(bd, 0);
pbd = e_border_under_pointer_get(bd->desk, bd);
if (pbd)
e_border_focus_set(pbd, 1, 1);
else if (e_config->focus_policy == E_FOCUS_SLOPPY)
{
/* If we could not determine a window under cursor but
* sloppy focus is enabled, we focus the most recently
* focused window */
e_desk_last_focused_focus(bd->desk);
}
e_object_del(E_OBJECT(bd));
}
return 1;
@ -5292,8 +5373,10 @@ _e_border_eval(E_Border *bd)
e_border_layer_set(bd, bd->parent->layer);
if ((e_config->modal_windows) && (bd->client.netwm.state.modal))
bd->parent->modal = bd;
if (bd->parent->focused)
e_border_focus_set(bd, 1, 1);
if (e_config->focus_setting == E_FOCUS_NEW_DIALOG ||
(bd->parent->focused && (e_config->focus_setting == E_FOCUS_NEW_DIALOG_IF_OWNER_FOCUSED)))
bd->take_focus = 1;
}
bd->client.icccm.fetch.transient_for = 0;
rem_change = 1;
@ -6710,7 +6793,7 @@ _e_border_eval(E_Border *bd)
{
bd->want_focus = 0;
if (!bd->lock_focus_out)
e_border_focus_set(bd, 1, 1);
e_border_focus_set_with_pointer(bd);
}
else
{
@ -6722,7 +6805,7 @@ _e_border_eval(E_Border *bd)
e_border_focused_get())))
{
if (!bd->lock_focus_out)
e_border_focus_set(bd, 1, 1);
e_border_focus_set_with_pointer(bd);
}
}
}
@ -7580,3 +7663,113 @@ e_border_focus_track_thaw(void)
{
focus_track_frozen--;
}
EAPI E_Border *
e_border_under_pointer_get(E_Desk *desk, E_Border *exclude)
{
E_Border *bd = NULL;
Evas_List *l;
int x, y;
/* We need to ensure that we can get the container window for the
* zone of either the given desk or the desk of the excluded
* window, so return if neither is given */
if (desk)
ecore_x_pointer_xy_get(desk->zone->container->win, &x, &y);
else if (exclude)
ecore_x_pointer_xy_get(exclude->desk->zone->container->win, &x, &y);
else return;
for (l = e_border_raise_stack_get(); l; l = l->next)
{
E_Border *cbd;
cbd = l->data;
if (!cbd) continue;
/* If a border was specified which should be excluded from the list
* (because it will be closed shortly for example), skip */
if ((exclude) && (cbd == exclude)) continue;
if ((desk) && (cbd->desk != desk)) continue;
if ((x < cbd->x) || (x > (cbd->x + cbd->w)) ||
(y < cbd->y) || (y > (cbd->y + cbd->h))) continue;
/* If the layer is higher, the position of the window is higher
* (always on top vs always below) */
if (!bd || (cbd->layer > bd->layer))
{
bd = cbd;
break;
}
}
return bd;
}
static int
_e_border_pointer_warp_to_center_timer(void *data)
{
if (warp_to)
{
int dx, dy, x, y;
double spd;
ecore_x_pointer_xy_get(warp_to_win, &x, &y);
if ((x - warp_x) > 5 || (x - warp_x) < -5 ||
(y - warp_y) > 5 || (y - warp_y) < -5)
{
/* User moved the mouse, so stop warping */
warp_to = 0;
goto cleanup;
}
/* We just use the same warp speed as configured
* for the windowlist */
spd = e_config->winlist_warp_speed;
x = warp_x;
y = warp_y;
warp_x = (x * (1.0 - spd)) + (warp_to_x * spd);
warp_y = (y * (1.0 - spd)) + (warp_to_y * spd);
if (warp_x == x && warp_y == y)
{
warp_x = warp_to_x;
warp_y = warp_to_y;
warp_to = 0;
goto cleanup;
}
ecore_x_pointer_warp(warp_to_win, warp_x, warp_y);
return 1;
}
cleanup:
ecore_timer_del(warp_timer);
warp_timer = NULL;
return 0;
}
EAPI int
e_border_pointer_warp_to_center(E_Border *bd)
{
int x, y;
/* Only warp the pointer if it is not already in the area of
* the given border */
ecore_x_pointer_xy_get(bd->zone->container->win, &x, &y);
if ((x >= bd->x) && (x <= (bd->x + bd->w)) &&
(y >= bd->y) && (y <= (bd->y + bd->h)))
return 0;
warp_to_x = bd->x + (bd->w / 2);
if (warp_to_x < (bd->zone->x + 1))
warp_to_x = bd->zone->x + ((bd->x + bd->w - bd->zone->x) / 2);
else if (warp_to_x > (bd->zone->x + bd->zone->w))
warp_to_x = (bd->zone->x + bd->zone->w + bd->x) / 2;
warp_to_y = bd->y + (bd->h / 2);
if (warp_to_y < (bd->zone->y + 1))
warp_to_y = bd->zone->y + ((bd->y + bd->h - bd->zone->y) / 2);
else if (warp_to_y > (bd->zone->y + bd->zone->h))
warp_to_y = (bd->zone->y + bd->zone->h + bd->y) / 2;
warp_to = 1;
warp_to_win = bd->zone->container->win;
ecore_x_pointer_xy_get(bd->zone->container->win, &warp_x, &warp_y);
warp_timer = ecore_timer_add(0.01, _e_border_pointer_warp_to_center_timer, (const void*)bd);
return 1;
}

View File

@ -546,6 +546,8 @@ EAPI void e_border_lower(E_Border *bd);
EAPI void e_border_stack_above(E_Border *bd, E_Border *above);
EAPI void e_border_stack_below(E_Border *bd, E_Border *below);
EAPI void e_border_focus_latest_set(E_Border *bd);
EAPI void e_border_raise_latest_set(E_Border *bd);
EAPI void e_border_focus_set_with_pointer(E_Border *bd);
EAPI void e_border_focus_set(E_Border *bd, int focus, int set);
EAPI void e_border_shade(E_Border *bd, E_Direction dir);
EAPI void e_border_unshade(E_Border *bd, E_Direction dir);
@ -605,6 +607,9 @@ EAPI void e_border_hook_del(E_Border_Hook *bh);
EAPI void e_border_focus_track_freeze(void);
EAPI void e_border_focus_track_thaw(void);
EAPI E_Border *e_border_under_pointer_get(E_Desk *desk, E_Border *exclude);
EAPI int e_border_pointer_warp_to_center(E_Border *bd);
extern EAPI int E_EVENT_BORDER_RESIZE;
extern EAPI int E_EVENT_BORDER_MOVE;
extern EAPI int E_EVENT_BORDER_ADD;