aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Tamin <richard.tamin@gmail.com>2020-08-23 04:01:43 (GMT)
committerMathias Gumz <mgumz@users.noreply.github.com>2022-04-18 19:50:06 (GMT)
commit174e62ff66fee78d83231b1f0f9ea083370ae55d (patch)
tree59168c7cc06e7a0d0ef0a3d55976db2fb733092c
parent8e32f098bd94cb14ae80c3621c3db74fbdfa7bb6 (diff)
downloadfluxbox-174e62ff66fee78d83231b1f0f9ea083370ae55d.zip
fluxbox-174e62ff66fee78d83231b1f0f9ea083370ae55d.tar.bz2
Initial implementation of shortcut to windows
[PURPOSE] In editors such as vi and emacs, a user can mark a line in a file with a shortcut key and afterwards jump back to that line using the shortcut. The idea is extended to opened windows. A user can assign a keyboard shortcut to an opened window. Afterwards, the shortcut can be used to switch focus back to the marked window. Such shortcuts save the user from pressing "alt+tab" multiple times to cycle through windows until the desired one is found. [EXAMPLE USAGE] The following binding is added to file "~/.fluxbox/keys": Mod1 m ARG :MarkWindow Mod1 g ARG :GotoMarkedWindow User enters "alt+m x" to mark the currently focused window with shortcut key 'x' User enters "alt+g x" to switch focus to the marked window [IMPLEMENTATION SUMMARY] - Two new commands were added :MarkWindow and :GotoMarkedWindow - Keys.cc was modified: - addBinding() method supports parsing an argument placeholder where the user can pass in a shortcut key - doAction() method forwards the shortcut key to the command to execute - Class Keys::t_key was modified to recognize a placeholder key - New class ShortcutManager was added to maintain mapping of shortcut keys to marked windows
-rw-r--r--src/Keys.cc53
-rw-r--r--src/Makemodule.am2
-rw-r--r--src/ShortcutManager.cc45
-rw-r--r--src/ShortcutManager.hh32
-rw-r--r--src/Window.cc1
-rw-r--r--src/WorkspaceCmd.cc37
-rw-r--r--src/WorkspaceCmd.hh10
-rw-r--r--src/fluxbox.cc3
-rw-r--r--src/fluxbox.hh3
9 files changed, 178 insertions, 8 deletions
diff --git a/src/Keys.cc b/src/Keys.cc
index 774cd05..8659137 100644
--- a/src/Keys.cc
+++ b/src/Keys.cc
@@ -140,21 +140,35 @@ public:
140 // constructor / destructor 140 // constructor / destructor
141 t_key(int type = 0, unsigned int mod = 0, unsigned int key = 0, 141 t_key(int type = 0, unsigned int mod = 0, unsigned int key = 0,
142 const std::string &key_str = std::string(), int context = 0, 142 const std::string &key_str = std::string(), int context = 0,
143 bool isdouble = false); 143 bool isdouble = false, bool isPlaceHolderArg = false);
144 144
145 RefKey find(int type_, unsigned int mod_, unsigned int key_, 145 RefKey find(int type_, unsigned int mod_, unsigned int key_,
146 int context_, bool isdouble_) { 146 int context_, bool isdouble_) {
147 // t_key ctor sets context_ of 0 to GLOBAL, so we must here too 147 // t_key ctor sets context_ of 0 to GLOBAL, so we must here too
148 context_ = context_ ? context_ : GLOBAL; 148 context_ = context_ ? context_ : GLOBAL;
149 keylist_t::iterator itPlaceHolder = keylist.end();
149 keylist_t::iterator it = keylist.begin(), it_end = keylist.end(); 150 keylist_t::iterator it = keylist.begin(), it_end = keylist.end();
150 for (; it != it_end; ++it) { 151 for (; it != it_end; ++it) {
152
153 if ((*it)->isPlaceHolderArg)
154 itPlaceHolder = it;
155
151 if (*it && (*it)->type == type_ && (*it)->key == key_ && 156 if (*it && (*it)->type == type_ && (*it)->key == key_ &&
152 ((*it)->context & context_) > 0 && 157 ((*it)->context & context_) > 0 &&
153 isdouble_ == (*it)->isdouble && (*it)->mod == 158 isdouble_ == (*it)->isdouble && (*it)->mod ==
154 FbTk::KeyUtil::instance().isolateModifierMask(mod_)) 159 FbTk::KeyUtil::instance().isolateModifierMask(mod_))
155 return *it; 160 return *it;
156 } 161 }
157 return RefKey(); 162
163 // Could not find any matching key. If a placeholder was located then user
164 // is trying to pass in a value for the placeholder.
165 if (itPlaceHolder == keylist.end()) {
166 return RefKey();
167 }
168 else {
169 (*itPlaceHolder)->lastPlaceHolderArgValue = key_;
170 return *itPlaceHolder;
171 }
158 } 172 }
159 173
160 // member variables 174 // member variables
@@ -165,6 +179,8 @@ public:
165 std::string key_str; // key-symbol, needed for regrab() 179 std::string key_str; // key-symbol, needed for regrab()
166 int context; // ON_TITLEBAR, etc.: bitwise-or of all desired contexts 180 int context; // ON_TITLEBAR, etc.: bitwise-or of all desired contexts
167 bool isdouble; 181 bool isdouble;
182 bool isPlaceHolderArg;
183 unsigned int lastPlaceHolderArgValue;
168 FbTk::RefCount<FbTk::Command<void> > m_command; 184 FbTk::RefCount<FbTk::Command<void> > m_command;
169 185
170 keylist_t keylist; 186 keylist_t keylist;
@@ -172,13 +188,15 @@ public:
172 188
173Keys::t_key::t_key(int type_, unsigned int mod_, unsigned int key_, 189Keys::t_key::t_key(int type_, unsigned int mod_, unsigned int key_,
174 const std::string &key_str_, 190 const std::string &key_str_,
175 int context_, bool isdouble_) : 191 int context_, bool isdouble_, bool isPlaceHolderArg_) :
176 type(type_), 192 type(type_),
177 mod(mod_), 193 mod(mod_),
178 key(key_), 194 key(key_),
179 key_str(key_str_), 195 key_str(key_str_),
180 context(context_), 196 context(context_),
181 isdouble(isdouble_), 197 isdouble(isdouble_),
198 isPlaceHolderArg(isPlaceHolderArg_),
199 lastPlaceHolderArgValue(0),
182 m_command(0) { 200 m_command(0) {
183 201
184 context = context_ ? context_ : GLOBAL; 202 context = context_ ? context_ : GLOBAL;
@@ -385,6 +403,8 @@ bool Keys::addBinding(const string &linebuffer) {
385 403
386 std::string arg = FbTk::StringUtil::toLower(val[argc]); 404 std::string arg = FbTk::StringUtil::toLower(val[argc]);
387 405
406 bool isPlaceHolderArg = false;
407
388 if (arg[0] != ':') { // parse key(s) 408 if (arg[0] != ':') { // parse key(s)
389 409
390 std::string key_str; 410 std::string key_str;
@@ -461,7 +481,11 @@ bool Keys::addBinding(const string &linebuffer) {
461 type = ButtonRelease; 481 type = ButtonRelease;
462 } else if (extractKeyFromString(arg, "move", key)) { 482 } else if (extractKeyFromString(arg, "move", key)) {
463 type = MotionNotify; 483 type = MotionNotify;
464 484 } else if (arg == "arg") {
485 isPlaceHolderArg = true;
486 key = 0;
487 mod = 0;
488 type = 0;
465 } else if ((key = FbTk::KeyUtil::getKey(val[argc].c_str()))) { // convert from string symbol 489 } else if ((key = FbTk::KeyUtil::getKey(val[argc].c_str()))) { // convert from string symbol
466 type = KeyPress; 490 type = KeyPress;
467 key_str = val[argc]; 491 key_str = val[argc];
@@ -476,25 +500,31 @@ bool Keys::addBinding(const string &linebuffer) {
476 type = KeyPress; 500 type = KeyPress;
477 } 501 }
478 502
479 if (key == 0 && (type == KeyPress || type == ButtonPress || type == ButtonRelease)) 503 if (key == 0 && (type == KeyPress || type == ButtonPress || type == ButtonRelease) && !isPlaceHolderArg)
480 return false; 504 return false;
481 505
482 if (type != ButtonPress) 506 if (type != ButtonPress)
483 isdouble = false; 507 isdouble = false;
484 508
509 // Placeholder argument cannot be the first key
510 if (!first_new_key && isPlaceHolderArg) {
511 return false;
512 }
513
485 if (!first_new_key) { 514 if (!first_new_key) {
486 first_new_keylist = current_key; 515 first_new_keylist = current_key;
487 current_key = current_key->find(type, mod, key, context, 516 current_key = current_key->find(type, mod, key, context,
488 isdouble); 517 isdouble);
489 if (!current_key) { 518 if (!current_key) {
490 first_new_key.reset( new t_key(type, mod, key, key_str, context, 519 first_new_key.reset( new t_key(type, mod, key, key_str, context,
491 isdouble) ); 520 isdouble, isPlaceHolderArg) );
492 current_key = first_new_key; 521 current_key = first_new_key;
493 } else if (current_key->m_command) // already being used 522 } else if (current_key->m_command) // already being used
494 return false; 523 return false;
495 } else { 524 } else {
525
496 RefKey temp_key( new t_key(type, mod, key, key_str, context, 526 RefKey temp_key( new t_key(type, mod, key, key_str, context,
497 isdouble) ); 527 isdouble, isPlaceHolderArg) );
498 current_key->keylist.push_back(temp_key); 528 current_key->keylist.push_back(temp_key);
499 current_key = temp_key; 529 current_key = temp_key;
500 } 530 }
@@ -608,6 +638,15 @@ bool Keys::doAction(int type, unsigned int mods, unsigned int key,
608 638
609 WinClient *old = WindowCmd<void>::client(); 639 WinClient *old = WindowCmd<void>::client();
610 WindowCmd<void>::setClient(current); 640 WindowCmd<void>::setClient(current);
641
642 // The key is a placeholder, store the value of the entered key in the shortcut manager
643 // before executing the action
644 if (temp_key->isPlaceHolderArg) {
645 fbdbg << "Encountered placeholder key. Assign value[" << temp_key->lastPlaceHolderArgValue
646 << "] to the placeholder" << std::endl;
647 Fluxbox::instance()->shortcutManager().setLastPlaceHolderKey(temp_key->lastPlaceHolderArgValue);
648 }
649
611 temp_key->m_command->execute(); 650 temp_key->m_command->execute();
612 WindowCmd<void>::setClient(old); 651 WindowCmd<void>::setClient(old);
613 652
diff --git a/src/Makemodule.am b/src/Makemodule.am
index 0156c90..5be5692 100644
--- a/src/Makemodule.am
+++ b/src/Makemodule.am
@@ -233,6 +233,8 @@ fluxbox_SOURCES = \
233 src/ScreenResource.hh \ 233 src/ScreenResource.hh \
234 src/SendToMenu.cc \ 234 src/SendToMenu.cc \
235 src/SendToMenu.hh \ 235 src/SendToMenu.hh \
236 src/ShortcutManager.cc \
237 src/ShortcutManager.hh \
236 src/Strut.hh \ 238 src/Strut.hh \
237 src/StyleMenuItem.cc \ 239 src/StyleMenuItem.cc \
238 src/StyleMenuItem.hh \ 240 src/StyleMenuItem.hh \
diff --git a/src/ShortcutManager.cc b/src/ShortcutManager.cc
new file mode 100644
index 0000000..52e94af
--- /dev/null
+++ b/src/ShortcutManager.cc
@@ -0,0 +1,45 @@
1#include "ShortcutManager.hh"
2#include "Debug.hh"
3
4#include <iostream>
5
6ShortcutManager::ShortcutManager() : m_last_placeholder_key(0) { }
7
8void ShortcutManager::setLastPlaceHolderKey(unsigned int lastPlaceHolderKey_)
9{
10 m_last_placeholder_key = lastPlaceHolderKey_;
11}
12
13unsigned int ShortcutManager::getLastPlaceHolderKey()
14{
15 return m_last_placeholder_key;
16}
17
18void ShortcutManager::mapKeyToWindow(unsigned int key, FluxboxWindow* window)
19{
20 m_key_to_window_map.insert(std::make_pair(key, window));
21}
22
23void ShortcutManager::removeWindow(FluxboxWindow* window)
24{
25 KeyToWindowMap::const_iterator it;
26 for (it = m_key_to_window_map.begin(); it != m_key_to_window_map.end(); ++it) {
27 if (it->second == window){
28 fbdbg << "Remove mapping window[" << window
29 << "] key [" << it->first << "]" << std::endl;
30 m_key_to_window_map.erase(it);
31 return;
32 }
33 }
34}
35
36FluxboxWindow* ShortcutManager::getWindowForKey(unsigned int key)
37{
38 KeyToWindowMap::const_iterator it = m_key_to_window_map.find(key);
39 if (it != m_key_to_window_map.end()) {
40 return it->second;
41 }
42 else {
43 return nullptr;
44 }
45}
diff --git a/src/ShortcutManager.hh b/src/ShortcutManager.hh
new file mode 100644
index 0000000..792a66c
--- /dev/null
+++ b/src/ShortcutManager.hh
@@ -0,0 +1,32 @@
1#ifndef SHORTCUTMANAGER_HH
2#define SHORTCUTMANAGER_HH
3
4#include <map>
5
6class FluxboxWindow;
7
8class ShortcutManager {
9
10public:
11
12 ShortcutManager();
13
14 void setLastPlaceHolderKey(unsigned int lastPlaceHolderKey_);
15
16 unsigned int getLastPlaceHolderKey();
17
18 void mapKeyToWindow(unsigned int key, FluxboxWindow* window);
19
20 void removeWindow(FluxboxWindow* window);
21
22 FluxboxWindow* getWindowForKey(unsigned int key);
23
24private:
25
26 typedef std::map<unsigned int, FluxboxWindow*> KeyToWindowMap;
27
28 unsigned int m_last_placeholder_key;
29 KeyToWindowMap m_key_to_window_map;
30};
31
32#endif
diff --git a/src/Window.cc b/src/Window.cc
index d761016..342e488 100644
--- a/src/Window.cc
+++ b/src/Window.cc
@@ -353,6 +353,7 @@ FluxboxWindow::~FluxboxWindow() {
353 // no longer a valid window to do stuff with 353 // no longer a valid window to do stuff with
354 Fluxbox::instance()->removeWindowSearchGroup(frame().window().window()); 354 Fluxbox::instance()->removeWindowSearchGroup(frame().window().window());
355 Fluxbox::instance()->removeWindowSearchGroup(frame().tabcontainer().window()); 355 Fluxbox::instance()->removeWindowSearchGroup(frame().tabcontainer().window());
356 Fluxbox::instance()->shortcutManager().removeWindow(this);
356 357
357 Client2ButtonMap::iterator it = m_labelbuttons.begin(); 358 Client2ButtonMap::iterator it = m_labelbuttons.begin();
358 Client2ButtonMap::iterator it_end = m_labelbuttons.end(); 359 Client2ButtonMap::iterator it_end = m_labelbuttons.end();
diff --git a/src/WorkspaceCmd.cc b/src/WorkspaceCmd.cc
index 6d18b73..c2e4948 100644
--- a/src/WorkspaceCmd.cc
+++ b/src/WorkspaceCmd.cc
@@ -39,6 +39,8 @@
39#include "FbTk/stringstream.hh" 39#include "FbTk/stringstream.hh"
40#include "FbTk/StringUtil.hh" 40#include "FbTk/StringUtil.hh"
41 41
42#include "Debug.hh"
43
42#ifdef HAVE_CMATH 44#ifdef HAVE_CMATH
43 #include <cmath> 45 #include <cmath>
44#else 46#else
@@ -751,3 +753,38 @@ FbTk::Command<void> *RelabelButtonCmd::parse(const std::string &command,
751 753
752REGISTER_COMMAND_PARSER(relabelbutton, RelabelButtonCmd::parse, void); 754REGISTER_COMMAND_PARSER(relabelbutton, RelabelButtonCmd::parse, void);
753 755
756void MarkWindowCmd::execute() {
757 BScreen *screen = Fluxbox::instance()->keyScreen();
758 if (screen) {
759
760 FluxboxWindow* window = screen->focusControl().focusedFbWindow();
761 if (window) {
762 ShortcutManager &shortcutManager = Fluxbox::instance()->shortcutManager();
763 unsigned int key = shortcutManager.getLastPlaceHolderKey();
764 shortcutManager.mapKeyToWindow(key, window);
765 fbdbg << "Map window[" << window << "] to key[" << key << "]" << std::endl;
766 }
767 }
768}
769
770REGISTER_COMMAND(markwindow, MarkWindowCmd, void);
771
772void GotoMarkedWindowCmd::execute() {
773
774 ShortcutManager &shortcutManager = Fluxbox::instance()->shortcutManager();
775 unsigned int key = shortcutManager.getLastPlaceHolderKey();
776
777 FluxboxWindow *window = shortcutManager.getWindowForKey(key);
778 if (window) {
779
780 if (window->isIconic()) {
781 window->deiconify(false);
782 }
783 window->raiseAndFocus();
784
785 fbdbg << "Raise and focus window[" << window
786 << "] mapped to key[" << key << "]" << std::endl;
787 }
788}
789
790REGISTER_COMMAND(gotomarkedwindow, GotoMarkedWindowCmd, void);
diff --git a/src/WorkspaceCmd.hh b/src/WorkspaceCmd.hh
index 4f294fe..8993e60 100644
--- a/src/WorkspaceCmd.hh
+++ b/src/WorkspaceCmd.hh
@@ -236,4 +236,14 @@ private:
236 std::string m_button, m_label; 236 std::string m_button, m_label;
237}; 237};
238 238
239class MarkWindowCmd: public FbTk::Command<void> {
240public:
241 void execute();
242};
243
244class GotoMarkedWindowCmd: public FbTk::Command<void> {
245public:
246 void execute();
247};
248
239#endif // WORKSPACECMD_HH 249#endif // WORKSPACECMD_HH
diff --git a/src/fluxbox.cc b/src/fluxbox.cc
index 468ca33..a55bd29 100644
--- a/src/fluxbox.cc
+++ b/src/fluxbox.cc
@@ -272,7 +272,8 @@ Fluxbox::Fluxbox(int argc, char **argv,
272 m_masked_window(0), 272 m_masked_window(0),
273 m_argv(argv), m_argc(argc), 273 m_argv(argv), m_argc(argc),
274 m_showing_dialog(false), 274 m_showing_dialog(false),
275 m_server_grabs(0) { 275 m_server_grabs(0),
276 m_shortcut_manager(new ShortcutManager) {
276 277
277 _FB_USES_NLS; 278 _FB_USES_NLS;
278 279
diff --git a/src/fluxbox.hh b/src/fluxbox.hh
index 42739fb..d300102 100644
--- a/src/fluxbox.hh
+++ b/src/fluxbox.hh
@@ -32,6 +32,7 @@
32#include "FbTk/MenuSearch.hh" 32#include "FbTk/MenuSearch.hh"
33 33
34#include "AttentionNoticeHandler.hh" 34#include "AttentionNoticeHandler.hh"
35#include "ShortcutManager.hh"
35 36
36#include <X11/Xresource.h> 37#include <X11/Xresource.h>
37 38
@@ -185,6 +186,7 @@ public:
185 const XEvent &lastEvent() const { return m_last_event; } 186 const XEvent &lastEvent() const { return m_last_event; }
186 187
187 AttentionNoticeHandler &attentionHandler() { return m_attention_handler; } 188 AttentionNoticeHandler &attentionHandler() { return m_attention_handler; }
189 ShortcutManager &shortcutManager() { return *m_shortcut_manager; }
188 190
189private: 191private:
190 std::string getRcFilename(); 192 std::string getRcFilename();
@@ -306,6 +308,7 @@ private:
306 } m_state; 308 } m_state;
307 309
308 int m_server_grabs; 310 int m_server_grabs;
311 std::unique_ptr<ShortcutManager> m_shortcut_manager;
309}; 312};
310 313
311 314