2006-02-19 07:38:02 +00:00
|
|
|
// FocusControl.cc
|
2006-02-18 09:20:50 +00:00
|
|
|
// Copyright (c) 2006 Fluxbox Team (fluxgen at fluxbox dot org)
|
|
|
|
//
|
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
// copy of this software and associated documentation files (the "Software"),
|
|
|
|
// to deal in the Software without restriction, including without limitation
|
|
|
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
// and/or sell copies of the Software, and to permit persons to whom the
|
|
|
|
// Software is furnished to do so, subject to the following conditions:
|
|
|
|
//
|
|
|
|
// The above copyright notice and this permission notice shall be included in
|
|
|
|
// all copies or substantial portions of the Software.
|
|
|
|
//
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
|
|
// DEALINGS IN THE SOFTWARE.
|
|
|
|
|
|
|
|
// $Id$
|
|
|
|
|
|
|
|
#include "FocusControl.hh"
|
|
|
|
|
2007-10-13 21:51:37 +00:00
|
|
|
#include "ClientPattern.hh"
|
2006-02-18 09:20:50 +00:00
|
|
|
#include "Screen.hh"
|
|
|
|
#include "Window.hh"
|
|
|
|
#include "WinClient.hh"
|
|
|
|
#include "Workspace.hh"
|
|
|
|
#include "fluxbox.hh"
|
|
|
|
#include "FbWinFrameTheme.hh"
|
|
|
|
|
2007-03-04 17:47:37 +00:00
|
|
|
#include "FbTk/EventManager.hh"
|
|
|
|
|
2006-02-18 09:20:50 +00:00
|
|
|
#include <string>
|
|
|
|
#include <iostream>
|
2007-06-29 17:25:24 +00:00
|
|
|
#ifdef HAVE_CSTRING
|
|
|
|
#include <cstring>
|
|
|
|
#else
|
|
|
|
#include <string.h>
|
|
|
|
#endif
|
2006-04-25 06:46:06 +00:00
|
|
|
|
2006-02-18 09:20:50 +00:00
|
|
|
using std::cerr;
|
|
|
|
using std::endl;
|
|
|
|
using std::string;
|
|
|
|
|
|
|
|
WinClient *FocusControl::s_focused_window = 0;
|
2006-06-28 00:54:40 +00:00
|
|
|
FluxboxWindow *FocusControl::s_focused_fbwindow = 0;
|
2007-01-13 19:24:35 +00:00
|
|
|
bool FocusControl::s_reverting = false;
|
2006-02-18 09:20:50 +00:00
|
|
|
|
2007-10-13 21:51:37 +00:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
bool doSkipWindow(const Focusable &win, const ClientPattern *pat) {
|
|
|
|
const FluxboxWindow *fbwin = win.fbwindow();
|
|
|
|
if (!fbwin || fbwin->isFocusHidden())
|
|
|
|
return true; // skip if no fbwindow or if focushidden
|
|
|
|
if (pat && !pat->match(win))
|
|
|
|
return true; // skip if it doesn't match the pattern
|
|
|
|
if (fbwin->workspaceNumber() != win.screen().currentWorkspaceID() &&
|
|
|
|
!fbwin->isStuck())
|
|
|
|
return true; // for now, we only cycle through the current workspace
|
|
|
|
return false; // else don't skip
|
|
|
|
}
|
|
|
|
|
|
|
|
}; // end anonymous namespace
|
|
|
|
|
2006-02-18 09:20:50 +00:00
|
|
|
FocusControl::FocusControl(BScreen &screen):
|
|
|
|
m_screen(screen),
|
|
|
|
m_focus_model(screen.resourceManager(),
|
|
|
|
CLICKFOCUS,
|
|
|
|
screen.name()+".focusModel",
|
|
|
|
screen.altName()+".FocusModel"),
|
|
|
|
m_tab_focus_model(screen.resourceManager(),
|
|
|
|
CLICKTABFOCUS,
|
|
|
|
screen.name()+".tabFocusModel",
|
|
|
|
screen.altName()+".TabFocusModel"),
|
|
|
|
m_focus_new(screen.resourceManager(), true,
|
|
|
|
screen.name()+".focusNewWindows",
|
|
|
|
screen.altName()+".FocusNewWindows"),
|
2007-03-01 21:19:04 +00:00
|
|
|
m_cycling_list(0),
|
2006-07-14 06:00:37 +00:00
|
|
|
m_was_iconic(false),
|
2006-02-18 09:20:50 +00:00
|
|
|
m_cycling_last(0) {
|
|
|
|
|
2007-10-13 21:51:37 +00:00
|
|
|
m_cycling_window = m_focused_win_list.end();
|
2006-02-18 09:20:50 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2007-10-24 17:09:26 +00:00
|
|
|
void FocusControl::cycleFocus(const Focusables &window_list,
|
|
|
|
const ClientPattern *pat, bool cycle_reverse) {
|
2006-02-18 09:20:50 +00:00
|
|
|
|
2007-03-01 21:19:04 +00:00
|
|
|
if (!m_cycling_list) {
|
2007-03-04 17:47:37 +00:00
|
|
|
if (&m_screen == FbTk::EventManager::instance()->grabbingKeyboard())
|
2007-03-01 21:19:04 +00:00
|
|
|
// only set this when we're waiting for modifiers
|
2007-07-17 21:21:17 +00:00
|
|
|
m_cycling_list = &window_list;
|
2007-03-01 21:19:04 +00:00
|
|
|
m_was_iconic = 0;
|
2006-04-23 08:27:07 +00:00
|
|
|
m_cycling_last = 0;
|
2007-07-17 21:21:17 +00:00
|
|
|
} else if (m_cycling_list != &window_list)
|
|
|
|
m_cycling_list = &window_list;
|
|
|
|
|
2007-10-24 17:09:26 +00:00
|
|
|
Focusables::const_iterator it_begin = window_list.begin();
|
|
|
|
Focusables::const_iterator it_end = window_list.end();
|
2007-03-01 21:19:04 +00:00
|
|
|
|
|
|
|
// too many things can go wrong with remembering this
|
2007-07-17 21:21:17 +00:00
|
|
|
m_cycling_window = find(it_begin, it_end, s_focused_window);
|
2007-10-13 21:51:37 +00:00
|
|
|
if (m_cycling_window == it_end)
|
|
|
|
m_cycling_window = find(it_begin, it_end, s_focused_fbwindow);
|
2007-03-01 21:19:04 +00:00
|
|
|
|
2007-10-24 17:09:26 +00:00
|
|
|
Focusables::const_iterator it = m_cycling_window;
|
2007-07-17 21:21:17 +00:00
|
|
|
FluxboxWindow *fbwin = 0;
|
|
|
|
WinClient *last_client = 0;
|
|
|
|
WinClient *was_iconic = 0;
|
2006-04-23 08:27:07 +00:00
|
|
|
|
2007-03-01 21:19:04 +00:00
|
|
|
// find the next window in the list that works
|
2006-04-23 08:27:07 +00:00
|
|
|
while (true) {
|
|
|
|
if (cycle_reverse && it == it_begin)
|
|
|
|
it = it_end;
|
2006-07-14 06:00:37 +00:00
|
|
|
else if (!cycle_reverse && it == it_end)
|
2006-04-23 08:27:07 +00:00
|
|
|
it = it_begin;
|
2006-07-14 06:00:37 +00:00
|
|
|
else
|
|
|
|
cycle_reverse ? --it : ++it;
|
2006-04-23 08:27:07 +00:00
|
|
|
// give up [do nothing] if we reach the current focused again
|
2006-07-14 06:00:37 +00:00
|
|
|
if (it == m_cycling_window)
|
2007-07-17 21:21:17 +00:00
|
|
|
return;
|
2006-07-14 06:00:37 +00:00
|
|
|
if (it == it_end)
|
|
|
|
continue;
|
2006-02-18 09:20:50 +00:00
|
|
|
|
2007-07-17 21:21:17 +00:00
|
|
|
fbwin = (*it)->fbwindow();
|
2007-10-13 21:51:37 +00:00
|
|
|
if (!fbwin)
|
2007-07-17 21:21:17 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// keep track of the originally selected window in a group
|
|
|
|
last_client = &fbwin->winClient();
|
|
|
|
was_iconic = (fbwin->isIconic() ? last_client : 0);
|
|
|
|
|
|
|
|
// now we actually try to focus the window
|
2007-10-13 21:51:37 +00:00
|
|
|
if (!doSkipWindow(**it, pat) && (*it)->focus())
|
2007-07-17 21:21:17 +00:00
|
|
|
break;
|
|
|
|
}
|
2007-11-08 18:05:05 +00:00
|
|
|
m_cycling_window = it;
|
2007-07-17 21:21:17 +00:00
|
|
|
|
|
|
|
// if we're still in the same fbwin, there's nothing else to do
|
|
|
|
if (m_cycling_last && m_cycling_last->fbwindow() == fbwin)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// if we were already cycling, then restore the old state
|
|
|
|
if (m_cycling_last) {
|
|
|
|
m_screen.layerManager().restack();
|
|
|
|
|
|
|
|
// set back to originally selected window in that group
|
|
|
|
m_cycling_last->fbwindow()->setCurrentClient(*m_cycling_last, false);
|
|
|
|
|
|
|
|
if (m_was_iconic == m_cycling_last) {
|
|
|
|
s_reverting = true; // little hack
|
|
|
|
m_cycling_last->fbwindow()->iconify();
|
|
|
|
s_reverting = false;
|
2006-02-18 09:20:50 +00:00
|
|
|
}
|
|
|
|
}
|
2007-07-17 21:21:17 +00:00
|
|
|
|
2007-10-31 19:34:07 +00:00
|
|
|
if (!isCycling())
|
2007-07-17 21:21:17 +00:00
|
|
|
fbwin->raise();
|
|
|
|
|
|
|
|
m_cycling_last = last_client;
|
|
|
|
m_was_iconic = was_iconic;
|
|
|
|
|
2006-02-18 09:20:50 +00:00
|
|
|
}
|
|
|
|
|
2007-10-24 17:09:26 +00:00
|
|
|
void FocusControl::goToWindowNumber(const Focusables &winlist, int num,
|
2007-10-13 21:51:37 +00:00
|
|
|
const ClientPattern *pat) {
|
2007-11-05 17:05:58 +00:00
|
|
|
Focusables::const_iterator it = winlist.begin();
|
|
|
|
Focusables::const_iterator it_end = winlist.end();
|
|
|
|
for (; it != it_end && num; ++it) {
|
|
|
|
if (!doSkipWindow(**it, pat) && (*it)->acceptsFocus()) {
|
|
|
|
num > 0 ? --num : ++num;
|
|
|
|
if (!num) {
|
|
|
|
(*it)->focus();
|
|
|
|
if ((*it)->fbwindow())
|
|
|
|
(*it)->fbwindow()->raise();
|
2007-10-13 21:51:37 +00:00
|
|
|
}
|
|
|
|
}
|
2007-11-04 22:42:01 +00:00
|
|
|
}
|
2007-10-13 21:51:37 +00:00
|
|
|
}
|
|
|
|
|
2006-02-18 09:20:50 +00:00
|
|
|
void FocusControl::addFocusBack(WinClient &client) {
|
|
|
|
m_focused_list.push_back(&client);
|
2006-04-23 08:27:07 +00:00
|
|
|
m_creation_order_list.push_back(&client);
|
2006-02-18 09:20:50 +00:00
|
|
|
}
|
|
|
|
|
2007-01-26 17:21:44 +00:00
|
|
|
void FocusControl::addFocusFront(WinClient &client) {
|
|
|
|
m_focused_list.push_front(&client);
|
|
|
|
m_creation_order_list.push_back(&client);
|
|
|
|
}
|
|
|
|
|
2007-10-13 21:51:37 +00:00
|
|
|
void FocusControl::addFocusWinBack(Focusable &win) {
|
|
|
|
m_focused_win_list.push_back(&win);
|
|
|
|
m_creation_order_win_list.push_back(&win);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FocusControl::addFocusWinFront(Focusable &win) {
|
|
|
|
m_focused_win_list.push_front(&win);
|
|
|
|
m_creation_order_win_list.push_back(&win);
|
|
|
|
}
|
|
|
|
|
2007-01-04 00:11:22 +00:00
|
|
|
// move all clients in given window to back of focused list
|
|
|
|
void FocusControl::setFocusBack(FluxboxWindow *fbwin) {
|
|
|
|
// do nothing if there are no windows open
|
2007-01-04 02:15:29 +00:00
|
|
|
// don't change focus order while cycling
|
2007-03-01 21:19:04 +00:00
|
|
|
if (m_focused_list.empty() || s_reverting)
|
2007-01-04 00:11:22 +00:00
|
|
|
return;
|
|
|
|
|
2007-10-13 21:51:37 +00:00
|
|
|
// if the window isn't already in this list, we could accidentally add it
|
|
|
|
Focusables::iterator win_begin = m_focused_win_list.begin(),
|
|
|
|
win_end = m_focused_win_list.end();
|
|
|
|
Focusables::iterator win_it = find(win_begin, win_end, fbwin);
|
|
|
|
if (win_it == win_end)
|
|
|
|
return;
|
|
|
|
|
|
|
|
m_focused_win_list.erase(win_it);
|
|
|
|
m_focused_win_list.push_back(fbwin);
|
|
|
|
|
|
|
|
Focusables::iterator it = m_focused_list.begin();
|
2007-01-04 00:11:22 +00:00
|
|
|
// use back to avoid an infinite loop
|
2007-10-13 21:51:37 +00:00
|
|
|
Focusables::iterator it_back = --m_focused_list.end();
|
2007-01-04 00:11:22 +00:00
|
|
|
|
|
|
|
while (it != it_back) {
|
|
|
|
if ((*it)->fbwindow() == fbwin) {
|
|
|
|
m_focused_list.push_back(*it);
|
|
|
|
it = m_focused_list.erase(it);
|
|
|
|
} else
|
|
|
|
++it;
|
|
|
|
}
|
|
|
|
// move the last one, if necessary, in order to preserve focus order
|
|
|
|
if ((*it)->fbwindow() == fbwin) {
|
|
|
|
m_focused_list.push_back(*it);
|
|
|
|
m_focused_list.erase(it);
|
|
|
|
}
|
2007-10-13 21:51:37 +00:00
|
|
|
|
2007-01-04 00:11:22 +00:00
|
|
|
}
|
|
|
|
|
2006-02-18 09:20:50 +00:00
|
|
|
void FocusControl::stopCyclingFocus() {
|
|
|
|
// nothing to do
|
2007-03-01 21:19:04 +00:00
|
|
|
if (m_cycling_list == 0)
|
2006-02-18 09:20:50 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
m_cycling_last = 0;
|
2007-03-01 21:19:04 +00:00
|
|
|
m_cycling_list = 0;
|
|
|
|
|
2006-02-18 09:20:50 +00:00
|
|
|
// put currently focused window to top
|
2007-11-08 18:05:05 +00:00
|
|
|
if (s_focused_window) {
|
|
|
|
setScreenFocusedWindow(*s_focused_window);
|
|
|
|
if (s_focused_fbwindow)
|
|
|
|
s_focused_fbwindow->raise();
|
2007-03-01 21:19:04 +00:00
|
|
|
} else
|
2006-02-18 20:19:22 +00:00
|
|
|
revertFocus(m_screen);
|
2006-02-18 09:20:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Used to find out which window was last focused on the given workspace
|
|
|
|
* If workspace is outside the ID range, then the absolute last focused window
|
|
|
|
* is given.
|
|
|
|
*/
|
2007-10-13 21:51:37 +00:00
|
|
|
Focusable *FocusControl::lastFocusedWindow(int workspace) {
|
|
|
|
if (m_focused_list.empty() || m_screen.isShuttingdown()) return 0;
|
2006-02-18 09:20:50 +00:00
|
|
|
if (workspace < 0 || workspace >= (int) m_screen.numberOfWorkspaces())
|
|
|
|
return m_focused_list.front();
|
|
|
|
|
2007-10-13 21:51:37 +00:00
|
|
|
Focusables::iterator it = m_focused_list.begin();
|
|
|
|
Focusables::iterator it_end = m_focused_list.end();
|
2006-02-18 09:20:50 +00:00
|
|
|
for (; it != it_end; ++it) {
|
|
|
|
if ((*it)->fbwindow() &&
|
2006-12-28 18:11:17 +00:00
|
|
|
((((int)(*it)->fbwindow()->workspaceNumber()) == workspace ||
|
2007-01-05 17:57:07 +00:00
|
|
|
(*it)->fbwindow()->isStuck()) && (*it)->acceptsFocus() &&
|
|
|
|
!(*it)->fbwindow()->isIconic()))
|
2006-02-18 09:20:50 +00:00
|
|
|
return *it;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Used to find out which window was last active in the given group
|
|
|
|
* If ignore_client is given, it excludes that client.
|
|
|
|
* Stuck, iconic etc don't matter within a group
|
|
|
|
*/
|
|
|
|
WinClient *FocusControl::lastFocusedWindow(FluxboxWindow &group, WinClient *ignore_client) {
|
2007-10-13 21:51:37 +00:00
|
|
|
if (m_focused_list.empty() || m_screen.isShuttingdown())
|
|
|
|
return 0;
|
2006-02-18 09:20:50 +00:00
|
|
|
|
2007-10-13 21:51:37 +00:00
|
|
|
Focusables::iterator it = m_focused_list.begin();
|
|
|
|
Focusables::iterator it_end = m_focused_list.end();
|
2006-02-18 09:20:50 +00:00
|
|
|
for (; it != it_end; ++it) {
|
|
|
|
if (((*it)->fbwindow() == &group) &&
|
|
|
|
(*it) != ignore_client)
|
2007-10-13 21:51:37 +00:00
|
|
|
return dynamic_cast<WinClient *>(*it);
|
2006-02-18 09:20:50 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FocusControl::setScreenFocusedWindow(WinClient &win_client) {
|
|
|
|
|
|
|
|
// raise newly focused window to the top of the focused list
|
2006-07-19 07:31:39 +00:00
|
|
|
// don't change the order if we're cycling or shutting down
|
2007-10-13 21:51:37 +00:00
|
|
|
if (!isCycling() && !m_screen.isShuttingdown() && !s_reverting) {
|
|
|
|
|
|
|
|
// make sure client is in our list, or else we could end up adding it
|
|
|
|
Focusables::iterator it_begin = m_focused_list.begin(),
|
|
|
|
it_end = m_focused_list.end();
|
|
|
|
Focusables::iterator it = find(it_begin, it_end, &win_client);
|
|
|
|
if (it == it_end)
|
|
|
|
return;
|
|
|
|
|
|
|
|
m_focused_list.erase(it);
|
2006-02-18 09:20:50 +00:00
|
|
|
m_focused_list.push_front(&win_client);
|
2007-10-13 21:51:37 +00:00
|
|
|
|
|
|
|
// also check the fbwindow
|
|
|
|
it_begin = m_focused_win_list.begin();
|
|
|
|
it_end = m_focused_win_list.end();
|
|
|
|
it = find(it_begin, it_end, win_client.fbwindow());
|
|
|
|
|
|
|
|
if (it != it_end) {
|
|
|
|
m_focused_win_list.erase(it);
|
|
|
|
m_focused_win_list.push_front(win_client.fbwindow());
|
|
|
|
}
|
|
|
|
|
2006-02-18 09:20:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void FocusControl::setFocusModel(FocusModel model) {
|
|
|
|
m_focus_model = model;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FocusControl::setTabFocusModel(TabFocusModel model) {
|
|
|
|
m_tab_focus_model = model;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FocusControl::dirFocus(FluxboxWindow &win, FocusDir dir) {
|
|
|
|
// change focus to the window in direction dir from the given window
|
|
|
|
|
|
|
|
// we scan through the list looking for the window that is "closest"
|
|
|
|
// in the given direction
|
|
|
|
|
|
|
|
FluxboxWindow *foundwin = 0;
|
|
|
|
int weight = 999999, exposure = 0; // extreme values
|
|
|
|
int borderW = m_screen.winFrameTheme().border().width(),
|
2007-02-28 21:29:58 +00:00
|
|
|
top = win.y() + borderW,
|
|
|
|
bottom = win.y() + win.height() + borderW,
|
|
|
|
left = win.x() + borderW,
|
|
|
|
right = win.x() + win.width() + borderW;
|
2006-02-18 09:20:50 +00:00
|
|
|
|
|
|
|
Workspace::Windows &wins = m_screen.currentWorkspace()->windowList();
|
|
|
|
Workspace::Windows::iterator it = wins.begin();
|
|
|
|
for (; it != wins.end(); ++it) {
|
|
|
|
if ((*it) == &win
|
|
|
|
|| (*it)->isIconic()
|
|
|
|
|| (*it)->isFocusHidden()
|
2007-11-05 17:05:58 +00:00
|
|
|
|| !(*it)->acceptsFocus())
|
2006-02-18 09:20:50 +00:00
|
|
|
continue; // skip self
|
|
|
|
|
|
|
|
// we check things against an edge, and within the bounds (draw a picture)
|
|
|
|
int edge=0, upper=0, lower=0, oedge=0, oupper=0, olower=0;
|
|
|
|
|
2007-02-28 21:29:58 +00:00
|
|
|
int otop = (*it)->y() + borderW,
|
2006-02-18 20:19:22 +00:00
|
|
|
// 2 * border = border on each side
|
2007-02-28 21:29:58 +00:00
|
|
|
obottom = (*it)->y() + (*it)->height() + borderW,
|
|
|
|
oleft = (*it)->x() + borderW,
|
2006-02-18 20:19:22 +00:00
|
|
|
// 2 * border = border on each side
|
2007-02-28 21:29:58 +00:00
|
|
|
oright = (*it)->x() + (*it)->width() + borderW;
|
2006-02-18 20:19:22 +00:00
|
|
|
|
2006-02-18 09:20:50 +00:00
|
|
|
// check if they intersect
|
|
|
|
switch (dir) {
|
|
|
|
case FOCUSUP:
|
|
|
|
edge = obottom;
|
|
|
|
oedge = bottom;
|
|
|
|
upper = left;
|
|
|
|
oupper = oleft;
|
|
|
|
lower = right;
|
|
|
|
olower = oright;
|
|
|
|
break;
|
|
|
|
case FOCUSDOWN:
|
|
|
|
edge = top;
|
|
|
|
oedge = otop;
|
|
|
|
upper = left;
|
|
|
|
oupper = oleft;
|
|
|
|
lower = right;
|
|
|
|
olower = oright;
|
|
|
|
break;
|
|
|
|
case FOCUSLEFT:
|
|
|
|
edge = oright;
|
|
|
|
oedge = right;
|
|
|
|
upper = top;
|
|
|
|
oupper = otop;
|
|
|
|
lower = bottom;
|
|
|
|
olower = obottom;
|
|
|
|
break;
|
|
|
|
case FOCUSRIGHT:
|
|
|
|
edge = left;
|
|
|
|
oedge = oleft;
|
|
|
|
upper = top;
|
|
|
|
oupper = otop;
|
|
|
|
lower = bottom;
|
|
|
|
olower = obottom;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2006-02-18 20:19:22 +00:00
|
|
|
if (oedge < edge)
|
|
|
|
continue; // not in the right direction
|
|
|
|
|
2006-02-18 09:20:50 +00:00
|
|
|
if (olower <= upper || oupper >= lower) {
|
|
|
|
// outside our horz bounds, get a heavy weight penalty
|
|
|
|
int myweight = 100000 + oedge - edge + abs(upper-oupper)+abs(lower-olower);
|
|
|
|
if (myweight < weight) {
|
|
|
|
foundwin = *it;
|
|
|
|
exposure = 0;
|
|
|
|
weight = myweight;
|
|
|
|
}
|
|
|
|
} else if ((oedge - edge) < weight) {
|
|
|
|
foundwin = *it;
|
|
|
|
weight = oedge - edge;
|
|
|
|
exposure = ((lower < olower)?lower:olower) - ((upper > oupper)?upper:oupper);
|
|
|
|
} else if (foundwin && oedge - edge == weight) {
|
|
|
|
int myexp = ((lower < olower)?lower:olower) - ((upper > oupper)?upper:oupper);
|
|
|
|
if (myexp > exposure) {
|
|
|
|
foundwin = *it;
|
|
|
|
// weight is same
|
|
|
|
exposure = myexp;
|
|
|
|
}
|
|
|
|
} // else not improvement
|
|
|
|
}
|
|
|
|
|
|
|
|
if (foundwin)
|
2007-10-13 21:51:37 +00:00
|
|
|
foundwin->focus();
|
2006-02-18 09:20:50 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void FocusControl::removeClient(WinClient &client) {
|
2006-07-19 07:31:39 +00:00
|
|
|
if (client.screen().isShuttingdown())
|
|
|
|
return;
|
|
|
|
|
2007-11-08 18:05:05 +00:00
|
|
|
if (m_cycling_list && m_cycling_window != m_cycling_list->end() &&
|
|
|
|
*m_cycling_window == &client) {
|
2007-03-01 21:19:04 +00:00
|
|
|
m_cycling_window = m_cycling_list->end();
|
2006-04-23 08:27:07 +00:00
|
|
|
stopCyclingFocus();
|
2007-11-08 18:05:05 +00:00
|
|
|
} else if (m_cycling_last == &client)
|
|
|
|
m_cycling_last = 0;
|
2007-11-08 18:35:57 +00:00
|
|
|
|
|
|
|
m_focused_list.remove(&client);
|
|
|
|
m_creation_order_list.remove(&client);
|
|
|
|
client.screen().clientListSig().notify();
|
2006-02-18 09:20:50 +00:00
|
|
|
}
|
|
|
|
|
2007-10-13 21:51:37 +00:00
|
|
|
void FocusControl::removeWindow(Focusable &win) {
|
2007-11-08 18:05:05 +00:00
|
|
|
if (win.screen().isShuttingdown())
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (m_cycling_list && m_cycling_window != m_cycling_list->end() &&
|
|
|
|
*m_cycling_window == &win) {
|
|
|
|
m_cycling_window = m_cycling_list->end();
|
|
|
|
stopCyclingFocus();
|
|
|
|
}
|
2007-11-08 18:35:57 +00:00
|
|
|
|
|
|
|
m_focused_win_list.remove(&win);
|
|
|
|
m_creation_order_win_list.remove(&win);
|
|
|
|
win.screen().clientListSig().notify();
|
2007-10-13 21:51:37 +00:00
|
|
|
}
|
|
|
|
|
2006-07-19 07:31:39 +00:00
|
|
|
void FocusControl::shutdown() {
|
2007-01-26 17:21:44 +00:00
|
|
|
// restore windows backwards so they get put back correctly on restart
|
2007-10-13 21:51:37 +00:00
|
|
|
Focusables::reverse_iterator it = m_focused_list.rbegin();
|
2007-01-26 17:21:44 +00:00
|
|
|
for (; it != m_focused_list.rend(); ++it) {
|
2007-10-13 21:51:37 +00:00
|
|
|
WinClient *client = dynamic_cast<WinClient *>(*it);
|
|
|
|
if (client && client->fbwindow())
|
|
|
|
client->fbwindow()->restore(client, true);
|
2006-07-19 07:31:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-02-18 09:20:50 +00:00
|
|
|
/**
|
|
|
|
* This function is called whenever we aren't quite sure what
|
|
|
|
* focus is meant to be, it'll make things right ;-)
|
|
|
|
*/
|
|
|
|
void FocusControl::revertFocus(BScreen &screen) {
|
2007-10-13 21:51:37 +00:00
|
|
|
if (s_reverting || screen.isShuttingdown())
|
2006-07-14 06:00:37 +00:00
|
|
|
return;
|
2007-01-13 18:59:49 +00:00
|
|
|
|
2007-10-13 21:51:37 +00:00
|
|
|
Focusable *next_focus =
|
2006-02-18 09:20:50 +00:00
|
|
|
screen.focusControl().lastFocusedWindow(screen.currentWorkspaceID());
|
|
|
|
|
2007-08-20 14:31:43 +00:00
|
|
|
if (next_focus && next_focus->fbwindow() &&
|
|
|
|
next_focus->fbwindow()->isStuck())
|
|
|
|
FocusControl::s_reverting = true;
|
|
|
|
|
2006-02-18 09:20:50 +00:00
|
|
|
// if setting focus fails, or isn't possible, fallback correctly
|
2007-01-13 18:59:49 +00:00
|
|
|
if (!(next_focus && next_focus->focus())) {
|
2007-10-13 21:51:37 +00:00
|
|
|
|
2006-02-18 09:20:50 +00:00
|
|
|
setFocusedWindow(0); // so we don't get dangling m_focused_window pointer
|
2007-01-21 18:43:22 +00:00
|
|
|
// if there's a menu open, focus it
|
|
|
|
if (FbTk::Menu::shownMenu())
|
|
|
|
FbTk::Menu::shownMenu()->grabInputFocus();
|
|
|
|
else {
|
|
|
|
switch (screen.focusControl().focusModel()) {
|
|
|
|
case FocusControl::MOUSEFOCUS:
|
|
|
|
XSetInputFocus(screen.rootWindow().display(),
|
|
|
|
PointerRoot, None, CurrentTime);
|
|
|
|
break;
|
|
|
|
case FocusControl::CLICKFOCUS:
|
|
|
|
screen.rootWindow().setInputFocus(RevertToPointerRoot,
|
|
|
|
CurrentTime);
|
|
|
|
break;
|
|
|
|
}
|
2006-02-18 09:20:50 +00:00
|
|
|
}
|
|
|
|
}
|
2007-01-13 19:24:35 +00:00
|
|
|
|
|
|
|
FocusControl::s_reverting = false;
|
2006-02-18 09:20:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Like revertFocus, but specifically related to this window (transients etc)
|
|
|
|
* if full_revert, we fallback to a full revertFocus if we can't find anything
|
|
|
|
* local to the client.
|
|
|
|
* If unfocus_frame is true, we won't focus anything in the same frame
|
|
|
|
* as the client.
|
|
|
|
*
|
2007-10-13 21:51:37 +00:00
|
|
|
* So, we first prefer to choose the last client in this window, and if no luck
|
|
|
|
* (or unfocus_frame), then we just use the normal revertFocus on the screen.
|
2006-02-18 09:20:50 +00:00
|
|
|
*
|
|
|
|
* assumption: client has focus
|
|
|
|
*/
|
|
|
|
void FocusControl::unfocusWindow(WinClient &client,
|
|
|
|
bool full_revert,
|
|
|
|
bool unfocus_frame) {
|
|
|
|
// go up the transient tree looking for a focusable window
|
|
|
|
|
|
|
|
FluxboxWindow *fbwin = client.fbwindow();
|
|
|
|
if (fbwin == 0)
|
|
|
|
return; // nothing more we can do
|
|
|
|
|
|
|
|
BScreen &screen = fbwin->screen();
|
|
|
|
|
|
|
|
if (!unfocus_frame) {
|
|
|
|
WinClient *last_focus = screen.focusControl().lastFocusedWindow(*fbwin, &client);
|
|
|
|
if (last_focus != 0 &&
|
|
|
|
fbwin->setCurrentClient(*last_focus,
|
2006-02-18 20:19:22 +00:00
|
|
|
s_focused_window == &client)) {
|
2006-02-18 09:20:50 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-02-18 20:19:22 +00:00
|
|
|
if (full_revert && s_focused_window == &client)
|
2006-02-18 09:20:50 +00:00
|
|
|
revertFocus(screen);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void FocusControl::setFocusedWindow(WinClient *client) {
|
2006-02-18 20:19:22 +00:00
|
|
|
BScreen *screen = client ? &client->screen() : 0;
|
|
|
|
BScreen *old_screen =
|
|
|
|
FocusControl::focusedWindow() ?
|
|
|
|
&FocusControl::focusedWindow()->screen() : 0;
|
|
|
|
|
2006-02-18 09:20:50 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
cerr<<"------------------"<<endl;
|
|
|
|
cerr<<"Setting Focused window = "<<client<<endl;
|
2006-08-04 00:40:16 +00:00
|
|
|
if (client != 0)
|
|
|
|
cerr<<"title: "<<client->title()<<endl;
|
2006-02-18 09:20:50 +00:00
|
|
|
cerr<<"Current Focused window = "<<s_focused_window<<endl;
|
|
|
|
cerr<<"------------------"<<endl;
|
|
|
|
#endif // DEBUG
|
|
|
|
|
|
|
|
// Update the old focused client to non focus
|
2006-07-06 04:10:34 +00:00
|
|
|
if (s_focused_fbwindow)
|
|
|
|
s_focused_fbwindow->setFocusFlag(false);
|
2006-02-18 20:19:22 +00:00
|
|
|
|
2006-02-18 09:20:50 +00:00
|
|
|
if (client && client->fbwindow() && !client->fbwindow()->isIconic()) {
|
|
|
|
// screen should be ok
|
2006-06-28 00:54:40 +00:00
|
|
|
s_focused_fbwindow = client->fbwindow();
|
2006-02-18 09:20:50 +00:00
|
|
|
s_focused_window = client; // update focused window
|
2006-06-28 00:54:40 +00:00
|
|
|
s_focused_fbwindow->setCurrentClient(*client,
|
2006-02-18 20:19:22 +00:00
|
|
|
false); // don't set inputfocus
|
2006-06-28 00:54:40 +00:00
|
|
|
s_focused_fbwindow->setFocusFlag(true); // set focus flag
|
2006-02-18 09:20:50 +00:00
|
|
|
|
2006-06-28 00:54:40 +00:00
|
|
|
} else {
|
2006-02-18 09:20:50 +00:00
|
|
|
s_focused_window = 0;
|
2006-06-28 00:54:40 +00:00
|
|
|
s_focused_fbwindow = 0;
|
|
|
|
}
|
2006-02-18 09:20:50 +00:00
|
|
|
|
2006-02-18 20:19:22 +00:00
|
|
|
// update AtomHandlers and/or other stuff...
|
|
|
|
Fluxbox::instance()->updateFocusedWindow(screen, old_screen);
|
2006-02-18 09:20:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////// FocusControl RESOURCES
|
2006-03-02 07:49:13 +00:00
|
|
|
namespace FbTk {
|
|
|
|
|
2006-02-18 09:20:50 +00:00
|
|
|
template<>
|
|
|
|
std::string FbTk::Resource<FocusControl::FocusModel>::getString() const {
|
|
|
|
switch (m_value) {
|
|
|
|
case FocusControl::MOUSEFOCUS:
|
|
|
|
return string("MouseFocus");
|
|
|
|
case FocusControl::CLICKFOCUS:
|
|
|
|
return string("ClickFocus");
|
|
|
|
}
|
|
|
|
// default string
|
|
|
|
return string("ClickFocus");
|
|
|
|
}
|
|
|
|
|
|
|
|
template<>
|
|
|
|
void FbTk::Resource<FocusControl::FocusModel>::
|
|
|
|
setFromString(char const *strval) {
|
|
|
|
if (strcasecmp(strval, "MouseFocus") == 0)
|
|
|
|
m_value = FocusControl::MOUSEFOCUS;
|
|
|
|
else if (strcasecmp(strval, "ClickToFocus") == 0)
|
|
|
|
m_value = FocusControl::CLICKFOCUS;
|
|
|
|
else
|
|
|
|
setDefaultValue();
|
|
|
|
}
|
|
|
|
|
|
|
|
template<>
|
|
|
|
std::string FbTk::Resource<FocusControl::TabFocusModel>::getString() const {
|
|
|
|
switch (m_value) {
|
|
|
|
case FocusControl::MOUSETABFOCUS:
|
|
|
|
return string("SloppyTabFocus");
|
|
|
|
case FocusControl::CLICKTABFOCUS:
|
|
|
|
return string("ClickToTabFocus");
|
|
|
|
}
|
|
|
|
// default string
|
|
|
|
return string("ClickToTabFocus");
|
|
|
|
}
|
|
|
|
|
|
|
|
template<>
|
|
|
|
void FbTk::Resource<FocusControl::TabFocusModel>::
|
|
|
|
setFromString(char const *strval) {
|
|
|
|
|
|
|
|
if (strcasecmp(strval, "SloppyTabFocus") == 0 )
|
|
|
|
m_value = FocusControl::MOUSETABFOCUS;
|
|
|
|
else if (strcasecmp(strval, "ClickToTabFocus") == 0)
|
|
|
|
m_value = FocusControl::CLICKTABFOCUS;
|
|
|
|
else
|
|
|
|
setDefaultValue();
|
|
|
|
}
|
2006-03-02 07:49:13 +00:00
|
|
|
} // end namespace FbTk
|