diff options
author | Thomas Lübking <thomas.luebking@gmail.com> | 2016-05-23 13:00:19 (GMT) |
---|---|---|
committer | Mathias Gumz <akira@fluxbox.org> | 2016-05-28 09:05:45 (GMT) |
commit | 98313bfb91e45a3f95a74e84ea4cbc7ec7f8a66f (patch) | |
tree | d7a39e314fa0423debac796233a1f1e0d25d4909 | |
parent | cb1a82ba9fa78dfc98d59cd875e19f40d6e9cf7a (diff) | |
download | fluxbox-98313bfb91e45a3f95a74e84ea4cbc7ec7f8a66f.zip fluxbox-98313bfb91e45a3f95a74e84ea4cbc7ec7f8a66f.tar.bz2 |
harden focus cycling against client focussing
Clients which implement a client-side modality might cause
livelocks by reverting the focus to the transient (after the
WM tried to put it on the leader as the transient's modality
is unknown)
So while cycling we revert the focus whenever it moves somewhere
where we don't expect it.
When done, we also focus the window that should have the focus anyway
to allow the client to redistribute the focus (as we prevented it
during cycling)
Hall of Shame: Softmaker Freeoffice uses (only) client side modality.
-rw-r--r-- | src/FocusControl.cc | 16 |
1 files changed, 15 insertions, 1 deletions
diff --git a/src/FocusControl.cc b/src/FocusControl.cc index f0d88b9..3be7937 100644 --- a/src/FocusControl.cc +++ b/src/FocusControl.cc | |||
@@ -239,7 +239,11 @@ void FocusControl::stopCyclingFocus() { | |||
239 | 239 | ||
240 | // put currently focused window to top | 240 | // put currently focused window to top |
241 | if (s_focused_window) { | 241 | if (s_focused_window) { |
242 | setScreenFocusedWindow(*s_focused_window); | 242 | // re-focus last window to give the client a chance to redistribute the |
243 | // focus internally (client-side only modality) | ||
244 | s_focused_window->focus(); | ||
245 | if (s_focused_window) | ||
246 | setScreenFocusedWindow(*s_focused_window); | ||
243 | if (s_focused_fbwindow) | 247 | if (s_focused_fbwindow) |
244 | s_focused_fbwindow->raise(); | 248 | s_focused_fbwindow->raise(); |
245 | } else | 249 | } else |
@@ -574,6 +578,16 @@ void FocusControl::setFocusedWindow(WinClient *client) { | |||
574 | return; | 578 | return; |
575 | 579 | ||
576 | BScreen *screen = client ? &client->screen() : 0; | 580 | BScreen *screen = client ? &client->screen() : 0; |
581 | if (screen && screen->focusControl().isCycling()) { | ||
582 | WinClient *last = screen->focusControl().m_cycling_last; | ||
583 | if (last && last != client && screen->focusControl().m_cycling_list->contains(*last)) { | ||
584 | // if we're currently cycling and the client tries to juggle around focus | ||
585 | // on FocusIn events to provide client-side modality - don't let him | ||
586 | last->focus(); | ||
587 | return; | ||
588 | } | ||
589 | } | ||
590 | |||
577 | BScreen *old_screen = | 591 | BScreen *old_screen = |
578 | FocusControl::focusedWindow() ? | 592 | FocusControl::focusedWindow() ? |
579 | &FocusControl::focusedWindow()->screen() : 0; | 593 | &FocusControl::focusedWindow()->screen() : 0; |