diff options
-rw-r--r-- | ChangeLog | 4 | ||||
-rw-r--r-- | src/FocusControl.cc | 255 | ||||
-rw-r--r-- | src/FocusControl.hh | 11 |
3 files changed, 75 insertions, 195 deletions
@@ -1,5 +1,9 @@ | |||
1 | (Format: Year/Month/Day) | 1 | (Format: Year/Month/Day) |
2 | Changes for 0.9.16: | 2 | Changes for 0.9.16: |
3 | *06/04/23: | ||
4 | * Tidy up window cycling, and make linear mode work in order of | ||
5 | creation (Thanks Mark Tiefenbruck, mark at tiefenbruck dot org) | ||
6 | FocusControl.hh/cc | ||
3 | *06/04/22: | 7 | *06/04/22: |
4 | * Fix workspace menu corruption when window title changes (Simon) | 8 | * Fix workspace menu corruption when window title changes (Simon) |
5 | sf.net bug #1113668 | 9 | sf.net bug #1113668 |
diff --git a/src/FocusControl.cc b/src/FocusControl.cc index a31270b..f7ed962 100644 --- a/src/FocusControl.cc +++ b/src/FocusControl.cc | |||
@@ -77,108 +77,84 @@ bool doSkipWindow(const WinClient &winclient, int opts) { | |||
77 | ); | 77 | ); |
78 | } | 78 | } |
79 | 79 | ||
80 | void FocusControl::prevFocus(int opts) { | 80 | void FocusControl::cycleFocus(int opts, bool cycle_reverse) { |
81 | int num_windows = m_screen.currentWorkspace()->numberOfWindows(); | 81 | int num_windows = m_screen.currentWorkspace()->numberOfWindows(); |
82 | 82 | ||
83 | if (num_windows < 1) | 83 | if (num_windows < 1) |
84 | return; | 84 | return; |
85 | 85 | ||
86 | if (!(opts & CYCLELINEAR)) { | 86 | FocusedWindows *window_list = (opts & CYCLELINEAR) ? &m_creation_order_list : &m_focused_list; |
87 | if (!m_cycling_focus) { | 87 | if (!m_cycling_focus) { |
88 | m_cycling_focus = true; | 88 | m_cycling_focus = true; |
89 | m_cycling_window = m_focused_list.end(); | 89 | if ((opts & CYCLELINEAR) && m_cycling_window != m_focused_list.end()) { |
90 | m_cycling_last = 0; | 90 | m_cycling_creation_order = true; |
91 | m_cycling_window = find(window_list->begin(),window_list->end(),*m_cycling_window); | ||
91 | } else { | 92 | } else { |
92 | // already cycling, so restack to put windows back in their proper order | 93 | m_cycling_creation_order = (opts & CYCLELINEAR); |
93 | m_screen.layerManager().restack(); | 94 | m_cycling_window = window_list->begin(); |
94 | } | 95 | } |
95 | // if it is stacked, we want the highest window in the focused list | 96 | m_cycling_last = 0; |
96 | // that is on the same workspace | 97 | } else { |
97 | FocusedWindows::iterator it = m_cycling_window; | 98 | // already cycling, so restack to put windows back in their proper order |
98 | FocusedWindows::iterator it_end = m_focused_list.end(); | 99 | m_screen.layerManager().restack(); |
99 | 100 | if (m_cycling_creation_order ^ (bool)(opts & CYCLELINEAR)) { | |
100 | while (true) { | 101 | m_cycling_creation_order ^= true; |
101 | --it; | 102 | if (m_cycling_window != m_focused_list.end() && m_cycling_window != m_creation_order_list.end()) |
102 | if (it == it_end) { | 103 | m_cycling_window = find(window_list->begin(),window_list->end(),*m_cycling_window); |
103 | it = m_focused_list.end(); | 104 | else |
104 | --it; | 105 | m_cycling_window = window_list->begin(); |
105 | } | 106 | } |
106 | // give up [do nothing] if we reach the current focused again | 107 | } |
107 | if ((*it) == (*m_cycling_window)) { | 108 | // if it is stacked, we want the highest window in the focused list |
108 | break; | 109 | // that is on the same workspace |
109 | } | 110 | FocusedWindows::iterator it = m_cycling_window; |
110 | 111 | FocusedWindows::iterator it_begin = window_list->begin(); | |
111 | FluxboxWindow *fbwin = (*it)->fbwindow(); | 112 | FocusedWindows::iterator it_end = window_list->end(); |
112 | if (fbwin && !fbwin->isIconic() && | 113 | |
113 | (fbwin->isStuck() | 114 | while (true) { |
114 | || fbwin->workspaceNumber() == m_screen.currentWorkspaceID())) { | 115 | if (cycle_reverse && it == it_begin) |
115 | // either on this workspace, or stuck | 116 | it = it_end; |
116 | 117 | cycle_reverse ? --it : ++it; | |
117 | // keep track of the originally selected window in a set | 118 | if (it == it_end) |
118 | WinClient &last_client = fbwin->winClient(); | 119 | it = it_begin; |
119 | 120 | // give up [do nothing] if we reach the current focused again | |
121 | if ((*it) == (*m_cycling_window)) | ||
122 | break; | ||
120 | 123 | ||
121 | if (! (doSkipWindow(**it, opts) || !fbwin->setCurrentClient(**it)) ) { | 124 | FluxboxWindow *fbwin = (*it)->fbwindow(); |
122 | // moved onto a new fbwin | 125 | if (fbwin && !fbwin->isIconic() && |
123 | if (!m_cycling_last || m_cycling_last->fbwindow() != fbwin) { | 126 | (fbwin->isStuck() |
124 | if (m_cycling_last) { | 127 | || fbwin->workspaceNumber() == m_screen.currentWorkspaceID())) { |
125 | // set back to orig current Client in that fbwin | 128 | // either on this workspace, or stuck |
126 | m_cycling_last->fbwindow()->setCurrentClient(*m_cycling_last, false); | 129 | |
127 | } | 130 | // keep track of the originally selected window in a set |
128 | m_cycling_last = &last_client; | 131 | WinClient &last_client = fbwin->winClient(); |
132 | |||
133 | if (! (doSkipWindow(**it, opts) || !fbwin->setCurrentClient(**it)) ) { | ||
134 | // moved onto a new fbwin | ||
135 | if (!m_cycling_last || m_cycling_last->fbwindow() != fbwin) { | ||
136 | if (m_cycling_last) { | ||
137 | // set back to orig current Client in that fbwin | ||
138 | m_cycling_last->fbwindow()->setCurrentClient(*m_cycling_last, false); | ||
129 | } | 139 | } |
130 | fbwin->tempRaise(); | 140 | m_cycling_last = &last_client; |
131 | break; | ||
132 | } | 141 | } |
142 | fbwin->tempRaise(); | ||
143 | break; | ||
133 | } | 144 | } |
134 | } | 145 | } |
135 | m_cycling_window = it; | ||
136 | } else { // not stacked cycling | ||
137 | |||
138 | Workspace &wksp = *m_screen.currentWorkspace(); | ||
139 | Workspace::Windows &wins = wksp.windowList(); | ||
140 | Workspace::Windows::iterator it = wins.begin(); | ||
141 | |||
142 | FluxboxWindow *focused_group = 0; | ||
143 | // start from the focused window | ||
144 | bool have_focused = false; | ||
145 | WinClient *focused = focusedWindow(); | ||
146 | if (focused != 0) { | ||
147 | if (focused->screen().screenNumber() == m_screen.screenNumber()) { | ||
148 | have_focused = true; | ||
149 | focused_group = focused->fbwindow(); | ||
150 | } | ||
151 | } | ||
152 | |||
153 | if (!have_focused) { | ||
154 | focused_group = (*it); | ||
155 | } else { | ||
156 | //get focused window iterator | ||
157 | for (; it != wins.end() && (*it) != focused_group; ++it) | ||
158 | continue; | ||
159 | } | ||
160 | |||
161 | do { | ||
162 | if (it == wins.begin()) | ||
163 | it = wins.end(); | ||
164 | --it; | ||
165 | // see if the window should be skipped | ||
166 | if (! (doSkipWindow((*it)->winClient(), opts) || !(*it)->setInputFocus()) ) | ||
167 | break; | ||
168 | } while ((*it) != focused_group); | ||
169 | |||
170 | if ((*it) != focused_group && it != wins.end()) | ||
171 | (*it)->raise(); | ||
172 | } | 146 | } |
173 | 147 | m_cycling_window = it; | |
174 | } | 148 | } |
175 | 149 | ||
176 | void FocusControl::addFocusFront(WinClient &client) { | 150 | void FocusControl::addFocusFront(WinClient &client) { |
177 | m_focused_list.push_front(&client); | 151 | m_focused_list.push_front(&client); |
152 | m_creation_order_list.push_back(&client); | ||
178 | } | 153 | } |
179 | 154 | ||
180 | void FocusControl::addFocusBack(WinClient &client) { | 155 | void FocusControl::addFocusBack(WinClient &client) { |
181 | m_focused_list.push_back(&client); | 156 | m_focused_list.push_back(&client); |
157 | m_creation_order_list.push_back(&client); | ||
182 | } | 158 | } |
183 | 159 | ||
184 | void FocusControl::stopCyclingFocus() { | 160 | void FocusControl::stopCyclingFocus() { |
@@ -191,7 +167,9 @@ void FocusControl::stopCyclingFocus() { | |||
191 | // put currently focused window to top | 167 | // put currently focused window to top |
192 | // the iterator may be invalid if the window died | 168 | // the iterator may be invalid if the window died |
193 | // in which case we'll do a proper revert focus | 169 | // in which case we'll do a proper revert focus |
194 | if (m_cycling_window != m_focused_list.end()) { | 170 | if (m_cycling_creation_order && m_cycling_window != m_creation_order_list.end()) |
171 | m_cycling_window = find(m_focused_list.begin(),m_focused_list.end(),*m_cycling_window); | ||
172 | if (m_cycling_window != m_focused_list.end() && m_cycling_window != m_creation_order_list.end()) { | ||
195 | WinClient *client = *m_cycling_window; | 173 | WinClient *client = *m_cycling_window; |
196 | m_focused_list.erase(m_cycling_window); | 174 | m_focused_list.erase(m_cycling_window); |
197 | m_focused_list.push_front(client); | 175 | m_focused_list.push_front(client); |
@@ -244,108 +222,6 @@ WinClient *FocusControl::lastFocusedWindow(FluxboxWindow &group, WinClient *igno | |||
244 | return 0; | 222 | return 0; |
245 | } | 223 | } |
246 | 224 | ||
247 | void FocusControl::nextFocus(int opts) { | ||
248 | const int num_windows = m_screen.currentWorkspace()->numberOfWindows(); | ||
249 | |||
250 | if (num_windows < 1) | ||
251 | return; | ||
252 | |||
253 | if (!(opts & CYCLELINEAR)) { | ||
254 | if (!m_cycling_focus) { | ||
255 | m_cycling_focus = true; | ||
256 | m_cycling_window = m_focused_list.begin(); | ||
257 | m_cycling_last = 0; | ||
258 | } else { | ||
259 | // already cycling, so restack to put windows back in their proper order | ||
260 | m_screen.layerManager().restack(); | ||
261 | } | ||
262 | // if it is stacked, we want the highest window in the focused list | ||
263 | // that is on the same workspace | ||
264 | FocusedWindows::iterator it = m_cycling_window; | ||
265 | const FocusedWindows::iterator it_end = m_focused_list.end(); | ||
266 | int safety_counter = 0; | ||
267 | while (true) { | ||
268 | ++it; | ||
269 | if (it == it_end) { | ||
270 | it = m_focused_list.begin(); | ||
271 | safety_counter++; | ||
272 | if (safety_counter > 3) | ||
273 | break; | ||
274 | } | ||
275 | // give up [do nothing] if we reach the current focused again | ||
276 | if ((*it) == (*m_cycling_window)) { | ||
277 | break; | ||
278 | } | ||
279 | |||
280 | FluxboxWindow *fbwin = (*it)->fbwindow(); | ||
281 | if (fbwin && !fbwin->isIconic() && | ||
282 | (fbwin->isStuck() | ||
283 | || fbwin->workspaceNumber() == m_screen.currentWorkspaceID())) { | ||
284 | // either on this workspace, or stuck | ||
285 | |||
286 | // keep track of the originally selected window in a set | ||
287 | WinClient &last_client = fbwin->winClient(); | ||
288 | |||
289 | if (! (doSkipWindow(**it, opts) || !fbwin->setCurrentClient(**it)) ) { | ||
290 | // moved onto a new fbwin | ||
291 | if (!m_cycling_last || m_cycling_last->fbwindow() != fbwin) { | ||
292 | if (m_cycling_last) { | ||
293 | // set back to orig current Client in that fbwin | ||
294 | m_cycling_last->fbwindow()->setCurrentClient(*m_cycling_last, false); | ||
295 | } | ||
296 | m_cycling_last = &last_client; | ||
297 | } | ||
298 | fbwin->tempRaise(); | ||
299 | break; | ||
300 | } | ||
301 | } | ||
302 | } | ||
303 | m_cycling_window = it; | ||
304 | } else { // not stacked cycling | ||
305 | // I really don't like this, but evidently some people use it(!) | ||
306 | Workspace &wksp = *m_screen.currentWorkspace(); | ||
307 | Workspace::Windows &wins = wksp.windowList(); | ||
308 | Workspace::Windows::iterator it = wins.begin(); | ||
309 | |||
310 | FluxboxWindow *focused_group = 0; | ||
311 | // start from the focused window | ||
312 | bool have_focused = false; | ||
313 | WinClient *focused = focusedWindow(); | ||
314 | if (focused != 0) { | ||
315 | if (focused->screen().screenNumber() == m_screen.screenNumber()) { | ||
316 | have_focused = true; | ||
317 | focused_group = focused->fbwindow(); | ||
318 | } | ||
319 | } | ||
320 | |||
321 | if (!have_focused) { | ||
322 | focused_group = (*it); | ||
323 | } else { | ||
324 | // get focused window iterator | ||
325 | for (; it != wins.end() && (*it) != focused_group; ++it) | ||
326 | continue; | ||
327 | } | ||
328 | |||
329 | int safety_counter = 0; | ||
330 | do { | ||
331 | ++it; | ||
332 | if (it == wins.end()) { | ||
333 | it = wins.begin(); | ||
334 | safety_counter++; | ||
335 | if (safety_counter > 3) | ||
336 | break; | ||
337 | } | ||
338 | // see if the window should be skipped | ||
339 | if (! (doSkipWindow((*it)->winClient(), opts) || !(*it)->setInputFocus()) ) | ||
340 | break; | ||
341 | } while ((*it) != focused_group); | ||
342 | |||
343 | if ((*it) != focused_group && it != wins.end()) | ||
344 | (*it)->raise(); | ||
345 | } | ||
346 | |||
347 | } | ||
348 | |||
349 | void FocusControl::raiseFocus() { | 225 | void FocusControl::raiseFocus() { |
350 | bool have_focused = false; | 226 | bool have_focused = false; |
351 | 227 | ||
@@ -483,17 +359,14 @@ void FocusControl::dirFocus(FluxboxWindow &win, FocusDir dir) { | |||
483 | 359 | ||
484 | void FocusControl::removeClient(WinClient &client) { | 360 | void FocusControl::removeClient(WinClient &client) { |
485 | WinClient *cyc = 0; | 361 | WinClient *cyc = 0; |
486 | if (m_cycling_window != m_focused_list.end()) | 362 | if (m_cycling_window != m_focused_list.end() && m_cycling_window != m_creation_order_list.end()) |
487 | cyc = *m_cycling_window; | 363 | cyc = *m_cycling_window; |
488 | 364 | ||
489 | m_focused_list.remove(&client); | 365 | m_focused_list.remove(&client); |
366 | m_creation_order_list.remove(&client); | ||
490 | 367 | ||
491 | if (cyc == &client) { | 368 | if (cyc == &client) |
492 | m_cycling_window = m_focused_list.end(); | 369 | stopCyclingFocus(); |
493 | } | ||
494 | |||
495 | if (m_cycling_last == &client) | ||
496 | m_cycling_last = 0; | ||
497 | 370 | ||
498 | } | 371 | } |
499 | 372 | ||
diff --git a/src/FocusControl.hh b/src/FocusControl.hh index 65363dd..fd8f56d 100644 --- a/src/FocusControl.hh +++ b/src/FocusControl.hh | |||
@@ -67,10 +67,11 @@ public: | |||
67 | 67 | ||
68 | explicit FocusControl(BScreen &screen); | 68 | explicit FocusControl(BScreen &screen); |
69 | 69 | ||
70 | void prevFocus() { prevFocus(0); } | 70 | void prevFocus() { cycleFocus(0, true); } |
71 | void nextFocus() { nextFocus(0); } | 71 | void nextFocus() { cycleFocus(0, false); } |
72 | void prevFocus(int options); | 72 | void prevFocus(int options) { cycleFocus(options, true); } |
73 | void nextFocus(int options); | 73 | void nextFocus(int options) { cycleFocus(options, false); } |
74 | void cycleFocus(int options, bool cycle_reverse); | ||
74 | void raiseFocus(); | 75 | void raiseFocus(); |
75 | 76 | ||
76 | void setScreenFocusedWindow(WinClient &win_client); | 77 | void setScreenFocusedWindow(WinClient &win_client); |
@@ -112,8 +113,10 @@ private: | |||
112 | // This list keeps the order of window focusing for this screen | 113 | // This list keeps the order of window focusing for this screen |
113 | // Screen global so it works for sticky windows too. | 114 | // Screen global so it works for sticky windows too. |
114 | FocusedWindows m_focused_list; | 115 | FocusedWindows m_focused_list; |
116 | FocusedWindows m_creation_order_list; | ||
115 | FocusedWindows::iterator m_cycling_window; | 117 | FocusedWindows::iterator m_cycling_window; |
116 | bool m_cycling_focus; | 118 | bool m_cycling_focus; |
119 | bool m_cycling_creation_order; | ||
117 | WinClient *m_cycling_last; | 120 | WinClient *m_cycling_last; |
118 | 121 | ||
119 | static WinClient *s_focused_window; | 122 | static WinClient *s_focused_window; |