all repos — fluxbox @ fa4328d8620959dce8a53b40c743fba691cfe471

custom fork of the fluxbox windowmanager

make doFocusLast work for sloppy focus as well
rathnor rathnor
commit

fa4328d8620959dce8a53b40c743fba691cfe471

parent

35fe2d5e128c1b13d34a5152945a1b8979401d6f

6 files changed, 182 insertions(+), 34 deletions(-)

jump to
M ChangeLogChangeLog

@@ -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
M src/Screen.ccsrc/Screen.cc

@@ -22,7 +22,7 @@ // 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: 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 @@ id == m_current_workspace->workspaceID())

return; XSync(FbTk::App::instance()->display(), true); + WinClient *focused_client = Fluxbox::instance()->getFocusedWindow(); FluxboxWindow *focused = 0; if (focused_client)
M src/Window.ccsrc/Window.cc

@@ -22,7 +22,7 @@ // 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: 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 @@ last_client = *it;

} } -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 @@

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 @@ // it doesn't guarantee that it has focus, but says that we have

// 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 @@

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 @@

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(),
M src/Window.hhsrc/Window.hh

@@ -22,7 +22,7 @@ // 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: 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 @@ void detachCurrentClient();

/// 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
M src/fluxbox.ccsrc/fluxbox.cc

@@ -22,7 +22,7 @@ // 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: 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 @@ TitlebarList(&s_titlebar_right[0], &s_titlebar_right[3]),

"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 @@ m_shutdown(false),

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 @@ #endif // DEBUG

} 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 @@ #endif // DEBUG

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 @@ * focus is meant to be, it'll make things right ;-)

* 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 @@ XGrabKeyboard(FbTk::App::instance()->display(),

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; + } + } +}
M src/fluxbox.hhsrc/fluxbox.hh

@@ -22,7 +22,7 @@ // 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: 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 @@

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 @@ BScreen *keyScreen() { return m_keyscreen; }

// 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 @@ typedef std::list<BScreen *> ScreenList;

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 @@ Atom m_fluxbox_pid;

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 @@ bool m_have_shape; ///< if shape is supported by server

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; };