1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
|
From 998d9ea7942e3bcb07b52e06d08ef69bbe552944 Mon Sep 17 00:00:00 2001
From: Jim Ramsay <i.am@jimramsay.com>
Date: Fri, 30 Jan 2009 10:41:27 -0500
Subject: [PATCH 1/2] Added facility to selectively ignore EnterNotify events
This will be used to avoid some situations where an EnterNotify event should not
focus the window beneath the mouse cursor. For example, when a menu (or any
window for that matter) is unmapped, focus should not pass to whatever window is
beneath the current location of the mouse cursor, but to the previous window in
the focus list.
This was first noticed when using the ClientMenu feature with
focus-follows-mouse on -> The focus would always end up on the window beneath
the mouse pointer, not the window selected in the menu.
---
src/FocusControl.cc | 25 ++++++++++++++++++++++++-
src/FocusControl.hh | 10 ++++++++++
src/Window.cc | 8 ++++++--
3 files changed, 40 insertions(+), 3 deletions(-)
diff --git a/src/FocusControl.cc b/src/FocusControl.cc
index cead827..e0a3662 100644
--- a/src/FocusControl.cc
+++ b/src/FocusControl.cc
@@ -81,7 +81,8 @@ FocusControl::FocusControl(BScreen &screen):
m_focused_win_list(screen), m_creation_order_win_list(screen),
m_cycling_list(0),
m_was_iconic(false),
- m_cycling_last(0) {
+ m_cycling_last(0),
+ m_ignore_mouse_x(-1), m_ignore_mouse_y(-1) {
m_cycling_window = m_focused_list.clientList().end();
@@ -402,6 +403,28 @@ void FocusControl::dirFocus(FluxboxWindow &win, FocusDir dir) {
}
+void FocusControl::ignoreAtPointer()
+{
+ int ignore_i;
+ unsigned int ignore_ui;
+ Window ignore_w;
+
+ XQueryPointer(m_screen.rootWindow().display(),
+ m_screen.rootWindow().window(), &ignore_w, &ignore_w,
+ &m_ignore_mouse_x, &m_ignore_mouse_y,
+ &ignore_i, &ignore_i, &ignore_ui);
+}
+
+void FocusControl::ignoreAt(int x, int y)
+{
+ m_ignore_mouse_x = x; m_ignore_mouse_y = y;
+}
+
+bool FocusControl::isIgnored(int x, int y)
+{
+ return x == m_ignore_mouse_x && y == m_ignore_mouse_y;
+}
+
void FocusControl::removeClient(WinClient &client) {
if (client.screen().isShuttingdown())
return;
diff --git a/src/FocusControl.hh b/src/FocusControl.hh
index 4de4310..91681ab 100644
--- a/src/FocusControl.hh
+++ b/src/FocusControl.hh
@@ -93,6 +93,15 @@ public:
bool isMouseFocus() const { return focusModel() == MOUSEFOCUS; }
/// @return true if tab focus mode is mouse tab focus
bool isMouseTabFocus() const { return tabFocusModel() == MOUSETABFOCUS; }
+
+ /// Set the "ignore" pointer location to the current pointer location
+ void ignoreAtPointer();
+ /// Set the "ignore" pointer location to the given coordinates
+ void ignoreAt(int x, int y);
+ /// @return true if events at the given X/Y coordinate should be ignored
+ /// (ie, they were previously cached via one of the ignoreAt calls)
+ bool isIgnored(int x, int y);
+
/// @return true if cycling is in progress
bool isCycling() const { return m_cycling_list != 0; }
/// Appends a client to the front of the focus list
@@ -157,6 +166,7 @@ private:
const FocusableList *m_cycling_list;
Focusable *m_was_iconic;
WinClient *m_cycling_last;
+ int m_ignore_mouse_x, m_ignore_mouse_y;
static WinClient *s_focused_window;
static FluxboxWindow *s_focused_fbwindow;
diff --git a/src/Window.cc b/src/Window.cc
index 5d50fcf..fe32d29 100644
--- a/src/Window.cc
+++ b/src/Window.cc
@@ -2676,13 +2676,17 @@ void FluxboxWindow::enterNotifyEvent(XCrossingEvent &ev) {
sa.enter = sa.leave = False;
XCheckIfEvent(display, &dummy, queueScanner, (char *) &sa);
- if ((!sa.leave || sa.inferior) && !screen().focusControl().isCycling() ) {
+ if ((!sa.leave || sa.inferior) &&
+ !screen().focusControl().isCycling() &&
+ !screen().focusControl().isIgnored(ev.x_root, ev.y_root) ) {
focus();
}
}
}
- if (screen().focusControl().isMouseTabFocus() && client && client != m_client) {
+ if (screen().focusControl().isMouseTabFocus() &&
+ client && client != m_client &&
+ !screen().focusControl().isIgnored(ev.x_root, ev.y_root) ) {
setCurrentClient(*client, isFocused());
}
--
1.7.1
From e16a6d1fa71825b5390d9139b771f470aeb03d79 Mon Sep 17 00:00:00 2001
From: Jim Ramsay <i.am@jimramsay.com>
Date: Sat, 29 May 2010 09:30:48 -0400
Subject: [PATCH 2/2] Ignore EnterNotify when the ClientMenu closes
This is so that the resulting exposition of a window belowe the ClientMenu will
not steal focus from the window just focused by the ClientMenu.
---
src/ClientMenu.cc | 7 ++++++-
1 files changed, 6 insertions(+), 1 deletions(-)
diff --git a/src/ClientMenu.cc b/src/ClientMenu.cc
index f5af305..c49791c 100644
--- a/src/ClientMenu.cc
+++ b/src/ClientMenu.cc
@@ -25,6 +25,7 @@
#include "Screen.hh"
#include "Window.hh"
#include "WindowCmd.hh"
+#include "FocusControl.hh"
#include <X11/keysym.h>
#include "FbTk/MenuItem.hh"
@@ -52,8 +53,12 @@ public:
m_client.focus();
fbwin->raise();
- if ((mods & ControlMask) == 0)
+ if ((mods & ControlMask) == 0) {
+ // Ignore any focus changes due to this menu closing
+ // (even in StrictMouseFocus mode)
+ m_client.screen().focusControl().ignoreAtPointer();
parent->hide();
+ }
}
const std::string &label() const { return m_client.title(); }
--
1.7.1
|