aboutsummaryrefslogtreecommitdiff
path: root/src/FocusControl.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/FocusControl.cc')
-rw-r--r--src/FocusControl.cc187
1 files changed, 127 insertions, 60 deletions
diff --git a/src/FocusControl.cc b/src/FocusControl.cc
index d4cb410..6ccc9a1 100644
--- a/src/FocusControl.cc
+++ b/src/FocusControl.cc
@@ -23,6 +23,7 @@
23 23
24#include "FocusControl.hh" 24#include "FocusControl.hh"
25 25
26#include "ClientPattern.hh"
26#include "Screen.hh" 27#include "Screen.hh"
27#include "Window.hh" 28#include "Window.hh"
28#include "WinClient.hh" 29#include "WinClient.hh"
@@ -48,6 +49,22 @@ WinClient *FocusControl::s_focused_window = 0;
48FluxboxWindow *FocusControl::s_focused_fbwindow = 0; 49FluxboxWindow *FocusControl::s_focused_fbwindow = 0;
49bool FocusControl::s_reverting = false; 50bool FocusControl::s_reverting = false;
50 51
52namespace {
53
54bool doSkipWindow(const Focusable &win, const ClientPattern *pat) {
55 const FluxboxWindow *fbwin = win.fbwindow();
56 if (!fbwin || fbwin->isFocusHidden())
57 return true; // skip if no fbwindow or if focushidden
58 if (pat && !pat->match(win))
59 return true; // skip if it doesn't match the pattern
60 if (fbwin->workspaceNumber() != win.screen().currentWorkspaceID() &&
61 !fbwin->isStuck())
62 return true; // for now, we only cycle through the current workspace
63 return false; // else don't skip
64}
65
66}; // end anonymous namespace
67
51FocusControl::FocusControl(BScreen &screen): 68FocusControl::FocusControl(BScreen &screen):
52 m_screen(screen), 69 m_screen(screen),
53 m_focus_model(screen.resourceManager(), 70 m_focus_model(screen.resourceManager(),
@@ -65,28 +82,12 @@ FocusControl::FocusControl(BScreen &screen):
65 m_was_iconic(false), 82 m_was_iconic(false),
66 m_cycling_last(0) { 83 m_cycling_last(0) {
67 84
68 m_cycling_window = m_focused_list.end(); 85 m_cycling_window = m_focused_win_list.end();
69 86
70} 87}
71 88
72// true if the windows should be skiped else false 89void FocusControl::cycleFocus(Focusables &window_list, const ClientPattern *pat,
73bool doSkipWindow(const WinClient &winclient, int opts) { 90 bool cycle_reverse) {
74 const FluxboxWindow *win = winclient.fbwindow();
75 return (!win ||
76 // skip if stuck
77 (opts & FocusControl::CYCLESKIPSTUCK) != 0 && win->isStuck() ||
78 // skip if not active client (i.e. only visit each fbwin once)
79 (opts & FocusControl::CYCLEGROUPS) != 0 && win->winClient().window() != winclient.window() ||
80 // skip if shaded
81 (opts & FocusControl::CYCLESKIPSHADED) != 0 && win->isShaded() ||
82 // skip if iconic
83 (opts & FocusControl::CYCLESKIPICONIC) != 0 && win->isIconic() ||
84 // skip if hidden
85 win->isFocusHidden()
86 );
87}
88
89void FocusControl::cycleFocus(FocusedWindows &window_list, int opts, bool cycle_reverse) {
90 91
91 if (!m_cycling_list) { 92 if (!m_cycling_list) {
92 if (&m_screen == FbTk::EventManager::instance()->grabbingKeyboard()) 93 if (&m_screen == FbTk::EventManager::instance()->grabbingKeyboard())
@@ -97,13 +98,15 @@ void FocusControl::cycleFocus(FocusedWindows &window_list, int opts, bool cycle_
97 } else if (m_cycling_list != &window_list) 98 } else if (m_cycling_list != &window_list)
98 m_cycling_list = &window_list; 99 m_cycling_list = &window_list;
99 100
100 FocusedWindows::iterator it_begin = window_list.begin(); 101 Focusables::iterator it_begin = window_list.begin();
101 FocusedWindows::iterator it_end = window_list.end(); 102 Focusables::iterator it_end = window_list.end();
102 103
103 // too many things can go wrong with remembering this 104 // too many things can go wrong with remembering this
104 m_cycling_window = find(it_begin, it_end, s_focused_window); 105 m_cycling_window = find(it_begin, it_end, s_focused_window);
106 if (m_cycling_window == it_end)
107 m_cycling_window = find(it_begin, it_end, s_focused_fbwindow);
105 108
106 FocusedWindows::iterator it = m_cycling_window; 109 Focusables::iterator it = m_cycling_window;
107 FluxboxWindow *fbwin = 0; 110 FluxboxWindow *fbwin = 0;
108 WinClient *last_client = 0; 111 WinClient *last_client = 0;
109 WinClient *was_iconic = 0; 112 WinClient *was_iconic = 0;
@@ -123,11 +126,7 @@ void FocusControl::cycleFocus(FocusedWindows &window_list, int opts, bool cycle_
123 continue; 126 continue;
124 127
125 fbwin = (*it)->fbwindow(); 128 fbwin = (*it)->fbwindow();
126 // make sure the window is on the same workspace, 129 if (!fbwin)
127 // unless its sticky, which is ok
128 if (!fbwin ||
129 ( fbwin->workspaceNumber() != m_screen.currentWorkspaceID() &&
130 ! fbwin->isStuck()))
131 continue; 130 continue;
132 131
133 // keep track of the originally selected window in a group 132 // keep track of the originally selected window in a group
@@ -135,7 +134,7 @@ void FocusControl::cycleFocus(FocusedWindows &window_list, int opts, bool cycle_
135 was_iconic = (fbwin->isIconic() ? last_client : 0); 134 was_iconic = (fbwin->isIconic() ? last_client : 0);
136 135
137 // now we actually try to focus the window 136 // now we actually try to focus the window
138 if (!doSkipWindow(**it, opts) && (*it)->focus()) 137 if (!doSkipWindow(**it, pat) && (*it)->focus())
139 break; 138 break;
140 } 139 }
141 140
@@ -168,6 +167,33 @@ void FocusControl::cycleFocus(FocusedWindows &window_list, int opts, bool cycle_
168 167
169} 168}
170 169
170void FocusControl::goToWindowNumber(Focusables &winlist, int num,
171 const ClientPattern *pat) {
172 Focusable *last_matched = 0;
173 if (num > 0) {
174 Focusables::iterator it = winlist.begin();
175 Focusables::iterator it_end = winlist.end();
176 for (; it != it_end; ++it) {
177 if (!doSkipWindow(**it, pat) && (*it)->acceptsFocus()) {
178 --num;
179 last_matched = *it;
180 if (!num) break;
181 }
182 }
183 } else if (num < 0) {
184 Focusables::reverse_iterator it = winlist.rbegin();
185 Focusables::reverse_iterator it_end = winlist.rend();
186 for (; it != it_end; ++it) {
187 if (!doSkipWindow(**it, pat) && (*it)->acceptsFocus()) {
188 ++num;
189 last_matched = *it;
190 if (!num) break;
191 }
192 }
193 }
194 if (last_matched) last_matched->focus();
195}
196
171void FocusControl::addFocusBack(WinClient &client) { 197void FocusControl::addFocusBack(WinClient &client) {
172 m_focused_list.push_back(&client); 198 m_focused_list.push_back(&client);
173 m_creation_order_list.push_back(&client); 199 m_creation_order_list.push_back(&client);
@@ -178,6 +204,16 @@ void FocusControl::addFocusFront(WinClient &client) {
178 m_creation_order_list.push_back(&client); 204 m_creation_order_list.push_back(&client);
179} 205}
180 206
207void FocusControl::addFocusWinBack(Focusable &win) {
208 m_focused_win_list.push_back(&win);
209 m_creation_order_win_list.push_back(&win);
210}
211
212void FocusControl::addFocusWinFront(Focusable &win) {
213 m_focused_win_list.push_front(&win);
214 m_creation_order_win_list.push_back(&win);
215}
216
181// move all clients in given window to back of focused list 217// move all clients in given window to back of focused list
182void FocusControl::setFocusBack(FluxboxWindow *fbwin) { 218void FocusControl::setFocusBack(FluxboxWindow *fbwin) {
183 // do nothing if there are no windows open 219 // do nothing if there are no windows open
@@ -185,9 +221,19 @@ void FocusControl::setFocusBack(FluxboxWindow *fbwin) {
185 if (m_focused_list.empty() || s_reverting) 221 if (m_focused_list.empty() || s_reverting)
186 return; 222 return;
187 223
188 FocusedWindows::iterator it = m_focused_list.begin(); 224 // if the window isn't already in this list, we could accidentally add it
225 Focusables::iterator win_begin = m_focused_win_list.begin(),
226 win_end = m_focused_win_list.end();
227 Focusables::iterator win_it = find(win_begin, win_end, fbwin);
228 if (win_it == win_end)
229 return;
230
231 m_focused_win_list.erase(win_it);
232 m_focused_win_list.push_back(fbwin);
233
234 Focusables::iterator it = m_focused_list.begin();
189 // use back to avoid an infinite loop 235 // use back to avoid an infinite loop
190 FocusedWindows::iterator it_back = --m_focused_list.end(); 236 Focusables::iterator it_back = --m_focused_list.end();
191 237
192 while (it != it_back) { 238 while (it != it_back) {
193 if ((*it)->fbwindow() == fbwin) { 239 if ((*it)->fbwindow() == fbwin) {
@@ -201,6 +247,7 @@ void FocusControl::setFocusBack(FluxboxWindow *fbwin) {
201 m_focused_list.push_back(*it); 247 m_focused_list.push_back(*it);
202 m_focused_list.erase(it); 248 m_focused_list.erase(it);
203 } 249 }
250
204} 251}
205 252
206void FocusControl::stopCyclingFocus() { 253void FocusControl::stopCyclingFocus() {
@@ -208,7 +255,7 @@ void FocusControl::stopCyclingFocus() {
208 if (m_cycling_list == 0) 255 if (m_cycling_list == 0)
209 return; 256 return;
210 257
211 FocusedWindows::iterator it_end = m_cycling_list->end(); 258 Focusables::iterator it_end = m_cycling_list->end();
212 m_cycling_last = 0; 259 m_cycling_last = 0;
213 m_cycling_list = 0; 260 m_cycling_list = 0;
214 261
@@ -217,10 +264,9 @@ void FocusControl::stopCyclingFocus() {
217 // in which case we'll do a proper revert focus 264 // in which case we'll do a proper revert focus
218 if (m_cycling_window != it_end && (*m_cycling_window)->fbwindow() && 265 if (m_cycling_window != it_end && (*m_cycling_window)->fbwindow() &&
219 (*m_cycling_window)->fbwindow()->isVisible()) { 266 (*m_cycling_window)->fbwindow()->isVisible()) {
220 WinClient *client = *m_cycling_window; 267 (*m_cycling_window)->fbwindow()->raise();
221 m_focused_list.remove(client); 268 if (s_focused_window)
222 m_focused_list.push_front(client); 269 setScreenFocusedWindow(*s_focused_window);
223 client->fbwindow()->raise();
224 } else 270 } else
225 revertFocus(m_screen); 271 revertFocus(m_screen);
226} 272}
@@ -230,13 +276,13 @@ void FocusControl::stopCyclingFocus() {
230 * If workspace is outside the ID range, then the absolute last focused window 276 * If workspace is outside the ID range, then the absolute last focused window
231 * is given. 277 * is given.
232 */ 278 */
233WinClient *FocusControl::lastFocusedWindow(int workspace) { 279Focusable *FocusControl::lastFocusedWindow(int workspace) {
234 if (m_focused_list.empty()) return 0; 280 if (m_focused_list.empty() || m_screen.isShuttingdown()) return 0;
235 if (workspace < 0 || workspace >= (int) m_screen.numberOfWorkspaces()) 281 if (workspace < 0 || workspace >= (int) m_screen.numberOfWorkspaces())
236 return m_focused_list.front(); 282 return m_focused_list.front();
237 283
238 FocusedWindows::iterator it = m_focused_list.begin(); 284 Focusables::iterator it = m_focused_list.begin();
239 FocusedWindows::iterator it_end = m_focused_list.end(); 285 Focusables::iterator it_end = m_focused_list.end();
240 for (; it != it_end; ++it) { 286 for (; it != it_end; ++it) {
241 if ((*it)->fbwindow() && 287 if ((*it)->fbwindow() &&
242 ((((int)(*it)->fbwindow()->workspaceNumber()) == workspace || 288 ((((int)(*it)->fbwindow()->workspaceNumber()) == workspace ||
@@ -253,14 +299,15 @@ WinClient *FocusControl::lastFocusedWindow(int workspace) {
253 * Stuck, iconic etc don't matter within a group 299 * Stuck, iconic etc don't matter within a group
254 */ 300 */
255WinClient *FocusControl::lastFocusedWindow(FluxboxWindow &group, WinClient *ignore_client) { 301WinClient *FocusControl::lastFocusedWindow(FluxboxWindow &group, WinClient *ignore_client) {
256 if (m_focused_list.empty()) return 0; 302 if (m_focused_list.empty() || m_screen.isShuttingdown())
303 return 0;
257 304
258 FocusedWindows::iterator it = m_focused_list.begin(); 305 Focusables::iterator it = m_focused_list.begin();
259 FocusedWindows::iterator it_end = m_focused_list.end(); 306 Focusables::iterator it_end = m_focused_list.end();
260 for (; it != it_end; ++it) { 307 for (; it != it_end; ++it) {
261 if (((*it)->fbwindow() == &group) && 308 if (((*it)->fbwindow() == &group) &&
262 (*it) != ignore_client) 309 (*it) != ignore_client)
263 return *it; 310 return dynamic_cast<WinClient *>(*it);
264 } 311 }
265 return 0; 312 return 0;
266} 313}
@@ -269,11 +316,28 @@ void FocusControl::setScreenFocusedWindow(WinClient &win_client) {
269 316
270 // raise newly focused window to the top of the focused list 317 // raise newly focused window to the top of the focused list
271 // don't change the order if we're cycling or shutting down 318 // don't change the order if we're cycling or shutting down
272 // don't change on startup, as it may add windows that aren't listed yet 319 if (!isCycling() && !m_screen.isShuttingdown() && !s_reverting) {
273 if (!isCycling() && !m_screen.isShuttingdown() && !s_reverting && 320
274 !Fluxbox::instance()->isStartup()) { 321 // make sure client is in our list, or else we could end up adding it
275 m_focused_list.remove(&win_client); 322 Focusables::iterator it_begin = m_focused_list.begin(),
323 it_end = m_focused_list.end();
324 Focusables::iterator it = find(it_begin, it_end, &win_client);
325 if (it == it_end)
326 return;
327
328 m_focused_list.erase(it);
276 m_focused_list.push_front(&win_client); 329 m_focused_list.push_front(&win_client);
330
331 // also check the fbwindow
332 it_begin = m_focused_win_list.begin();
333 it_end = m_focused_win_list.end();
334 it = find(it_begin, it_end, win_client.fbwindow());
335
336 if (it != it_end) {
337 m_focused_win_list.erase(it);
338 m_focused_win_list.push_front(win_client.fbwindow());
339 }
340
277 } 341 }
278} 342}
279 343
@@ -380,7 +444,7 @@ void FocusControl::dirFocus(FluxboxWindow &win, FocusDir dir) {
380 } 444 }
381 445
382 if (foundwin) 446 if (foundwin)
383 foundwin->setInputFocus(); 447 foundwin->focus();
384 448
385} 449}
386 450
@@ -388,7 +452,7 @@ void FocusControl::removeClient(WinClient &client) {
388 if (client.screen().isShuttingdown()) 452 if (client.screen().isShuttingdown())
389 return; 453 return;
390 454
391 WinClient *cyc = 0; 455 Focusable *cyc = 0;
392 if (m_cycling_list && m_cycling_window != m_cycling_list->end()) 456 if (m_cycling_list && m_cycling_window != m_cycling_list->end())
393 cyc = *m_cycling_window; 457 cyc = *m_cycling_window;
394 458
@@ -401,27 +465,30 @@ void FocusControl::removeClient(WinClient &client) {
401 } 465 }
402} 466}
403 467
468void FocusControl::removeWindow(Focusable &win) {
469 m_focused_win_list.remove(&win);
470 m_creation_order_win_list.remove(&win);
471}
472
404void FocusControl::shutdown() { 473void FocusControl::shutdown() {
405 // restore windows backwards so they get put back correctly on restart 474 // restore windows backwards so they get put back correctly on restart
406 FocusedWindows::reverse_iterator it = m_focused_list.rbegin(); 475 Focusables::reverse_iterator it = m_focused_list.rbegin();
407 for (; it != m_focused_list.rend(); ++it) { 476 for (; it != m_focused_list.rend(); ++it) {
408 if (*it && (*it)->fbwindow()) 477 WinClient *client = dynamic_cast<WinClient *>(*it);
409 (*it)->fbwindow()->restore(*it, true); 478 if (client && client->fbwindow())
479 client->fbwindow()->restore(client, true);
410 } 480 }
411} 481}
412 482
413/** 483/**
414 * This function is called whenever we aren't quite sure what 484 * This function is called whenever we aren't quite sure what
415 * focus is meant to be, it'll make things right ;-) 485 * focus is meant to be, it'll make things right ;-)
416 * last_focused is set to something if we want to make use of the
417 * previously focused window (it must NOT be set focused now, it
418 * is probably dying).
419 */ 486 */
420void FocusControl::revertFocus(BScreen &screen) { 487void FocusControl::revertFocus(BScreen &screen) {
421 if (s_reverting) 488 if (s_reverting || screen.isShuttingdown())
422 return; 489 return;
423 490
424 WinClient *next_focus = 491 Focusable *next_focus =
425 screen.focusControl().lastFocusedWindow(screen.currentWorkspaceID()); 492 screen.focusControl().lastFocusedWindow(screen.currentWorkspaceID());
426 493
427 if (next_focus && next_focus->fbwindow() && 494 if (next_focus && next_focus->fbwindow() &&
@@ -430,6 +497,7 @@ void FocusControl::revertFocus(BScreen &screen) {
430 497
431 // if setting focus fails, or isn't possible, fallback correctly 498 // if setting focus fails, or isn't possible, fallback correctly
432 if (!(next_focus && next_focus->focus())) { 499 if (!(next_focus && next_focus->focus())) {
500
433 setFocusedWindow(0); // so we don't get dangling m_focused_window pointer 501 setFocusedWindow(0); // so we don't get dangling m_focused_window pointer
434 // if there's a menu open, focus it 502 // if there's a menu open, focus it
435 if (FbTk::Menu::shownMenu()) 503 if (FbTk::Menu::shownMenu())
@@ -458,9 +526,8 @@ void FocusControl::revertFocus(BScreen &screen) {
458 * If unfocus_frame is true, we won't focus anything in the same frame 526 * If unfocus_frame is true, we won't focus anything in the same frame
459 * as the client. 527 * as the client.
460 * 528 *
461 * So, we first prefer to choose a transient parent, then the last 529 * So, we first prefer to choose the last client in this window, and if no luck
462 * client in this window, and if no luck (or unfocus_frame), then 530 * (or unfocus_frame), then we just use the normal revertFocus on the screen.
463 * we just use the normal revertFocus on the screen.
464 * 531 *
465 * assumption: client has focus 532 * assumption: client has focus
466 */ 533 */