From 53fff0d24b996f01d7426e44420c158500a4d311 Mon Sep 17 00:00:00 2001 From: markt Date: Wed, 21 Mar 2007 22:10:22 +0000 Subject: added TypeAheadFocus command --- ChangeLog | 7 +++++++ src/FbCommandFactory.cc | 3 +++ src/Screen.cc | 53 ++++++++++++++++++++++++++++++++++++++++++++++--- src/Screen.hh | 6 +++++- src/WinClient.hh | 5 ++++- src/WorkspaceCmd.cc | 14 +++++++++++++ src/WorkspaceCmd.hh | 8 ++++++++ 7 files changed, 91 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index 96126ba..22e74d5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,12 @@ (Format: Year/Month/Day) Changes for 1.0rc3: +*07/03/21: + * Added new command TypeAheadFocus (Mark) + - syntax is the same as for NextWindow; when you run the command, you can + start typing the title of the window, and it will gain focus; pressing + tab will cycle through all matching entries using the options specified; + when you've found the window you want, just press return or escape + WinClient.hh Screen.cc/hh FbCommandFactory.cc WorkspaceCmd.cc/hh *07/03/20: * Updated doc/asciidoc/fluxbox.txt (Mathias) *07/03/19: diff --git a/src/FbCommandFactory.cc b/src/FbCommandFactory.cc index c02365a..bd20c39 100644 --- a/src/FbCommandFactory.cc +++ b/src/FbCommandFactory.cc @@ -145,6 +145,7 @@ FbCommandFactory::FbCommandFactory() { "taketoprevworkspace", "togglecmd", "toggledecor", + "typeaheadfocus", "windowmenu", "workspace", /* NOTE: The following are DEPRECATED and subject to removal */ @@ -419,6 +420,8 @@ FbTk::Command *FbCommandFactory::stringToCommand(const std::string &command, return new NextWindowCmd(atoi(arguments.c_str())); else if (command == "prevwindow") return new PrevWindowCmd(atoi(arguments.c_str())); + else if (command == "typeaheadfocus") + return new TypeAheadFocusCmd(atoi(arguments.c_str())); else if (command == "focusup") return new DirFocusCmd(FocusControl::FOCUSUP); else if (command == "focusdown") diff --git a/src/Screen.cc b/src/Screen.cc index 987bbd0..4bcc988 100644 --- a/src/Screen.cc +++ b/src/Screen.cc @@ -365,7 +365,7 @@ BScreen::BScreen(FbTk::ResourceManager &rm, m_altname(altscreenname), m_focus_control(new FocusControl(*this)), m_placement_strategy(new ScreenPlacement(*this)), - m_cycling(false), + m_cycling(false), m_typing_ahead(false), m_cycle_opts(0), m_xinerama_headinfo(0), m_restart(false), m_shutdown(false) { @@ -788,7 +788,43 @@ void BScreen::update(FbTk::Subject *subj) { } void BScreen::keyPressEvent(XKeyEvent &ke) { - Fluxbox::instance()->keys()->doAction(ke.type, ke.state, ke.keycode); + if (!m_typing_ahead) { + Fluxbox::instance()->keys()->doAction(ke.type, ke.state, ke.keycode); + return; + } + + KeySym ks; + char keychar[1]; + XLookupString(&ke, keychar, 1, &ks, 0); + // a modifier key by itself doesn't do anything + if (IsModifierKey(ks)) + return; + + switch (ks) { + case XK_Escape: + case XK_KP_Enter: + case XK_Return: + m_type_ahead.reset(); + FbTk::EventManager::instance()->ungrabKeyboard(); + break; + case XK_BackSpace: + m_type_ahead.putBackSpace(); + m_matches = m_type_ahead.matched(); + break; + case XK_Tab: + case XK_ISO_Left_Tab: + m_type_ahead.seek(); + focusControl().cycleFocus(&m_matches, m_cycle_opts, (bool)(ke.state & ShiftMask)); + break; + default: + m_matches = m_type_ahead.putCharacter(keychar[0]); + // if focused win doesn't match new search string, find the next one + if (!m_matches.empty() && + std::find(m_matches.begin(), m_matches.end(), + FocusControl::focusedWindow()) == m_matches.end()) + focusControl().cycleFocus(&m_matches, m_cycle_opts); + break; + } } void BScreen::keyReleaseEvent(XKeyEvent &ke) { @@ -812,9 +848,20 @@ void BScreen::buttonPressEvent(XButtonEvent &be) { void BScreen::notifyUngrabKeyboard() { m_cycling = false; + m_typing_ahead = false; + m_type_ahead.reset(); focusControl().stopCyclingFocus(); } +void BScreen::startTypeAheadFocus(std::list &winlist, int opts) { + m_type_ahead.init(winlist); + FbTk::EventManager *evm = FbTk::EventManager::instance(); + if (!m_typing_ahead && !m_cycling) + evm->grabKeyboard(*this, rootWindow().window()); + m_cycle_opts = opts; + m_typing_ahead = true; +} + void BScreen::cycleFocus(int options, bool reverse) { // get modifiers from event that causes this for focus order cycling XEvent ev = Fluxbox::instance()->lastEvent(); @@ -824,7 +871,7 @@ void BScreen::cycleFocus(int options, bool reverse) { else if (ev.type == ButtonPress) mods = FbTk::KeyUtil::instance().cleanMods(ev.xbutton.state); - if (!m_cycling && mods) { + if (!m_cycling && !m_typing_ahead && mods) { m_cycling = true; FbTk::EventManager::instance()->grabKeyboard(*this, rootWindow().window()); } diff --git a/src/Screen.hh b/src/Screen.hh index bf03ac6..c2e493b 100644 --- a/src/Screen.hh +++ b/src/Screen.hh @@ -217,6 +217,7 @@ public: void buttonPressEvent(XButtonEvent &be); void notifyUngrabKeyboard(); + void startTypeAheadFocus(std::list &winlist, int opts); void cycleFocus(int opts, bool reverse); FbTk::Menu *createMenu(const std::string &label); @@ -485,7 +486,10 @@ private: typedef std::map Groupables; Groupables m_expecting_groups; - bool m_cycling; + bool m_cycling, m_typing_ahead; + int m_cycle_opts; + FbTk::TypeAhead, WinClient *> m_type_ahead; + std::list m_matches; // Xinerama related private data bool m_xinerama_avail; diff --git a/src/WinClient.hh b/src/WinClient.hh index 0082bb0..7d2c734 100644 --- a/src/WinClient.hh +++ b/src/WinClient.hh @@ -29,6 +29,7 @@ #include "Subject.hh" #include "FbWindow.hh" #include "FbTk/FbString.hh" +#include "FbTk/ITypeAheadable.hh" #include @@ -36,7 +37,8 @@ class BScreen; class Strut; /// Holds client window info -class WinClient: public Focusable, public FbTk::FbWindow { +class WinClient: public Focusable, public FbTk::ITypeAheadable, + public FbTk::FbWindow { public: typedef std::list TransientList; // this structure only contains 3 elements... the Motif 2.0 structure contains @@ -143,6 +145,7 @@ public: inline unsigned int maxWidth() const { return max_width; } inline unsigned int maxHeight() const { return max_height; } + const std::string &iTypeString() const { return m_title; } static const int PropBlackboxHintsElements = 5; static const int PropMwmHintsElements = 3; diff --git a/src/WorkspaceCmd.cc b/src/WorkspaceCmd.cc index 0cbf5b9..f92418f 100644 --- a/src/WorkspaceCmd.cc +++ b/src/WorkspaceCmd.cc @@ -53,6 +53,20 @@ void PrevWindowCmd::execute() { screen->cycleFocus(m_option, true); } +void TypeAheadFocusCmd::execute() { + Fluxbox *fb = Fluxbox::instance(); + BScreen *screen = fb->keyScreen(); + if (screen != 0) { + int options = m_option; + FocusControl::FocusedWindows *win_list = + (options & FocusControl::CYCLELINEAR) ? + &screen->focusControl().creationOrderList() : + &screen->focusControl().focusedOrderList(); + + screen->startTypeAheadFocus(*win_list, m_option); + } +} + void DirFocusCmd::execute() { BScreen *screen = Fluxbox::instance()->keyScreen(); if (screen == 0) diff --git a/src/WorkspaceCmd.hh b/src/WorkspaceCmd.hh index 7d8d9e6..d0a6713 100644 --- a/src/WorkspaceCmd.hh +++ b/src/WorkspaceCmd.hh @@ -45,6 +45,14 @@ private: const int m_option; }; +class TypeAheadFocusCmd: public FbTk::Command { +public: + explicit TypeAheadFocusCmd(int option): m_option(option) { } + void execute(); +private: + const int m_option; +}; + class DirFocusCmd: public FbTk::Command { public: explicit DirFocusCmd(const FocusControl::FocusDir dir): m_dir(dir) { } -- cgit v0.11.2