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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
|
From 5c7784affe78467d7ef4e52e22da83c341622d53 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/5] 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 78752bb..701373b 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();
@@ -400,6 +401,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 4b4d1dc..513fbb6 100644
--- a/src/Window.cc
+++ b/src/Window.cc
@@ -2680,13 +2680,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.6.2
From 76ea1d9bbe3f3b7edb15da1a67652982edd5f646 Mon Sep 17 00:00:00 2001
From: Jim Ramsay <i.am@jimramsay.com>
Date: Fri, 30 Jan 2009 10:47:24 -0500
Subject: [PATCH 2/5] Ignore EnterNotify on Unmap
This is the basic condition that was first noticed because of the effect of the
ClientMenu window unmapping and the resulting EnterNotify event stealing focus
from the window selected in that menu. But to be complete, any window unmapping
should cause focus to move to the next in the last-recently-focused window list,
not the one that happens to be beneath the mouse cursor.
---
src/fluxbox.cc | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/src/fluxbox.cc b/src/fluxbox.cc
index 93768da..f44f8aa 100644
--- a/src/fluxbox.cc
+++ b/src/fluxbox.cc
@@ -899,6 +899,11 @@ void Fluxbox::handleUnmapNotify(XUnmapEvent &ue) {
BScreen *screen = searchScreen(ue.event);
+ if (screen) {
+ /* Ignore all EnterNotify events until the pointer actually moves */
+ screen->focusControl().ignoreAtPointer();
+ }
+
if (ue.event != ue.window && (!screen || !ue.send_event)) {
return;
}
--
1.6.2
From 8a7879913ba7169224e18db81888a49e732c1819 Mon Sep 17 00:00:00 2001
From: Jim Ramsay <i.am@jimramsay.com>
Date: Fri, 30 Jan 2009 10:51:10 -0500
Subject: [PATCH 3/5] Ignore EnterNotify on Lower
Lower is one of the actions which may reveal a window under the current mouse
pointer which would unexpectedly change focus under focus-folows-mouse.
---
src/Window.cc | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/src/Window.cc b/src/Window.cc
index 513fbb6..35d9b80 100644
--- a/src/Window.cc
+++ b/src/Window.cc
@@ -1668,6 +1668,10 @@ void FluxboxWindow::lower() {
#ifdef DEBUG
cerr<<"FluxboxWindow("<<title()<<")::lower()"<<endl;
#endif // DEBUG
+
+ /* Ignore all EnterNotify events until the pointer actually moves */
+ screen().focusControl().ignoreAtPointer();
+
// get root window
WinClient *client = getRootTransientFor(m_client);
--
1.6.2
From 54c1ac8704c2ad81a597547912bdbf5cbf7967d9 Mon Sep 17 00:00:00 2001
From: Jim Ramsay <i.am@jimramsay.com>
Date: Fri, 30 Jan 2009 10:54:04 -0500
Subject: [PATCH 4/5] Ignore EnterNotify on Move or Resize
Moving and Resizing windows can reveal other windows, which of course can change
unexpected focus changes in focus-follows-mouse.
---
src/Window.cc | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/src/Window.cc b/src/Window.cc
index 35d9b80..1104e50 100644
--- a/src/Window.cc
+++ b/src/Window.cc
@@ -1211,6 +1211,9 @@ void FluxboxWindow::moveResize(int new_x, int new_y,
if (!moving) {
m_last_resize_x = new_x;
m_last_resize_y = new_y;
+
+ /* Ignore all EnterNotify events until the pointer actually moves */
+ screen().focusControl().ignoreAtPointer();
}
}
--
1.6.2
From c1dee4a4055f8f0dafadeca508ff5568e2d0ce08 Mon Sep 17 00:00:00 2001
From: Jim Ramsay <i.am@jimramsay.com>
Date: Mon, 9 Mar 2009 14:05:41 -0400
Subject: [PATCH 5/5] Ignore EnterNotify on workspace change
Changing workspaces also reveals other windows, which causes unexpected focus
changes.
---
src/Screen.cc | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/src/Screen.cc b/src/Screen.cc
index 8b605e7..4d9a65f 100644
--- a/src/Screen.cc
+++ b/src/Screen.cc
@@ -1098,6 +1098,9 @@ void BScreen::changeWorkspaceID(unsigned int id, bool revert) {
id == m_current_workspace->workspaceID())
return;
+ /* Ignore all EnterNotify events until the pointer actually moves */
+ this->focusControl().ignoreAtPointer();
+
FbTk::App::instance()->sync(false);
FluxboxWindow *focused = FocusControl::focusedFbWindow();
--
1.6.2
|