From fa4328d8620959dce8a53b40c743fba691cfe471 Mon Sep 17 00:00:00 2001 From: rathnor Date: Sun, 5 Oct 2003 02:31:23 +0000 Subject: make doFocusLast work for sloppy focus as well --- ChangeLog | 5 +++ src/Screen.cc | 3 +- src/Window.cc | 31 +++++++++++--- src/Window.hh | 6 +-- src/fluxbox.cc | 131 ++++++++++++++++++++++++++++++++++++++++++++++++++------- src/fluxbox.hh | 40 +++++++++++++++--- 6 files changed, 182 insertions(+), 34 deletions(-) diff --git a/ChangeLog b/ChangeLog index 53be5ff..430f137 100644 --- a/ChangeLog +++ b/ChangeLog @@ -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 diff --git a/src/Screen.cc b/src/Screen.cc index 487f0c0..3795455 100644 --- a/src/Screen.cc +++ b/src/Screen.cc @@ -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) diff --git a/src/Window.cc b/src/Window.cc index 47fe00c..e104ae6 100644 --- a/src/Window.cc +++ b/src/Window.cc @@ -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(), diff --git a/src/Window.hh b/src/Window.hh index 9d94166..8831522 100644 --- a/src/Window.hh +++ b/src/Window.hh @@ -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 diff --git a/src/fluxbox.cc b/src/fluxbox.cc index bd02cee..1045200 100644 --- a/src/fluxbox.cc +++ b/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<<"-----------------"<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; + } + } +} diff --git a/src/fluxbox.hh b/src/fluxbox.hh index 6459385..5d3f505 100644 --- a/src/fluxbox.hh +++ b/src/fluxbox.hh @@ -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 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; }; -- cgit v0.11.2