make doFocusLast work for sloppy focus as well
This commit is contained in:
parent
35fe2d5e12
commit
fa4328d862
6 changed files with 182 additions and 34 deletions
|
@ -1,5 +1,10 @@
|
|||
(Format: Year/Month/Day)
|
||||
Changes for 0.9.6:
|
||||
*03/10/05:
|
||||
* Make focusLast work for sloppy focus when changing workspace or
|
||||
closing a window (Simon)
|
||||
- also generalises event redirects (e.g. for window moving)
|
||||
fluxbox.hh/cc Window.hh/cc Screen.cc
|
||||
*03/10/04:
|
||||
* Fix NLS bad message errors by adding explicit codeset entries (Simon)
|
||||
- thanks to Matt Hope for pointing us to the recent workaround from
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
// $Id: Screen.cc,v 1.236 2003/10/02 16:14:41 rathnor Exp $
|
||||
// $Id: Screen.cc,v 1.237 2003/10/05 02:31:22 rathnor Exp $
|
||||
|
||||
|
||||
#include "Screen.hh"
|
||||
|
@ -836,6 +836,7 @@ void BScreen::changeWorkspaceID(unsigned int id) {
|
|||
return;
|
||||
|
||||
XSync(FbTk::App::instance()->display(), true);
|
||||
|
||||
WinClient *focused_client = Fluxbox::instance()->getFocusedWindow();
|
||||
FluxboxWindow *focused = 0;
|
||||
if (focused_client)
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
// $Id: Window.cc,v 1.238 2003/10/02 16:14:41 rathnor Exp $
|
||||
// $Id: Window.cc,v 1.239 2003/10/05 02:31:22 rathnor Exp $
|
||||
|
||||
#include "Window.hh"
|
||||
|
||||
|
@ -888,7 +888,7 @@ void FluxboxWindow::updateClientLeftWindow() {
|
|||
}
|
||||
}
|
||||
|
||||
bool FluxboxWindow::setCurrentClient(WinClient &client, bool setinput) {
|
||||
bool FluxboxWindow::setCurrentClient(WinClient &client, bool setinput, long ignore_event) {
|
||||
// make sure it's in our list
|
||||
if (client.m_win != this)
|
||||
return false;
|
||||
|
@ -896,7 +896,7 @@ bool FluxboxWindow::setCurrentClient(WinClient &client, bool setinput) {
|
|||
m_client = &client;
|
||||
m_client->raise();
|
||||
frame().setLabelButtonFocus(*m_labelbuttons[m_client]);
|
||||
return setinput && setInputFocus();
|
||||
return setinput && setInputFocus(ignore_event);
|
||||
}
|
||||
|
||||
bool FluxboxWindow::isGroupable() const {
|
||||
|
@ -1138,7 +1138,7 @@ void FluxboxWindow::moveResize(int new_x, int new_y,
|
|||
// tried. A FocusqIn event should eventually arrive for that
|
||||
// window if it actually got the focus, then setFocusedFlag is called,
|
||||
// which updates all the graphics etc
|
||||
bool FluxboxWindow::setInputFocus() {
|
||||
bool FluxboxWindow::setInputFocus(long ignore_event) {
|
||||
|
||||
if (((signed) (frame().x() + frame().width())) < 0) {
|
||||
if (((signed) (frame().y() + frame().height())) < 0) {
|
||||
|
@ -1181,6 +1181,14 @@ bool FluxboxWindow::setInputFocus() {
|
|||
if (m_client->getFocusMode() == WinClient::F_LOCALLYACTIVE ||
|
||||
m_client->getFocusMode() == WinClient::F_PASSIVE) {
|
||||
m_client->setInputFocus(RevertToPointerRoot, CurrentTime);
|
||||
|
||||
// People can ignore an event until the focus comes through
|
||||
// this is most likely to be an EnterNotify for sloppy focus
|
||||
if (ignore_event)
|
||||
Fluxbox::instance()->addRedirectEvent(
|
||||
&screen(), ignore_event, None,
|
||||
FocusIn, m_client->window(), None);
|
||||
|
||||
// this may or may not send, but we've setInputFocus already, so return true
|
||||
m_client->sendFocus();
|
||||
return true;
|
||||
|
@ -2724,7 +2732,16 @@ void FluxboxWindow::startMoving(Window win) {
|
|||
if (m_windowmenu.isVisible())
|
||||
m_windowmenu.hide();
|
||||
|
||||
fluxbox->maskWindowEvents(screen().rootWindow().window(), this);
|
||||
// The "stop" window and event aren't going to happen (since it's
|
||||
// grabbed, so they are just so we can remove it in stopMoving)
|
||||
fluxbox->addRedirectEvent(&screen(),
|
||||
MotionNotify, screen().rootWindow().window(),
|
||||
MotionNotify, fbWindow().window(),
|
||||
fbWindow().window());
|
||||
fluxbox->addRedirectEvent(&screen(),
|
||||
ButtonRelease, screen().rootWindow().window(),
|
||||
ButtonRelease, fbWindow().window(),
|
||||
fbWindow().window());
|
||||
|
||||
m_last_move_x = frame().x();
|
||||
m_last_move_y = frame().y();
|
||||
|
@ -2742,8 +2759,8 @@ void FluxboxWindow::stopMoving() {
|
|||
moving = false;
|
||||
Fluxbox *fluxbox = Fluxbox::instance();
|
||||
|
||||
fluxbox->maskWindowEvents(0, 0);
|
||||
|
||||
fluxbox->removeRedirectEvent(MotionNotify, fbWindow().window());
|
||||
fluxbox->removeRedirectEvent(ButtonRelease, fbWindow().window());
|
||||
|
||||
if (! screen().doOpaqueMove()) {
|
||||
parent().drawRectangle(screen().rootTheme().opGC(),
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
// $Id: Window.hh,v 1.97 2003/09/29 14:58:15 rathnor Exp $
|
||||
// $Id: Window.hh,v 1.98 2003/10/05 02:31:23 rathnor Exp $
|
||||
|
||||
#ifndef WINDOW_HH
|
||||
#define WINDOW_HH
|
||||
|
@ -167,14 +167,14 @@ public:
|
|||
/// remove client from client list
|
||||
bool removeClient(WinClient &client);
|
||||
/// set new current client and raise it
|
||||
bool setCurrentClient(WinClient &client, bool setinput = true);
|
||||
bool setCurrentClient(WinClient &client, bool setinput = true, long ignore_event = 0);
|
||||
WinClient *findClient(Window win);
|
||||
void nextClient();
|
||||
void prevClient();
|
||||
void moveClientLeft();
|
||||
void moveClientRight();
|
||||
|
||||
bool setInputFocus();
|
||||
bool setInputFocus(long ignore_event = 0);
|
||||
void raiseAndFocus() { raise(); setInputFocus(); }
|
||||
void setFocusFlag(bool flag);
|
||||
// map this window
|
||||
|
|
131
src/fluxbox.cc
131
src/fluxbox.cc
|
@ -22,7 +22,7 @@
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
// $Id: fluxbox.cc,v 1.193 2003/09/14 12:03:40 fluxgen Exp $
|
||||
// $Id: fluxbox.cc,v 1.194 2003/10/05 02:31:23 rathnor Exp $
|
||||
|
||||
#include "fluxbox.hh"
|
||||
|
||||
|
@ -403,12 +403,11 @@ Fluxbox::Fluxbox(int argc, char **argv, const char *dpy_name, const char *rcfile
|
|||
"session.titlebar.right", "Session.Titlebar.Right"),
|
||||
m_rc_cache_life(m_resourcemanager, 5, "session.cacheLife", "Session.CacheLife"),
|
||||
m_rc_cache_max(m_resourcemanager, 200, "session.cacheMax", "Session.CacheMax"),
|
||||
m_focused_window(0), m_masked_window(0),
|
||||
m_focused_window(0),
|
||||
m_mousescreen(0),
|
||||
m_keyscreen(0),
|
||||
m_watching_screen(0), m_watch_keyrelease(0),
|
||||
m_last_time(0),
|
||||
m_masked(0),
|
||||
m_rc_file(rcfilename ? rcfilename : ""),
|
||||
m_argv(argv), m_argc(argc),
|
||||
m_starting(true),
|
||||
|
@ -416,7 +415,9 @@ Fluxbox::Fluxbox(int argc, char **argv, const char *dpy_name, const char *rcfile
|
|||
m_server_grabs(0),
|
||||
m_randr_event_type(0),
|
||||
m_RC_PATH("fluxbox"),
|
||||
m_RC_INIT_FILE("init") {
|
||||
m_RC_INIT_FILE("init"),
|
||||
m_focus_revert_screen(0)
|
||||
{
|
||||
|
||||
|
||||
if (s_singleton != 0)
|
||||
|
@ -610,6 +611,10 @@ void Fluxbox::eventLoop() {
|
|||
} else {
|
||||
last_bad_window = None;
|
||||
handleEvent(&e);
|
||||
if (m_focus_revert_screen != 0) {
|
||||
revertFocus(*m_focus_revert_screen, false);
|
||||
m_focus_revert_screen = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
FbTk::Timer::updateTimers(ConnectionNumber(display())); //handle all timers
|
||||
|
@ -700,17 +705,52 @@ void Fluxbox::handleEvent(XEvent * const e) {
|
|||
m_last_event = *e;
|
||||
|
||||
// it is possible (e.g. during moving) for a window
|
||||
// to mask all events to go to it
|
||||
if ((m_masked == e->xany.window) && m_masked_window) {
|
||||
if (e->type == MotionNotify) {
|
||||
m_last_time = e->xmotion.time;
|
||||
m_masked_window->motionNotifyEvent(e->xmotion);
|
||||
return;
|
||||
} else if (e->type == ButtonRelease) {
|
||||
e->xbutton.window = m_masked_window->fbWindow().window();
|
||||
// to mask certain events to go somewhere (e.g. to that window)
|
||||
if (!m_redirect_events.empty()) {
|
||||
|
||||
bool drop_event = false;
|
||||
RedirectEvents::iterator it = m_redirect_events.begin();
|
||||
RedirectEvents::iterator it_end = m_redirect_events.end();
|
||||
RedirectEvent *re = 0;
|
||||
bool matched = false;
|
||||
Window orig_win = e->xany.window;
|
||||
|
||||
// look through all registered redirects
|
||||
while (it != it_end) {
|
||||
matched = false;
|
||||
re = *it;
|
||||
// do we affect this event?
|
||||
if (e->type == re->catch_type &&
|
||||
(re->catch_win == None ||
|
||||
re->catch_win == orig_win)) {
|
||||
matched = true;
|
||||
// redirect?
|
||||
if (re->redirect_win != None) {
|
||||
e->xany.window = re->redirect_win;
|
||||
} else {
|
||||
drop_event = true;
|
||||
}
|
||||
}
|
||||
|
||||
// does this event stop this redirect?
|
||||
if (e->type == re->stop_type &&
|
||||
((re->stop_win == None && matched) ||
|
||||
re->stop_win == orig_win)) {
|
||||
RedirectEvents::iterator next_it = it;
|
||||
++next_it;
|
||||
delete (*it);
|
||||
m_redirect_events.erase(it);
|
||||
it = next_it;
|
||||
} else
|
||||
++it;
|
||||
}
|
||||
|
||||
// if one of the redirects says to drop it, we do
|
||||
if (drop_event)
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// try FbTk::EventHandler first
|
||||
FbTk::EventManager::instance()->handleEvent(*e);
|
||||
|
||||
|
@ -1905,7 +1945,6 @@ void Fluxbox::setFocusedWindow(WinClient *client) {
|
|||
return;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
cerr<<"-----------------"<<endl;
|
||||
cerr<<"Setting Focused window = "<<client<<endl;
|
||||
cerr<<"Current Focused window = "<<m_focused_window<<endl;
|
||||
cerr<<"------------------"<<endl;
|
||||
|
@ -1978,16 +2017,38 @@ void Fluxbox::setFocusedWindow(WinClient *client) {
|
|||
* last_focused is set to something if we want to make use of the
|
||||
* previously focused window (it must NOT be set focused now, it
|
||||
* is probably dying).
|
||||
*
|
||||
* ignore_event means that it ignores the given event until
|
||||
* it gets a focusIn
|
||||
*/
|
||||
void Fluxbox::revertFocus(BScreen &screen) {
|
||||
void Fluxbox::revertFocus(BScreen &screen, bool wait_for_end) {
|
||||
// Relevant resources:
|
||||
// resource.focus_last = whether we focus last focused when changing workspace
|
||||
// Fluxbox::FocusModel = sloppy, click, whatever
|
||||
WinClient *next_focus = screen.getLastFocusedWindow(screen.currentWorkspaceID());
|
||||
if (wait_for_end) {
|
||||
if (m_focus_revert_screen == 0) {
|
||||
m_focus_revert_screen = &screen;
|
||||
return;
|
||||
} else if (m_focus_revert_screen == &screen)
|
||||
return;
|
||||
else
|
||||
cerr<<"Unexpected screen in revertFocus()"<<endl;
|
||||
}
|
||||
|
||||
WinClient *next_focus = 0;
|
||||
long ignore_event = 0;
|
||||
if (screen.doFocusLast()) {
|
||||
next_focus = screen.getLastFocusedWindow(screen.currentWorkspaceID());
|
||||
|
||||
// when doFocusLast is set, we don't do exact sloppy focus - we
|
||||
// go to the last focused window, rather than the pointer window
|
||||
// i.e. we ignore any EnterNotify events until the focus sending arrives
|
||||
ignore_event = EnterNotify;
|
||||
}
|
||||
|
||||
// if setting focus fails, or isn't possible, fallback correctly
|
||||
if (!(next_focus && next_focus->fbwindow() &&
|
||||
next_focus->fbwindow()->setCurrentClient(*next_focus, true))) {
|
||||
next_focus->fbwindow()->setCurrentClient(*next_focus, true, ignore_event))) {
|
||||
setFocusedWindow(0); // so we don't get dangling m_focused_window pointer
|
||||
switch (screen.getFocusModel()) {
|
||||
case SLOPPYFOCUS:
|
||||
|
@ -2017,3 +2078,41 @@ void Fluxbox::watchKeyRelease(BScreen &screen, unsigned int mods) {
|
|||
screen.rootWindow().window(), True,
|
||||
GrabModeAsync, GrabModeAsync, CurrentTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows people to create special event exclusions/redirects
|
||||
* useful for getting around X followup events, or for
|
||||
* effectively grabbing things
|
||||
* The ignore is automatically removed when it finds the wakeup_win
|
||||
* with an event matching the wakeup_mask
|
||||
* ignore None means all windows
|
||||
*/
|
||||
void Fluxbox::addRedirectEvent(BScreen *screen,
|
||||
long catch_type, Window catch_win,
|
||||
long stop_type, Window stop_win,
|
||||
Window redirect_win) {
|
||||
RedirectEvent * re = new RedirectEvent();
|
||||
re->screen = screen;
|
||||
re->catch_type = catch_type;
|
||||
re->catch_win = catch_win;
|
||||
re->stop_type = stop_type;
|
||||
re->stop_win = stop_win;
|
||||
re->redirect_win = redirect_win;
|
||||
|
||||
m_redirect_events.push_back(re);
|
||||
}
|
||||
|
||||
// So that an object may remove the ignore on its own
|
||||
void Fluxbox::removeRedirectEvent(long stop_type, Window stop_win) {
|
||||
RedirectEvents::iterator it = m_redirect_events.begin();
|
||||
RedirectEvents::iterator it_end = m_redirect_events.end();
|
||||
RedirectEvent *re = 0;
|
||||
for (; it != it_end; ++it) {
|
||||
re = *it;
|
||||
if (re->stop_type == re->stop_type && re->stop_win == stop_win) {
|
||||
m_redirect_events.erase(it);
|
||||
delete re;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
// $Id: fluxbox.hh,v 1.72 2003/09/10 09:51:58 fluxgen Exp $
|
||||
// $Id: fluxbox.hh,v 1.73 2003/10/05 02:31:23 rathnor Exp $
|
||||
|
||||
#ifndef FLUXBOX_HH
|
||||
#define FLUXBOX_HH
|
||||
|
@ -148,13 +148,11 @@ public:
|
|||
inline unsigned int getCacheLife() const { return *m_rc_cache_life * 60000; }
|
||||
inline unsigned int getCacheMax() const { return *m_rc_cache_max; }
|
||||
|
||||
inline void maskWindowEvents(Window w, FluxboxWindow *bw)
|
||||
{ m_masked = w; m_masked_window = bw; }
|
||||
|
||||
void watchKeyRelease(BScreen &screen, unsigned int mods);
|
||||
|
||||
void setFocusedWindow(WinClient *w);
|
||||
void revertFocus(BScreen &screen);
|
||||
// focus revert gets delayed until the end of the event handle
|
||||
void revertFocus(BScreen &screen, bool wait_for_end = true);
|
||||
void shutdown();
|
||||
void load_rc(BScreen &scr);
|
||||
void loadRootCommand(BScreen &scr);
|
||||
|
@ -204,6 +202,21 @@ public:
|
|||
// screen we are watching for modifier changes
|
||||
BScreen *watchingScreen() { return m_watching_screen; }
|
||||
const XEvent &lastEvent() const { return m_last_event; }
|
||||
|
||||
/**
|
||||
* Allows people to create special event exclusions/redirects
|
||||
* useful for getting around X followup events, or for
|
||||
* effectively grabbing things
|
||||
* The ignore is automatically removed when it finds the stop_win
|
||||
* with an event matching the stop_type
|
||||
* ignore None means all windows
|
||||
*/
|
||||
void addRedirectEvent(BScreen *screen, long catch_type, Window catch_win,
|
||||
long stop_type, Window stop_win, Window redirect_win);
|
||||
|
||||
// So that an object may remove the ignore on its own
|
||||
void removeRedirectEvent(long stop_type, Window stop_win);
|
||||
|
||||
private:
|
||||
|
||||
typedef struct MenuTimestamp {
|
||||
|
@ -264,9 +277,20 @@ private:
|
|||
ScreenList m_screen_list;
|
||||
|
||||
WinClient *m_focused_window;
|
||||
FluxboxWindow *m_masked_window;
|
||||
FbTk::Timer m_timer;
|
||||
|
||||
typedef struct RedirectEvent {
|
||||
BScreen *screen;
|
||||
long catch_type;
|
||||
Window catch_win;
|
||||
long stop_type;
|
||||
Window stop_win;
|
||||
Window redirect_win;
|
||||
} RedirectEvent;
|
||||
|
||||
typedef std::list<RedirectEvent *> RedirectEvents;
|
||||
|
||||
RedirectEvents m_redirect_events;
|
||||
BScreen *m_mousescreen, *m_keyscreen;
|
||||
BScreen *m_watching_screen;
|
||||
unsigned int m_watch_keyrelease;
|
||||
|
@ -275,7 +299,6 @@ private:
|
|||
|
||||
bool m_reconfigure_wait, m_reread_menu_wait;
|
||||
Time m_last_time;
|
||||
Window m_masked;
|
||||
std::string m_rc_file; ///< resource filename
|
||||
char **m_argv;
|
||||
int m_argc;
|
||||
|
@ -296,6 +319,9 @@ private:
|
|||
const char *m_RC_PATH;
|
||||
const char *m_RC_INIT_FILE;
|
||||
Atom m_kwm1_dockwindow, m_kwm2_dockwindow;
|
||||
|
||||
// each event can only affect one screen (right?)
|
||||
BScreen *m_focus_revert_screen;
|
||||
};
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue