Handle keynav vs. mousenav in mouse and sloppy focus modes. Fixes #167545.
2005-02-21 Elijah Newren <newren@gmail.com> Handle keynav vs. mousenav in mouse and sloppy focus modes. Fixes #167545. * doc/how-to-get-focus-right.txt: Update due to this new method for handling keynav vs. mousenav, plus various other updates that I previously forgot. * src/display.h: (struct _MetaDisplay): add a mouse_mode boolean * src/display.c: (meta_display_open): initialize mouse_mode to true, (event_callback): have EnterNotify and LeaveNotify events set mouse_mode to true when focusing a window * src/keybindings.c: (process_tab_grab): set mouse_mode to false when using alt-tab/alt-esc, (do_choose_window): likewise, (do_handle_move_to_workspace): set mouse_mode to false on move-window-to-workspace-<n> keybindings * src/window.c (idle_calc_showing): if we're in keynav mode while using sloppy or mouse focus, use metacity_sentinel to avoid EnterNotify events being generated from events other than mouse movement. * src/workspace.c (meta_workspace_activate_with_focus): add a FIXME in a potentially duplicate section of code, (meta_workspace_focus_default_window): use the same focus choice as click-to-focus if in keynav mode.
This commit is contained in:
parent
ad99427b49
commit
612507260a
30
ChangeLog
30
ChangeLog
@ -1,3 +1,33 @@
|
|||||||
|
2005-02-21 Elijah Newren <newren@gmail.com>
|
||||||
|
|
||||||
|
Handle keynav vs. mousenav in mouse and sloppy focus modes. Fixes
|
||||||
|
#167545.
|
||||||
|
|
||||||
|
* doc/how-to-get-focus-right.txt: Update due to this new method
|
||||||
|
for handling keynav vs. mousenav, plus various other updates that
|
||||||
|
I previously forgot.
|
||||||
|
|
||||||
|
* src/display.h: (struct _MetaDisplay): add a mouse_mode boolean
|
||||||
|
|
||||||
|
* src/display.c: (meta_display_open): initialize mouse_mode to
|
||||||
|
true, (event_callback): have EnterNotify and LeaveNotify events
|
||||||
|
set mouse_mode to true when focusing a window
|
||||||
|
|
||||||
|
* src/keybindings.c: (process_tab_grab): set mouse_mode to false
|
||||||
|
when using alt-tab/alt-esc, (do_choose_window): likewise,
|
||||||
|
(do_handle_move_to_workspace): set mouse_mode to false on
|
||||||
|
move-window-to-workspace-<n> keybindings
|
||||||
|
|
||||||
|
* src/window.c (idle_calc_showing): if we're in keynav mode while
|
||||||
|
using sloppy or mouse focus, use metacity_sentinel to avoid
|
||||||
|
EnterNotify events being generated from events other than mouse
|
||||||
|
movement.
|
||||||
|
|
||||||
|
* src/workspace.c (meta_workspace_activate_with_focus): add a
|
||||||
|
FIXME in a potentially duplicate section of code,
|
||||||
|
(meta_workspace_focus_default_window): use the same focus choice
|
||||||
|
as click-to-focus if in keynav mode.
|
||||||
|
|
||||||
2005-02-20 Elijah Newren <newren@gmail.com>
|
2005-02-20 Elijah Newren <newren@gmail.com>
|
||||||
|
|
||||||
* src/display.c: (event_callback): Handle _NET_CURRENT_DESKTOP
|
* src/display.c: (event_callback): Handle _NET_CURRENT_DESKTOP
|
||||||
|
@ -79,9 +79,26 @@ to alert the user that there is a window to work with:
|
|||||||
Additionally, the user may decide to use the keyboard instead of the mouse
|
Additionally, the user may decide to use the keyboard instead of the mouse
|
||||||
to navigate between windows (referred to as "keynav"). This poses no
|
to navigate between windows (referred to as "keynav"). This poses no
|
||||||
problems for click-to-focus (because the same invariant can be
|
problems for click-to-focus (because the same invariant can be
|
||||||
maintained), but for sloppy and mouse focus it means that EnterNotify
|
maintained), but for sloppy and mouse focus it requires extra work to
|
||||||
and LeaveNotify events should be ignored (they can be generated
|
attempt to handle the INHERENTLY CONFLICTING CONSTRAINTS. Metacity does
|
||||||
without using the mouse, for example, by grabs).
|
this by having a mouse_mode boolean used to determine which of the two
|
||||||
|
sets of invariants holds. This mode is set according to which method was
|
||||||
|
most recently used to choose a focus window:
|
||||||
|
1) When receiving EnterNotify/LeaveNotify events from mouse movement, set
|
||||||
|
mouse_mode to TRUE.
|
||||||
|
2) When using keynav to choose a focus window (e.g. alt-tab, alt-esc,
|
||||||
|
move-window-to-workspace keybindings), set mouse_mode to FALSE.
|
||||||
|
3) When handling events that don't choose a focus window but rather need
|
||||||
|
a focus_window chosen for them (e.g. switch-to-workspace keybindings),
|
||||||
|
don't change the mouse_mode and just use the current value.
|
||||||
|
Note that grabs present a special case since they can generate EnterNotify
|
||||||
|
and LeaveNotify events without using the mouse, thus these events should be
|
||||||
|
ignored when the crossing mode is NotifyGrab or NotifyUngrab. THIS
|
||||||
|
MOUSENAV/KEYNAV MODERATION METHOD IS NOT PERFECT--there are corner cases
|
||||||
|
when trying to mix-and-match between mousenav and keynav simultaneously
|
||||||
|
that cause problems; but it appears to be the most reasonable tradeoff and
|
||||||
|
works well in most cases, especially if the user sticks to just mousenav
|
||||||
|
for a long time or just keynav for a long time.
|
||||||
|
|
||||||
Finally, windows of type WM_DOCK or WM_DESKTOP (e.g. the desktop and
|
Finally, windows of type WM_DOCK or WM_DESKTOP (e.g. the desktop and
|
||||||
the panel) present a special case, at least partially due to the lack
|
the panel) present a special case, at least partially due to the lack
|
||||||
@ -103,7 +120,8 @@ To read more about the bugs that inspired these choices:
|
|||||||
Also, the EWMH spec, especially the parts relating to _NET_WM_USER_TIME
|
Also, the EWMH spec, especially the parts relating to _NET_WM_USER_TIME
|
||||||
- Modal vs. non-modal dialogs that get denied focus when mapped
|
- Modal vs. non-modal dialogs that get denied focus when mapped
|
||||||
http://bugzilla.gnome.org/show_bug.cgi?id=151996
|
http://bugzilla.gnome.org/show_bug.cgi?id=151996
|
||||||
- Ignoring EnterNotify and LeaveNotify events during keynav
|
- Mousenav vs. Keynav in mouse and sloppy focus modes
|
||||||
|
http://bugzilla.gnome.org/show_bug.cgi?id=167545
|
||||||
http://bugzilla.gnome.org/show_bug.cgi?id=101190
|
http://bugzilla.gnome.org/show_bug.cgi?id=101190
|
||||||
- Not focusing panels
|
- Not focusing panels
|
||||||
http://bugzilla.gnome.org/show_bug.cgi?id=160470
|
http://bugzilla.gnome.org/show_bug.cgi?id=160470
|
||||||
@ -121,6 +139,7 @@ the ones I'm the most familiar with):
|
|||||||
bug 95747 should ignore EnterNotify events with NotifyInferior detail set
|
bug 95747 should ignore EnterNotify events with NotifyInferior detail set
|
||||||
bug 97635 sticky windows always keep focus when switching workspaces
|
bug 97635 sticky windows always keep focus when switching workspaces
|
||||||
bug 102665 a window unminimized from the tasklist should be focused
|
bug 102665 a window unminimized from the tasklist should be focused
|
||||||
|
bug 107347 focus windows that manually position themselves too
|
||||||
bug 108643 focus in MRU order instead of stack order
|
bug 108643 focus in MRU order instead of stack order
|
||||||
bug 110970 moving a window to another workspace loses focus
|
bug 110970 moving a window to another workspace loses focus
|
||||||
bug 112031 closing a dialog can result in a strange focus window
|
bug 112031 closing a dialog can result in a strange focus window
|
||||||
@ -128,6 +147,7 @@ the ones I'm the most familiar with):
|
|||||||
bug 120100 panel shouldn't be focused after workspace applet usage
|
bug 120100 panel shouldn't be focused after workspace applet usage
|
||||||
bug 123803 need final EnterNotify after workspace switch (see also 124798)
|
bug 123803 need final EnterNotify after workspace switch (see also 124798)
|
||||||
bug 124981 focus clicked window in pager only if on current workspace
|
bug 124981 focus clicked window in pager only if on current workspace
|
||||||
|
bug 125492 catch the xserver unfocusing everything and fix its braindeadedness
|
||||||
bug 128200 focus correct window on libwnck window minimize (see 107681 too)
|
bug 128200 focus correct window on libwnck window minimize (see 107681 too)
|
||||||
bug 131582 fix race condition on window minimize/close
|
bug 131582 fix race condition on window minimize/close
|
||||||
bug 133120 wrong window focused when changing workspaces
|
bug 133120 wrong window focused when changing workspaces
|
||||||
@ -148,6 +168,18 @@ the ones I'm the most familiar with):
|
|||||||
bug 151990 prevent focus inconsistencies by only providing one focus method
|
bug 151990 prevent focus inconsistencies by only providing one focus method
|
||||||
bug 151996 modal dialogs denied focus should not be lowered
|
bug 151996 modal dialogs denied focus should not be lowered
|
||||||
bug 152000 fix race on window close followed by rapid mouse movement
|
bug 152000 fix race on window close followed by rapid mouse movement
|
||||||
|
bug 152004 ways to handle new window versus mouse invariants
|
||||||
|
bug 153220 catch the root window getting focus and reset to default window
|
||||||
|
bug 157360 focus parents of dismissed transient windows in preference to
|
||||||
|
the window that most recently had focus
|
||||||
|
bug 159257 focus the desktop when showing it
|
||||||
|
bug 160470 don't focus panels on click
|
||||||
|
bug 163450 correct highlighting in workspace switcher popup
|
||||||
|
bug 164716 refuse to focus a window with a modal transient, and focus
|
||||||
|
the transient instead
|
||||||
|
bug 166524 avoid new windows being obscured by the focus window
|
||||||
|
bug 167545 mousenav vs. keynav in mouse and sloppy focus modes
|
||||||
|
<a massive heap of bugs relating to focus stealing prevention...>
|
||||||
|
|
||||||
|
|
||||||
Addendum on sloppy and mouse focus
|
Addendum on sloppy and mouse focus
|
||||||
@ -156,7 +188,7 @@ Addendum on sloppy and mouse focus
|
|||||||
|
|
||||||
1) Keynav doesn't maintain the same invariants as mouse navigation
|
1) Keynav doesn't maintain the same invariants as mouse navigation
|
||||||
for these focus modes; switching back and forth between
|
for these focus modes; switching back and forth between
|
||||||
navigation methods, therefore, may appear to have
|
navigation methods, therefore, may have or appear to have
|
||||||
inconsistencies. Examples:
|
inconsistencies. Examples:
|
||||||
a) If the user uses Alt-Tab to change the window with focus, then
|
a) If the user uses Alt-Tab to change the window with focus, then
|
||||||
starts to move the mouse, at that moment the window where the
|
starts to move the mouse, at that moment the window where the
|
||||||
@ -182,6 +214,15 @@ Addendum on sloppy and mouse focus
|
|||||||
containing the menu) but is one of those hard-to-get-right
|
containing the menu) but is one of those hard-to-get-right
|
||||||
keynav and mouse focus mixture cases. (See bug 101190 for
|
keynav and mouse focus mixture cases. (See bug 101190 for
|
||||||
more details)
|
more details)
|
||||||
|
d) Similar to (c), moving the mouse off the menu doesn't immediately
|
||||||
|
focus the window that the mouse goes over, due to an application
|
||||||
|
grab (we couldn't change this and wouldn't want to, but
|
||||||
|
technically it does break the invariant).
|
||||||
|
e) If mouse_mode is off and the user does something to cause focus to
|
||||||
|
change (e.g. switch workspaces, close or minimize a window, etc.)
|
||||||
|
and simultaneously tries to move the mouse, the choice of which
|
||||||
|
window to focus is inherently race-y. (You probably can't satisfy
|
||||||
|
both keynav and mousenav invariants simultaneously...)
|
||||||
2) The sloppy/mouse invariants are often not strictly maintained;
|
2) The sloppy/mouse invariants are often not strictly maintained;
|
||||||
for example, we provide an exception to the invariant for newly
|
for example, we provide an exception to the invariant for newly
|
||||||
mapped windows. (Most find that not allowing this exception is
|
mapped windows. (Most find that not allowing this exception is
|
||||||
|
@ -343,6 +343,8 @@ meta_display_open (const char *name)
|
|||||||
display->expected_focus_window = NULL;
|
display->expected_focus_window = NULL;
|
||||||
display->grab_old_window_stacking = NULL;
|
display->grab_old_window_stacking = NULL;
|
||||||
|
|
||||||
|
display->mouse_mode = TRUE; /* Only relevant for mouse or sloppy focus */
|
||||||
|
|
||||||
#ifdef HAVE_XSYNC
|
#ifdef HAVE_XSYNC
|
||||||
display->grab_sync_request_alarm = None;
|
display->grab_sync_request_alarm = None;
|
||||||
#endif
|
#endif
|
||||||
@ -1785,10 +1787,15 @@ event_callback (XEvent *event,
|
|||||||
window->type != META_WINDOW_DESKTOP)
|
window->type != META_WINDOW_DESKTOP)
|
||||||
{
|
{
|
||||||
meta_topic (META_DEBUG_FOCUS,
|
meta_topic (META_DEBUG_FOCUS,
|
||||||
"Focusing %s due to enter notify with serial %lu\n",
|
"Focusing %s due to enter notify with serial %lu "
|
||||||
window->desc, event->xany.serial);
|
"at time %lu, and setting display->mouse_mode to "
|
||||||
|
"TRUE.\n",
|
||||||
|
window->desc,
|
||||||
|
event->xany.serial,
|
||||||
|
event->xcrossing.time);
|
||||||
|
|
||||||
meta_window_focus (window, event->xcrossing.time);
|
display->mouse_mode = TRUE;
|
||||||
|
meta_window_focus (window, event->xcrossing.time);
|
||||||
|
|
||||||
/* stop ignoring stuff */
|
/* stop ignoring stuff */
|
||||||
reset_ignores (display);
|
reset_ignores (display);
|
||||||
@ -1822,16 +1829,28 @@ event_callback (XEvent *event,
|
|||||||
switch (meta_prefs_get_focus_mode ())
|
switch (meta_prefs_get_focus_mode ())
|
||||||
{
|
{
|
||||||
case META_FOCUS_MODE_MOUSE:
|
case META_FOCUS_MODE_MOUSE:
|
||||||
if (window == display->expected_focus_window &&
|
if ((window->frame == NULL || frame_was_receiver) &&
|
||||||
(window->frame == NULL || frame_was_receiver) &&
|
|
||||||
event->xcrossing.mode != NotifyGrab &&
|
event->xcrossing.mode != NotifyGrab &&
|
||||||
event->xcrossing.mode != NotifyUngrab &&
|
event->xcrossing.mode != NotifyUngrab &&
|
||||||
event->xcrossing.detail != NotifyInferior)
|
event->xcrossing.detail != NotifyInferior)
|
||||||
{
|
{
|
||||||
meta_verbose ("Unsetting focus from %s due to LeaveNotify\n",
|
if (window == display->expected_focus_window)
|
||||||
window->desc);
|
{
|
||||||
meta_display_focus_the_no_focus_window (display,
|
meta_topic (META_DEBUG_FOCUS,
|
||||||
event->xcrossing.time);
|
"Unsetting focus from %s due to LeaveNotify\n",
|
||||||
|
window->desc);
|
||||||
|
meta_display_focus_the_no_focus_window (display,
|
||||||
|
event->xcrossing.time);
|
||||||
|
}
|
||||||
|
if (window->type != META_WINDOW_DOCK &&
|
||||||
|
window->type != META_WINDOW_DESKTOP)
|
||||||
|
{
|
||||||
|
meta_topic (META_DEBUG_FOCUS,
|
||||||
|
"Setting display->mouse_mode to TRUE due to "
|
||||||
|
"LeaveNotify at time %lu.\n",
|
||||||
|
event->xcrossing.time);
|
||||||
|
display->mouse_mode = TRUE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case META_FOCUS_MODE_SLOPPY:
|
case META_FOCUS_MODE_SLOPPY:
|
||||||
|
@ -204,6 +204,11 @@ struct _MetaDisplay
|
|||||||
/* last user interaction time in any app */
|
/* last user interaction time in any app */
|
||||||
Time last_user_time;
|
Time last_user_time;
|
||||||
|
|
||||||
|
/* whether we're using mousenav (only relevant for sloppy&mouse focus modes;
|
||||||
|
* !mouse_mode means "keynav mode")
|
||||||
|
*/
|
||||||
|
guint mouse_mode : 1;
|
||||||
|
|
||||||
guint static_gravity_works : 1;
|
guint static_gravity_works : 1;
|
||||||
|
|
||||||
/*< private-ish >*/
|
/*< private-ish >*/
|
||||||
|
@ -2378,8 +2378,10 @@ process_tab_grab (MetaDisplay *display,
|
|||||||
meta_topic (META_DEBUG_KEYBINDINGS,
|
meta_topic (META_DEBUG_KEYBINDINGS,
|
||||||
"Activating target window\n");
|
"Activating target window\n");
|
||||||
|
|
||||||
meta_topic (META_DEBUG_FOCUS, "Activating %s due to tab popup selection\n",
|
meta_topic (META_DEBUG_FOCUS, "Activating %s due to tab popup "
|
||||||
|
"selection and turning mouse_mode off\n",
|
||||||
target_window->desc);
|
target_window->desc);
|
||||||
|
display->mouse_mode = FALSE;
|
||||||
meta_window_activate (target_window, event->xkey.time);
|
meta_window_activate (target_window, event->xkey.time);
|
||||||
|
|
||||||
meta_topic (META_DEBUG_KEYBINDINGS,
|
meta_topic (META_DEBUG_KEYBINDINGS,
|
||||||
@ -2993,8 +2995,11 @@ do_choose_window (MetaDisplay *display,
|
|||||||
/* If no modifiers, we can't do the "hold down modifier to keep
|
/* If no modifiers, we can't do the "hold down modifier to keep
|
||||||
* moving" thing, so we just instaswitch by one window.
|
* moving" thing, so we just instaswitch by one window.
|
||||||
*/
|
*/
|
||||||
meta_topic (META_DEBUG_FOCUS, "Activating %s due to switch/cycle windows with no modifiers\n",
|
meta_topic (META_DEBUG_FOCUS,
|
||||||
|
"Activating %s and turning off mouse_mode due to "
|
||||||
|
"switch/cycle windows with no modifiers\n",
|
||||||
initial_selection->desc);
|
initial_selection->desc);
|
||||||
|
display->mouse_mode = FALSE;
|
||||||
meta_window_activate (initial_selection, event->xkey.time);
|
meta_window_activate (initial_selection, event->xkey.time);
|
||||||
}
|
}
|
||||||
else if (meta_display_begin_grab_op (display,
|
else if (meta_display_begin_grab_op (display,
|
||||||
@ -3017,9 +3022,13 @@ do_choose_window (MetaDisplay *display,
|
|||||||
* before we establish the grab. must end grab
|
* before we establish the grab. must end grab
|
||||||
* prior to trying to focus a window.
|
* prior to trying to focus a window.
|
||||||
*/
|
*/
|
||||||
meta_topic (META_DEBUG_FOCUS, "Ending grab and activating %s due to switch/cycle windows where modifier was released prior to grab\n",
|
meta_topic (META_DEBUG_FOCUS,
|
||||||
|
"Ending grab, activating %s, and turning off "
|
||||||
|
"mouse_mode due to switch/cycle windows where "
|
||||||
|
"modifier was released prior to grab\n",
|
||||||
initial_selection->desc);
|
initial_selection->desc);
|
||||||
meta_display_end_grab_op (display, event->xkey.time);
|
meta_display_end_grab_op (display, event->xkey.time);
|
||||||
|
display->mouse_mode = FALSE;
|
||||||
meta_window_activate (initial_selection, event->xkey.time);
|
meta_window_activate (initial_selection, event->xkey.time);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -3275,7 +3284,15 @@ do_handle_move_to_workspace (MetaDisplay *display,
|
|||||||
/* Activate second, so the window is never unmapped */
|
/* Activate second, so the window is never unmapped */
|
||||||
meta_window_change_workspace (window, workspace);
|
meta_window_change_workspace (window, workspace);
|
||||||
if (flip)
|
if (flip)
|
||||||
meta_workspace_activate_with_focus (workspace, window, event->xkey.time);
|
{
|
||||||
|
meta_topic (META_DEBUG_FOCUS,
|
||||||
|
"Resetting mouse_mode to FALSE due to "
|
||||||
|
"do_handle_move_to_workspace() call with flip set.\n");
|
||||||
|
workspace->screen->display->mouse_mode = FALSE;
|
||||||
|
meta_workspace_activate_with_focus (workspace,
|
||||||
|
window,
|
||||||
|
event->xkey.time);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
19
src/window.c
19
src/window.c
@ -1471,6 +1471,25 @@ idle_calc_showing (gpointer data)
|
|||||||
tmp = tmp->next;
|
tmp = tmp->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (meta_prefs_get_focus_mode () != META_FOCUS_MODE_CLICK)
|
||||||
|
{
|
||||||
|
/* When display->mouse_mode is false, we want to ignore
|
||||||
|
* EnterNotify events unless they come from mouse motion. To do
|
||||||
|
* that, we set a sentinel property on the root window if we're
|
||||||
|
* not in mouse_mode.
|
||||||
|
*/
|
||||||
|
tmp = should_show;
|
||||||
|
while (tmp != NULL)
|
||||||
|
{
|
||||||
|
MetaWindow *window = tmp->data;
|
||||||
|
|
||||||
|
if (!window->display->mouse_mode)
|
||||||
|
meta_display_increment_focus_sentinel (window->display);
|
||||||
|
|
||||||
|
tmp = tmp->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
g_slist_free (copy);
|
g_slist_free (copy);
|
||||||
|
|
||||||
g_slist_free (unplaced);
|
g_slist_free (unplaced);
|
||||||
|
@ -317,6 +317,7 @@ meta_workspace_activate_with_focus (MetaWorkspace *workspace,
|
|||||||
meta_workspace_queue_calc_showing (old);
|
meta_workspace_queue_calc_showing (old);
|
||||||
meta_workspace_queue_calc_showing (workspace);
|
meta_workspace_queue_calc_showing (workspace);
|
||||||
|
|
||||||
|
/* FIXME: Why do we need this?!? Isn't it handled in the lines above? */
|
||||||
if (move_window)
|
if (move_window)
|
||||||
/* Removes window from other spaces */
|
/* Removes window from other spaces */
|
||||||
meta_window_change_workspace (move_window, workspace);
|
meta_window_change_workspace (move_window, workspace);
|
||||||
@ -800,7 +801,8 @@ meta_workspace_focus_default_window (MetaWorkspace *workspace,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (meta_prefs_get_focus_mode () == META_FOCUS_MODE_CLICK)
|
if (meta_prefs_get_focus_mode () == META_FOCUS_MODE_CLICK ||
|
||||||
|
!workspace->screen->display->mouse_mode)
|
||||||
focus_ancestor_or_mru_window (workspace, not_this_one, timestamp);
|
focus_ancestor_or_mru_window (workspace, not_this_one, timestamp);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user