aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog13
-rw-r--r--data/init.in1
-rw-r--r--data/keys6
-rw-r--r--src/FbCommandFactory.cc3
-rw-r--r--src/FbCommands.cc9
-rw-r--r--src/FbCommands.hh5
-rw-r--r--src/FbTk/KeyUtil.cc7
-rw-r--r--src/FbTk/KeyUtil.hh1
-rw-r--r--src/Keys.cc95
-rw-r--r--src/Keys.hh43
-rw-r--r--src/Screen.cc2
-rw-r--r--src/Screen.hh2
-rw-r--r--src/WorkspaceCmd.cc66
-rw-r--r--src/fluxbox.cc98
-rw-r--r--util/Makefile.am12
-rw-r--r--util/fluxbox-update_configs.cc197
16 files changed, 433 insertions, 127 deletions
diff --git a/ChangeLog b/ChangeLog
index 4a745e1..ddece80 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,18 @@
1 (Format: Year/Month/Day) 1 (Format: Year/Month/Day)
2Changes for 1.0rc3: 2Changes for 1.0rc3:
3*07/02/09:
4 * Introduced support for mouse buttons in the keys file (Mark)
5 - Mouse buttons are bound to new `keys' Mouse1, Mouse2, etc.
6 - Also a new modifier `OnDesktop' to specify actions that should take place
7 when you click on the desktop -- without this, mouse bindings are global
8 - Obviously, more modifiers are planned, so don't ask
9 - Introduced new command HideMenus
10 - Added a utility to the project that automatically updates configuration
11 files when we change the syntax -- your current mouse bindings on the
12 desktop will be added to your keys file automatically
13 FbCommands.cc/hh FbCommandFactory.cc Keys.cc/hh Screen.cc/hh fluxbox.cc
14 FbTk/KeyUtil.cc/hh WorkspaceCmd.cc data/init.in data/keys util/Makefile.am
15 Added util/fluxbox-update_configs.cc
3*07/02/06: 16*07/02/06:
4 * Wrong window was being raised when attaching an unfocused window (Mark) 17 * Wrong window was being raised when attaching an unfocused window (Mark)
5 Window.cc 18 Window.cc
diff --git a/data/init.in b/data/init.in
index 278ac80..76b4e08 100644
--- a/data/init.in
+++ b/data/init.in
@@ -33,3 +33,4 @@ session.colorsPerChannel: 4
33session.doubleClickInterval: 250 33session.doubleClickInterval: 250
34session.cacheMax: 200 34session.cacheMax: 200
35session.imageDither: True 35session.imageDither: True
36session.configVersion: 1
diff --git a/data/keys b/data/keys
index b78e2c3..d76b18f 100644
--- a/data/keys
+++ b/data/keys
@@ -1,3 +1,9 @@
1OnDesktop Mouse1 :HideMenus
2OnDesktop Mouse2 :WorkspaceMenu
3OnDesktop Mouse3 :RootMenu
4OnDesktop Mouse4 :NextWorkspace
5OnDesktop Mouse5 :PrevWorkspace
6
1Mod1 Tab :NextWindow 7Mod1 Tab :NextWindow
2Mod1 Shift Tab :PrevWindow 8Mod1 Shift Tab :PrevWindow
3Mod1 F1 :Workspace 1 9Mod1 F1 :Workspace 1
diff --git a/src/FbCommandFactory.cc b/src/FbCommandFactory.cc
index b82332a..2f05e5a 100644
--- a/src/FbCommandFactory.cc
+++ b/src/FbCommandFactory.cc
@@ -77,6 +77,7 @@ FbCommandFactory::FbCommandFactory() {
77 "focusleft", 77 "focusleft",
78 "focusright", 78 "focusright",
79 "fullscreen", 79 "fullscreen",
80 "hidemenus",
80 "iconify", 81 "iconify",
81 "keymode", 82 "keymode",
82 "killwindow", 83 "killwindow",
@@ -433,6 +434,8 @@ FbTk::Command *FbCommandFactory::stringToCommand(const std::string &command,
433 return new ArrangeWindowsCmd(); 434 return new ArrangeWindowsCmd();
434 else if (command == "showdesktop") 435 else if (command == "showdesktop")
435 return new ShowDesktopCmd(); 436 return new ShowDesktopCmd();
437 else if (command == "hidemenus")
438 return new HideMenuCmd();
436 else if (command == "rootmenu") 439 else if (command == "rootmenu")
437 return new ShowRootMenuCmd(); 440 return new ShowRootMenuCmd();
438 else if (command == "workspacemenu") 441 else if (command == "workspacemenu")
diff --git a/src/FbCommands.cc b/src/FbCommands.cc
index 5fbceab..692e12f 100644
--- a/src/FbCommands.cc
+++ b/src/FbCommands.cc
@@ -260,6 +260,15 @@ void KeyModeCmd::execute() {
260 Fluxbox::instance()->keys()->keyMode(m_keymode); 260 Fluxbox::instance()->keys()->keyMode(m_keymode);
261} 261}
262 262
263void HideMenuCmd::execute() {
264 BScreen *screen = Fluxbox::instance()->mouseScreen();
265 screen->hideMenus();
266 if (screen->rootMenu().isVisible())
267 screen->rootMenu().hide();
268 if (screen->workspaceMenu().isVisible())
269 screen->workspaceMenu().hide();
270}
271
263void ShowRootMenuCmd::execute() { 272void ShowRootMenuCmd::execute() {
264 BScreen *screen = Fluxbox::instance()->mouseScreen(); 273 BScreen *screen = Fluxbox::instance()->mouseScreen();
265 if (screen == 0) 274 if (screen == 0)
diff --git a/src/FbCommands.hh b/src/FbCommands.hh
index 8ac40fa..59200d2 100644
--- a/src/FbCommands.hh
+++ b/src/FbCommands.hh
@@ -113,6 +113,11 @@ private:
113 std::string m_end_args; 113 std::string m_end_args;
114}; 114};
115 115
116class HideMenuCmd: public FbTk::Command {
117public:
118 void execute();
119};
120
116class ShowRootMenuCmd: public FbTk::Command { 121class ShowRootMenuCmd: public FbTk::Command {
117public: 122public:
118 void execute(); 123 void execute();
diff --git a/src/FbTk/KeyUtil.cc b/src/FbTk/KeyUtil.cc
index 3f413a9..6985139 100644
--- a/src/FbTk/KeyUtil.cc
+++ b/src/FbTk/KeyUtil.cc
@@ -138,7 +138,7 @@ void KeyUtil::grabButton(unsigned int button, unsigned int mod, Window win,
138 for (int i = 0; i < 8; i++) { 138 for (int i = 0; i < 8; i++) {
139 XGrabButton(display, button, mod | (i & 1 ? capsmod : 0) | 139 XGrabButton(display, button, mod | (i & 1 ? capsmod : 0) |
140 (i & 2 ? nummod : 0) | (i & 4 ? scrollmod : 0), 140 (i & 2 ? nummod : 0) | (i & 4 ? scrollmod : 0),
141 win, True, event_mask, GrabModeAsync, GrabModeAsync, 141 win, False, event_mask, GrabModeAsync, GrabModeAsync,
142 None, cursor); 142 None, cursor);
143 } 143 }
144 144
@@ -180,6 +180,11 @@ void KeyUtil::ungrabKeys(Window win) {
180 XUngrabKey(display, AnyKey, AnyModifier, win); 180 XUngrabKey(display, AnyKey, AnyModifier, win);
181} 181}
182 182
183void KeyUtil::ungrabButtons(Window win) {
184 Display * display = App::instance()->display();
185 XUngrabButton(display, AnyButton, AnyModifier, win);
186}
187
183unsigned int KeyUtil::keycodeToModmask(unsigned int keycode) { 188unsigned int KeyUtil::keycodeToModmask(unsigned int keycode) {
184 XModifierKeymap *modmap = instance().m_modmap; 189 XModifierKeymap *modmap = instance().m_modmap;
185 190
diff --git a/src/FbTk/KeyUtil.hh b/src/FbTk/KeyUtil.hh
index eb2cdd5..4909c5a 100644
--- a/src/FbTk/KeyUtil.hh
+++ b/src/FbTk/KeyUtil.hh
@@ -62,6 +62,7 @@ public:
62 ungrabs all keys 62 ungrabs all keys
63 */ 63 */
64 static void ungrabKeys(Window win); 64 static void ungrabKeys(Window win);
65 static void ungrabButtons(Window win);
65 66
66 /** 67 /**
67 Strip out modifiers we want to ignore 68 Strip out modifiers we want to ignore
diff --git a/src/Keys.cc b/src/Keys.cc
index e7b7acd..dbcff67 100644
--- a/src/Keys.cc
+++ b/src/Keys.cc
@@ -114,6 +114,7 @@ Keys::Keys():
114 114
115Keys::~Keys() { 115Keys::~Keys() {
116 ungrabKeys(); 116 ungrabKeys();
117 ungrabButtons();
117 deleteTree(); 118 deleteTree();
118} 119}
119 120
@@ -140,6 +141,23 @@ void Keys::ungrabKeys() {
140 FbTk::KeyUtil::ungrabKeys(*it); 141 FbTk::KeyUtil::ungrabKeys(*it);
141} 142}
142 143
144void Keys::grabButton(unsigned int button, unsigned int mod) {
145 std::list<Window>::iterator it = m_window_list.begin();
146 std::list<Window>::iterator it_end = m_window_list.end();
147
148 for (; it != it_end; ++it)
149 FbTk::KeyUtil::grabButton(button, mod, *it,
150 ButtonPressMask|ButtonReleaseMask);
151}
152
153void Keys::ungrabButtons() {
154 std::list<Window>::iterator it = m_window_list.begin();
155 std::list<Window>::iterator it_end = m_window_list.end();
156
157 for (; it != it_end; ++it)
158 FbTk::KeyUtil::ungrabButtons(*it);
159}
160
143/** 161/**
144 Load and grab keys 162 Load and grab keys
145 TODO: error checking 163 TODO: error checking
@@ -152,7 +170,7 @@ bool Keys::load(const char *filename) {
152 //free memory of previous grabs 170 //free memory of previous grabs
153 deleteTree(); 171 deleteTree();
154 172
155 m_map["default:"] = new t_key(0,0); 173 m_map["default:"] = new t_key(0,0,0,0);
156 174
157 FbTk::App::instance()->sync(false); 175 FbTk::App::instance()->sync(false);
158 176
@@ -211,6 +229,7 @@ bool Keys::addBinding(const string &linebuffer) {
211 return true; // still a valid line. 229 return true; // still a valid line.
212 230
213 unsigned int key = 0, mod = 0; 231 unsigned int key = 0, mod = 0;
232 int type = 0, context = 0;
214 size_t argc = 0; 233 size_t argc = 0;
215 t_key *current_key=m_map["default:"]; 234 t_key *current_key=m_map["default:"];
216 t_key *first_new_keylist = current_key, *first_new_key=0; 235 t_key *first_new_keylist = current_key, *first_new_key=0;
@@ -219,7 +238,7 @@ bool Keys::addBinding(const string &linebuffer) {
219 argc++; 238 argc++;
220 keyspace_t::iterator it = m_map.find(val[0]); 239 keyspace_t::iterator it = m_map.find(val[0]);
221 if (it == m_map.end()) 240 if (it == m_map.end())
222 m_map[val[0]] = new t_key(0,0); 241 m_map[val[0]] = new t_key(0,0,0,0);
223 current_key = m_map[val[0]]; 242 current_key = m_map[val[0]];
224 } 243 }
225 // for each argument 244 // for each argument
@@ -230,41 +249,53 @@ bool Keys::addBinding(const string &linebuffer) {
230 int tmpmod = FbTk::KeyUtil::getModifier(val[argc].c_str()); 249 int tmpmod = FbTk::KeyUtil::getModifier(val[argc].c_str());
231 if(tmpmod) 250 if(tmpmod)
232 mod |= tmpmod; //If it's a modifier 251 mod |= tmpmod; //If it's a modifier
252 else if (strcasecmp("ondesktop", val[argc].c_str()) == 0)
253 context |= ON_DESKTOP;
233 else if (strcasecmp("NONE",val[argc].c_str())) { 254 else if (strcasecmp("NONE",val[argc].c_str())) {
255 // check if it's a mouse button
256 if (!strcasecmp(val[argc].substr(0,5).c_str(), "mouse") &&
257 val[argc].length() > 5) {
258 type = ButtonPress;
259 key = atoi(val[argc].substr(5,val[argc].length()-5).c_str());
234 // keycode covers the following three two-byte cases: 260 // keycode covers the following three two-byte cases:
235 // 0x - hex 261 // 0x - hex
236 // +[1-9] - number between +1 and +9 262 // +[1-9] - number between +1 and +9
237 // numbers 10 and above 263 // numbers 10 and above
238 // 264 //
239 if (val[argc].size() > 1 && (isdigit(val[argc][0]) && 265 } else if (val[argc].size() > 1 && (isdigit(val[argc][0]) &&
240 (isdigit(val[argc][1]) || val[argc][1] == 'x') || 266 (isdigit(val[argc][1]) || val[argc][1] == 'x') ||
241 val[argc][0] == '+' && isdigit(val[argc][1])) ) { 267 val[argc][0] == '+' && isdigit(val[argc][1])) ) {
242 268
243 key = strtoul(val[argc].c_str(), NULL, 0); 269 key = strtoul(val[argc].c_str(), NULL, 0);
270 type = KeyPress;
244 271
245 if (errno == EINVAL || errno == ERANGE) 272 if (errno == EINVAL || errno == ERANGE)
246 key = 0; 273 key = 0;
247 274
248 } else // convert from string symbol 275 } else { // convert from string symbol
249 key = FbTk::KeyUtil::getKey(val[argc].c_str()); 276 key = FbTk::KeyUtil::getKey(val[argc].c_str());
277 type = KeyPress;
278 }
250 279
251 if (key == 0) 280 if (key == 0)
252 return false; 281 return false;
253 if (!first_new_key) { 282 if (!first_new_key) {
254 first_new_keylist = current_key; 283 first_new_keylist = current_key;
255 current_key = current_key->find(key, mod); 284 current_key = current_key->find(type, mod, key, context);
256 if (!current_key) { 285 if (!current_key) {
257 first_new_key = new t_key(key, mod); 286 first_new_key = new t_key(type, mod, key, context);
258 current_key = first_new_key; 287 current_key = first_new_key;
259 } else if (*current_key->m_command) // already being used 288 } else if (*current_key->m_command) // already being used
260 return false; 289 return false;
261 } else { 290 } else {
262 t_key *temp_key = new t_key(key, mod); 291 t_key *temp_key = new t_key(type, mod, key, context);
263 current_key->keylist.push_back(temp_key); 292 current_key->keylist.push_back(temp_key);
264 current_key = temp_key; 293 current_key = temp_key;
265 } 294 }
266 mod = 0; 295 mod = 0;
267 key = 0; 296 key = 0;
297 type = 0;
298 context = 0;
268 } 299 }
269 300
270 } else { // parse command line 301 } else { // parse command line
@@ -291,36 +322,43 @@ bool Keys::addBinding(const string &linebuffer) {
291} 322}
292 323
293// return true if bound to a command, else false 324// return true if bound to a command, else false
294bool Keys::doAction(XKeyEvent &ke) { 325bool Keys::doAction(int type, unsigned int mods, unsigned int key) {
295
296 ke.state = FbTk::KeyUtil::instance().cleanMods(ke.state);
297 326
298 static t_key* next_key = m_keylist; 327 static t_key* next_key = m_keylist;
299 if (!next_key) 328 if (!next_key)
300 next_key = m_keylist; 329 next_key = m_keylist;
301 t_key *temp_key = next_key->find(ke);
302 330
331 mods = FbTk::KeyUtil::instance().cleanMods(mods);
332 // at the moment, any key/button that gets here is on root window
333 // context will need to be added as an argument to doAction, though
334 t_key *temp_key = next_key->find(type, mods, key, ON_DESKTOP|GLOBAL);
303 335
304 // need to save this for emacs-style keybindings 336 // need to save this for emacs-style keybindings
305 static t_key *saved_keymode = 0; 337 static t_key *saved_keymode = 0;
306 338
339 // grab "None Escape" to exit keychain in the middle
340 unsigned int esc = FbTk::KeyUtil::getKey("Escape");
341
307 if (temp_key && temp_key->keylist.size()) { // emacs-style 342 if (temp_key && temp_key->keylist.size()) { // emacs-style
308 saved_keymode = m_keylist; 343 if (!saved_keymode)
344 saved_keymode = m_keylist;
309 next_key = temp_key; 345 next_key = temp_key;
310 setKeyMode(next_key); 346 setKeyMode(next_key);
311 // grab "None Escape" to exit keychain in the middle
312 unsigned int esc = FbTk::KeyUtil::getKey("Escape");
313 grabKey(esc,0); 347 grabKey(esc,0);
314 return true; 348 return true;
315 } 349 }
316 if (!temp_key || *temp_key->m_command == 0) { 350 if (!temp_key || *temp_key->m_command == 0) {
317 next_key = 0; 351 if (type == KeyPress && key == esc && mods == 0) {
318 if (saved_keymode) { 352 // if we're in the middle of an emacs-style keychain, exit it
319 setKeyMode(saved_keymode); 353 next_key = 0;
320 saved_keymode = 0; 354 if (saved_keymode) {
355 setKeyMode(saved_keymode);
356 saved_keymode = 0;
357 }
321 } 358 }
322 return false; 359 return false;
323 } 360 }
361
324 temp_key->m_command->execute(); 362 temp_key->m_command->execute();
325 if (saved_keymode) { 363 if (saved_keymode) {
326 if (next_key == m_keylist) // don't reset keymode if command changed it 364 if (next_key == m_keylist) // don't reset keymode if command changed it
@@ -349,22 +387,33 @@ void Keys::keyMode(string keyMode) {
349 387
350void Keys::setKeyMode(t_key *keyMode) { 388void Keys::setKeyMode(t_key *keyMode) {
351 ungrabKeys(); 389 ungrabKeys();
390 ungrabButtons();
352 keylist_t::iterator it = keyMode->keylist.begin(); 391 keylist_t::iterator it = keyMode->keylist.begin();
353 keylist_t::iterator it_end = keyMode->keylist.end(); 392 keylist_t::iterator it_end = keyMode->keylist.end();
354 for (; it != it_end; ++it) 393 for (; it != it_end; ++it) {
355 grabKey((*it)->key,(*it)->mod); 394 if ((*it)->type == KeyPress)
395 grabKey((*it)->key,(*it)->mod);
396 else if ((*it)->context == GLOBAL)
397 grabButton((*it)->key,(*it)->mod);
398 // we must use root window's event mask to get ON_DESKTOP events
399 }
356 m_keylist = keyMode; 400 m_keylist = keyMode;
357} 401}
358 402
359Keys::t_key::t_key(unsigned int key_, unsigned int mod_, FbTk::RefCount<FbTk::Command> command) { 403Keys::t_key::t_key(int type_, unsigned int mod_, unsigned int key_,
404 int context_, FbTk::RefCount<FbTk::Command> command) {
360 key = key_; 405 key = key_;
361 mod = mod_; 406 mod = mod_;
407 type = type_;
408 context = context_ ? context_ : GLOBAL;
362 m_command = command; 409 m_command = command;
363} 410}
364 411
365Keys::t_key::t_key(t_key *k) { 412Keys::t_key::t_key(t_key *k) {
366 key = k->key; 413 key = k->key;
367 mod = k->mod; 414 mod = k->mod;
415 type = k->type;
416 context = k->context;
368 m_command = k->m_command; 417 m_command = k->m_command;
369} 418}
370 419
diff --git a/src/Keys.hh b/src/Keys.hh
index 6602d49..0365cf8 100644
--- a/src/Keys.hh
+++ b/src/Keys.hh
@@ -38,6 +38,21 @@
38class Keys:private FbTk::NotCopyable { 38class Keys:private FbTk::NotCopyable {
39public: 39public:
40 40
41 // contexts for events
42 // it's ok if there is overlap; it will be worked out in t_key::find()
43 // eventHandlers should submit bitwise-or of contexts the event happened in
44 enum {
45 GLOBAL = 0x01,
46 ON_DESKTOP = 0x02,
47 ON_TOOLBAR = 0x04,
48 ON_ICONBUTTON = 0x08,
49 ON_TITLEBAR = 0x10,
50 ON_WINDOW = 0x20,
51 ON_TAB = 0x40,
52 ON_SLIT = 0x80
53 // and so on...
54 };
55
41 /** 56 /**
42 Constructor 57 Constructor
43 @param display display connection 58 @param display display connection
@@ -65,7 +80,7 @@ public:
65 /** 80 /**
66 do action from XKeyEvent; return false if not bound to anything 81 do action from XKeyEvent; return false if not bound to anything
67 */ 82 */
68 bool doAction(XKeyEvent &ke); 83 bool doAction(int type, unsigned int mods, unsigned int key);
69 84
70 /** 85 /**
71 Reload configuration from filename 86 Reload configuration from filename
@@ -79,6 +94,8 @@ private:
79 94
80 void grabKey(unsigned int key, unsigned int mod); 95 void grabKey(unsigned int key, unsigned int mod);
81 void ungrabKeys(); 96 void ungrabKeys();
97 void grabButton(unsigned int button, unsigned int mod);
98 void ungrabButtons();
82 99
83 std::string m_filename; 100 std::string m_filename;
84 101
@@ -87,33 +104,27 @@ private:
87 104
88 class t_key { 105 class t_key {
89 public: 106 public:
90 t_key(unsigned int key, unsigned int mod, 107 t_key(int type, unsigned int mod, unsigned int key, int context,
91 FbTk::RefCount<FbTk::Command> command = FbTk::RefCount<FbTk::Command>(0)); 108 FbTk::RefCount<FbTk::Command> command = FbTk::RefCount<FbTk::Command>(0));
92 t_key(t_key *k); 109 t_key(t_key *k);
93 ~t_key(); 110 ~t_key();
94 111
95 t_key *find(unsigned int key_, unsigned int mod_) { 112 t_key *find(int type_, unsigned int mod_, unsigned int key_,
96 for (size_t i = 0; i < keylist.size(); i++) { 113 int context_) {
97 if (keylist[i]->key == key_ && keylist[i]->mod == FbTk::KeyUtil::instance().isolateModifierMask(mod_))
98 return keylist[i];
99 }
100 return 0;
101 }
102 t_key *find(XKeyEvent &ke) {
103 for (size_t i = 0; i < keylist.size(); i++) { 114 for (size_t i = 0; i < keylist.size(); i++) {
104 if (keylist[i]->key == ke.keycode && 115 if (keylist[i]->type == type_ && keylist[i]->key == key_ &&
105 keylist[i]->mod == FbTk::KeyUtil::instance().isolateModifierMask(ke.state)) 116 (keylist[i]->context & context_) > 0 && keylist[i]->mod ==
117 FbTk::KeyUtil::instance().isolateModifierMask(mod_))
106 return keylist[i]; 118 return keylist[i];
107 } 119 }
108 return 0; 120 return 0;
109 } 121 }
110 122
111 bool operator == (XKeyEvent &ke) const {
112 return (mod == FbTk::KeyUtil::instance().isolateModifierMask(ke.state) && key == ke.keycode);
113 }
114 123
115 FbTk::RefCount<FbTk::Command> m_command; 124 FbTk::RefCount<FbTk::Command> m_command;
116 unsigned int key; 125 int context; // ON_TITLEBAR, etc.: bitwise-or of all desired contexts
126 int type; // KeyPress or ButtonPress
127 unsigned int key; // key code or button number
117 unsigned int mod; 128 unsigned int mod;
118 keylist_t keylist; 129 keylist_t keylist;
119 }; 130 };
diff --git a/src/Screen.cc b/src/Screen.cc
index d7fc19a..f3a5d01 100644
--- a/src/Screen.cc
+++ b/src/Screen.cc
@@ -2060,7 +2060,7 @@ void BScreen::renderPosWindow() {
2060/** 2060/**
2061 Called when a set of watched modifiers has been released 2061 Called when a set of watched modifiers has been released
2062*/ 2062*/
2063void BScreen::notifyReleasedKeys(XKeyEvent &ke) { 2063void BScreen::notifyReleasedKeys() {
2064 focusControl().stopCyclingFocus(); 2064 focusControl().stopCyclingFocus();
2065} 2065}
2066 2066
diff --git a/src/Screen.hh b/src/Screen.hh
index 739c458..de1dc78 100644
--- a/src/Screen.hh
+++ b/src/Screen.hh
@@ -294,7 +294,7 @@ public:
294 void showGeometry(int width, int height); 294 void showGeometry(int width, int height);
295 void hideGeometry(); 295 void hideGeometry();
296 296
297 void notifyReleasedKeys(XKeyEvent &ke); 297 void notifyReleasedKeys();
298 298
299 void setLayer(FbTk::XLayerItem &item, int layernum); 299 void setLayer(FbTk::XLayerItem &item, int layernum);
300 // remove? no, items are never removed from their layer until they die 300 // remove? no, items are never removed from their layer until they die
diff --git a/src/WorkspaceCmd.cc b/src/WorkspaceCmd.cc
index 6c97808..d2bc3b7 100644
--- a/src/WorkspaceCmd.cc
+++ b/src/WorkspaceCmd.cc
@@ -42,44 +42,48 @@
42#include <functional> 42#include <functional>
43 43
44void NextWindowCmd::execute() { 44void NextWindowCmd::execute() {
45 BScreen *screen = Fluxbox::instance()->keyScreen(); 45 Fluxbox *fb = Fluxbox::instance();
46 BScreen *screen = fb->keyScreen();
46 if (screen != 0) { 47 if (screen != 0) {
47 Fluxbox *fb = Fluxbox::instance(); 48 // get modifiers from event that causes this for focus order cycling
48 // special case for commands from key events 49 unsigned int mods = 0;
49 if (fb->lastEvent().type == KeyPress) { 50 XEvent ev = fb->lastEvent();
50 unsigned int mods = FbTk::KeyUtil::instance().cleanMods(fb->lastEvent().xkey.state); 51 if (ev.type == KeyPress) {
51 mods = FbTk::KeyUtil::instance().isolateModifierMask(mods); 52 mods = FbTk::KeyUtil::instance().cleanMods(ev.xkey.state);
52 if (mods == 0) // can't stacked cycle unless there is a mod to grab 53 } else if (ev.type == ButtonPress) {
53 screen->focusControl().nextFocus(m_option | FocusControl::CYCLELINEAR); 54 mods = FbTk::KeyUtil::instance().cleanMods(ev.xbutton.state);
54 else { 55 }
55 // if stacked cycling, then set a watch for 56 if (mods == 0) // can't stacked cycle unless there is a mod to grab
56 // the release of exactly these modifiers
57 Fluxbox::instance()->watchKeyRelease(*screen, mods);
58 screen->focusControl().nextFocus(m_option);
59 }
60 } else
61 screen->focusControl().nextFocus(m_option | FocusControl::CYCLELINEAR); 57 screen->focusControl().nextFocus(m_option | FocusControl::CYCLELINEAR);
58 else {
59 // if stacked cycling, then set a watch for
60 // the release of exactly these modifiers
61 fb->watchKeyRelease(*screen, mods);
62 screen->focusControl().nextFocus(m_option);
63 }
62 } 64 }
63} 65}
64 66
65void PrevWindowCmd::execute() { 67void PrevWindowCmd::execute() {
66 BScreen *screen = Fluxbox::instance()->keyScreen(); 68 Fluxbox *fb = Fluxbox::instance();
69 BScreen *screen = fb->keyScreen();
67 if (screen != 0) { 70 if (screen != 0) {
68 Fluxbox *fb = Fluxbox::instance(); 71 // get modifiers from event that causes this for focus order cycling
69 // special case for commands from key events 72 unsigned int mods = 0;
70 if (fb->lastEvent().type == KeyPress) { 73 XEvent ev = fb->lastEvent();
71 unsigned int mods = FbTk::KeyUtil::instance().cleanMods(fb->lastEvent().xkey.state); 74 if (ev.type == KeyPress) {
72 mods = FbTk::KeyUtil::instance().isolateModifierMask(mods); 75 mods = FbTk::KeyUtil::instance().cleanMods(ev.xkey.state);
73 if (mods == 0) // can't stacked cycle unless there is a mod to grab 76 } else if (ev.type == ButtonPress) {
74 screen->focusControl().prevFocus(m_option | FocusControl::CYCLELINEAR); 77 mods = FbTk::KeyUtil::instance().cleanMods(ev.xbutton.state);
75 else { 78 }
76 // if stacked cycling, then set a watch for 79 if (mods == 0) // can't stacked cycle unless there is a mod to grab
77 // the release of exactly these modifiers 80 screen->focusControl().prevFocus(m_option | FocusControl::CYCLELINEAR);
78 Fluxbox::instance()->watchKeyRelease(*screen, mods); 81 else {
79 screen->focusControl().prevFocus(m_option); 82 // if stacked cycling, then set a watch for
80 } 83 // the release of exactly these modifiers
81 } else 84 fb->watchKeyRelease(*screen, mods);
82 screen->focusControl().nextFocus(m_option | FocusControl::CYCLELINEAR); 85 screen->focusControl().prevFocus(m_option);
86 }
83 } 87 }
84} 88}
85 89
diff --git a/src/fluxbox.cc b/src/fluxbox.cc
index 89b37fe..7958a27 100644
--- a/src/fluxbox.cc
+++ b/src/fluxbox.cc
@@ -649,6 +649,28 @@ void Fluxbox::setupConfigFiles() {
649 if (create_init) 649 if (create_init)
650 FbTk::FileUtil::copyFile(DEFAULT_INITFILE, init_file.c_str()); 650 FbTk::FileUtil::copyFile(DEFAULT_INITFILE, init_file.c_str());
651 651
652#define CONFIG_VERSION 1
653 FbTk::Resource<int> config_version(m_resourcemanager, 0,
654 "session.configVersion", "Session.ConfigVersion");
655 if (*config_version < CONFIG_VERSION) {
656 // configs are out of date, so run fluxbox-update_configs
657
658 string commandargs = "fluxbox-update_configs -rc ";
659 commandargs += init_file;
660
661#ifdef HAVE_GETPID
662 // add the fluxbox pid so fbuc can have us reload rc if necessary
663 pid_t bpid = getpid();
664 char intbuff[64];
665 sprintf(intbuff, "%d", bpid);
666 commandargs += " -pid ";
667 commandargs += intbuff;
668#endif // HAVE_GETPID
669
670 FbCommands::ExecuteCmd fbuc(commandargs, 0);
671 fbuc.execute();
672 }
673
652} 674}
653 675
654void Fluxbox::handleEvent(XEvent * const e) { 676void Fluxbox::handleEvent(XEvent * const e) {
@@ -936,59 +958,28 @@ void Fluxbox::handleEvent(XEvent * const e) {
936} 958}
937 959
938void Fluxbox::handleButtonEvent(XButtonEvent &be) { 960void Fluxbox::handleButtonEvent(XButtonEvent &be) {
961 m_last_time = be.time;
939 962
940 switch (be.type) { 963 BScreen *screen = searchScreen(be.window);
941 case ButtonPress: { 964 if (be.type == ButtonRelease || !screen)
942 m_last_time = be.time; 965 // no bindings for this type yet
943 966 return;
944 BScreen *screen = searchScreen(be.window);
945 if (screen == 0)
946 break; // end case
947
948 screen->hideMenus();
949 967
950 // strip num/caps/scroll-lock and 968 if (be.button == 1 && !screen->isRootColormapInstalled())
951 // see if we're using any other modifier, 969 screen->imageControl().installRootColormap();
952 // if we're we shouldn't show the root menu
953 // this could happen if we're resizing aterm for instance
954 if (FbTk::KeyUtil::instance().cleanMods(be.state) != 0)
955 return;
956 970
957 if (be.button == 1) { 971 // see if we need to keep watching for key releases
958 if (! screen->isRootColormapInstalled()) 972 BScreen *old_watching_screen = m_watching_screen;
959 screen->imageControl().installRootColormap(); 973 m_watching_screen = 0;
960 // hide menus 974 if (!m_key->doAction(be.type, be.state, be.button))
961 if (screen->rootMenu().isVisible()) 975 // no command run, so could still be cycling
962 screen->rootMenu().hide(); 976 m_watching_screen = old_watching_screen;
963 if (screen->workspaceMenu().isVisible()) 977 else if (old_watching_screen &&
964 screen->workspaceMenu().hide(); 978 m_watching_screen != old_watching_screen) {
965 979 // no longer need to watch old screen, so stop cycling
966 } else if (be.button == 2) { 980 old_watching_screen->notifyReleasedKeys();
967 FbCommands::ShowWorkspaceMenuCmd cmd; 981 if (!m_watching_screen)
968 cmd.execute(); 982 XUngrabKeyboard(FbTk::App::instance()->display(), CurrentTime);
969 } else if (be.button == 3) {
970 FbCommands::ShowRootMenuCmd cmd;
971 cmd.execute();
972 } else if (screen->isDesktopWheeling() && be.button == 4) {
973 if(screen->isReverseWheeling()) {
974 screen->prevWorkspace(1);
975 } else {
976 screen->nextWorkspace(1);
977 }
978 } else if (screen->isDesktopWheeling() && be.button == 5) {
979 if(screen->isReverseWheeling()) {
980 screen->nextWorkspace(1);
981 } else {
982 screen->prevWorkspace(1);
983 }
984 }
985
986 } break;
987 case ButtonRelease:
988 m_last_time = be.time;
989 break;
990 default:
991 break;
992 } 983 }
993} 984}
994 985
@@ -1126,11 +1117,12 @@ void Fluxbox::handleKeyEvent(XKeyEvent &ke) {
1126 case KeyPress: 1117 case KeyPress:
1127 // see if we need to keep watching for key releases 1118 // see if we need to keep watching for key releases
1128 m_watching_screen = 0; 1119 m_watching_screen = 0;
1129 if (!m_key->doAction(ke)) // could still be cycling 1120 if (!m_key->doAction(ke.type, ke.state, ke.keycode))
1121 // no command run, so could still be cycling
1130 m_watching_screen = old_watching_screen; 1122 m_watching_screen = old_watching_screen;
1131 else if (old_watching_screen && 1123 else if (old_watching_screen &&
1132 m_watching_screen != old_watching_screen) { 1124 m_watching_screen != old_watching_screen) {
1133 old_watching_screen->notifyReleasedKeys(ke); 1125 old_watching_screen->notifyReleasedKeys();
1134 if (!m_watching_screen) 1126 if (!m_watching_screen)
1135 XUngrabKeyboard(FbTk::App::instance()->display(), CurrentTime); 1127 XUngrabKeyboard(FbTk::App::instance()->display(), CurrentTime);
1136 } 1128 }
@@ -1148,7 +1140,7 @@ void Fluxbox::handleKeyEvent(XKeyEvent &ke) {
1148 1140
1149 if ((m_watch_keyrelease & state) == 0) { 1141 if ((m_watch_keyrelease & state) == 0) {
1150 1142
1151 m_watching_screen->notifyReleasedKeys(ke); 1143 m_watching_screen->notifyReleasedKeys();
1152 XUngrabKeyboard(FbTk::App::instance()->display(), CurrentTime); 1144 XUngrabKeyboard(FbTk::App::instance()->display(), CurrentTime);
1153 1145
1154 // once they are released, we drop the watch 1146 // once they are released, we drop the watch
diff --git a/util/Makefile.am b/util/Makefile.am
index 53a61d7..263c456 100644
--- a/util/Makefile.am
+++ b/util/Makefile.am
@@ -2,10 +2,13 @@
2SUBDIRS= fbrun 2SUBDIRS= fbrun
3INCLUDES= -I$(top_srcdir)/src -I$(top_srcdir)/src/FbTk 3INCLUDES= -I$(top_srcdir)/src -I$(top_srcdir)/src/FbTk
4bin_SCRIPTS= fbsetbg fluxbox-generate_menu startfluxbox 4bin_SCRIPTS= fbsetbg fluxbox-generate_menu startfluxbox
5bin_PROGRAMS= fbsetroot 5bin_PROGRAMS= fbsetroot fluxbox-update_configs
6fbsetroot_SOURCES= fbsetroot.cc fbsetroot.hh 6fbsetroot_SOURCES= fbsetroot.cc fbsetroot.hh
7fbsetroot_LDADD=../src/FbRootWindow.o ../src/FbAtoms.o \ 7fbsetroot_LDADD=../src/FbRootWindow.o ../src/FbAtoms.o \
8 ../src/FbTk/libFbTk.a 8 ../src/FbTk/libFbTk.a
9fluxbox_update_configs_SOURCES= fluxbox-update_configs.cc
10fluxbox_update_configs_LDADD= ../src/defaults.o ../src/Resources.o \
11 ../src/FbTk/libFbTk.a
9 12
10MAINTAINERCLEANFILES= Makefile.in 13MAINTAINERCLEANFILES= Makefile.in
11EXTRA_DIST= fbsetbg fluxbox-generate_menu.in \ 14EXTRA_DIST= fbsetbg fluxbox-generate_menu.in \
@@ -22,6 +25,9 @@ clean-local:
22fbsetroot.o: fbsetroot.cc ../config.h $(srcdir)/fbsetroot.hh \ 25fbsetroot.o: fbsetroot.cc ../config.h $(srcdir)/fbsetroot.hh \
23 $(top_srcdir)/src/FbRootWindow.hh $(top_srcdir)/src/FbAtoms.hh 26 $(top_srcdir)/src/FbRootWindow.hh $(top_srcdir)/src/FbAtoms.hh
24 27
28fluxbox-update_configs.o: fluxbox-update_configs.cc ../config.h \
29 $(top_srcdir)/src/defaults.hh
30
25startfluxbox: startfluxbox.in 31startfluxbox: startfluxbox.in
26 @regex_cmd@ -e "s,@pkgdatadir@,$(pkgdatadir),g" \ 32 @regex_cmd@ -e "s,@pkgdatadir@,$(pkgdatadir),g" \
27 -e "s,@pkgbindir@,$(bindir),g" \ 33 -e "s,@pkgbindir@,$(bindir),g" \
@@ -40,3 +46,7 @@ fluxbox-generate_menu: fluxbox-generate_menu.in
40 cd ../src && ${MAKE} FbRootWindow.o 46 cd ../src && ${MAKE} FbRootWindow.o
41../src/FbAtoms.o: 47../src/FbAtoms.o:
42 cd ../src && ${MAKE} FbAtoms.o 48 cd ../src && ${MAKE} FbAtoms.o
49../src/defaults.o:
50 cd ../src && ${MAKE} defaults.o
51../src/Resources.o:
52 cd ../src && ${MAKE} Resources.o
diff --git a/util/fluxbox-update_configs.cc b/util/fluxbox-update_configs.cc
new file mode 100644
index 0000000..de1fbb9
--- /dev/null
+++ b/util/fluxbox-update_configs.cc
@@ -0,0 +1,197 @@
1// fluxbox-update_configs.cc
2// Copyright (c) 2007 Fluxbox Team (fluxgen at fluxbox dot org)
3//
4// Permission is hereby granted, free of charge, to any person obtaining a
5// copy of this software and associated documentation files (the "Software"),
6// to deal in the Software without restriction, including without limitation
7// the rights to use, copy, modify, merge, publish, distribute, sublicense,
8// and/or sell copies of the Software, and to permit persons to whom the
9// Software is furnished to do so, subject to the following conditions:
10//
11// The above copyright notice and this permission notice shall be included in
12// all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20// DEALINGS IN THE SOFTWARE.
21
22#include "../src/FbTk/I18n.hh"
23#include "../src/FbTk/Resource.hh"
24#include "../src/FbTk/StringUtil.hh"
25
26#include "../src/defaults.hh"
27
28#ifdef HAVE_CONFIG_H
29#include "config.h"
30#endif // HAVE_CONFIG_H
31
32#ifdef HAVE_SIGNAL_H
33#include <signal.h>
34#endif // HAVE_SIGNAL_H
35
36//use GNU extensions
37#ifndef _GNU_SOURCE
38#define _GNU_SOURCE
39#endif // _GNU_SOURCE
40
41#ifdef HAVE_CSTDIO
42 #include <cstdio>
43#else
44 #include <stdio.h>
45#endif
46#ifdef HAVE_CSTDLIB
47 #include <cstdlib>
48#else
49 #include <stdlib.h>
50#endif
51#ifdef HAVE_CSTRING
52 #include <cstring>
53#else
54 #include <string.h>
55#endif
56#include <iostream>
57#include <fstream>
58
59using std::cout;
60using std::cerr;
61using std::endl;
62using std::string;
63using std::ifstream;
64using std::ofstream;
65
66#define VERSION 1
67
68int run_updates(int old_version, FbTk::ResourceManager rm) {
69 int new_version = old_version;
70
71 if (old_version < 1) { // add mouse events to keys file
72 FbTk::Resource<string> rc_keyfile(rm, DEFAULTKEYSFILE,
73 "session.keyFile", "Session.KeyFile");
74 string keyfilename = FbTk::StringUtil::expandFilename(*rc_keyfile);
75
76 // ok, I don't know anything about file handling in c++
77 // what's it to you?!?!
78 // I assume there should be some error handling in here, but I sure
79 // don't know how, and I don't have documentation
80
81 ifstream in_keyfile(keyfilename.c_str());
82 string whole_keyfile = "";
83
84 while (!in_keyfile.eof()) {
85 string linebuffer;
86
87 getline(in_keyfile, linebuffer);
88 whole_keyfile += linebuffer + "\n";
89 }
90 in_keyfile.close();
91
92 ofstream out_keyfile(keyfilename.c_str());
93 // let's put our new keybindings first, so they're easy to find
94 out_keyfile << "!mouse actions added by fluxbox-update_configs" << endl
95 << "OnDesktop Mouse1 :hideMenus" << endl
96 << "OnDesktop Mouse2 :workspaceMenu" << endl
97 << "OnDesktop Mouse3 :rootMenu" << endl;
98
99 // scrolling on desktop needs to match user's desktop wheeling settings
100 // hmmm, what are the odds that somebody wants this to be different on
101 // different screens? the ability is going away until we make per-screen
102 // keys files, anyway, so let's just use the first screen's setting
103 FbTk::Resource<bool> rc_wheeling(rm, true,
104 "session.screen0.desktopwheeling",
105 "Session.Screen0.DesktopWheeling");
106 FbTk::Resource<bool> rc_reverse(rm, false,
107 "session.screen0.reversewheeling",
108 "Session.Screen0.ReverseWheeling");
109 if (*rc_wheeling) {
110 if (*rc_reverse) { // if you ask me, this should have been default
111 out_keyfile << "OnDesktop Mouse4 :prevWorkspace" << endl
112 << "OnDesktop Mouse5 :nextWorkspace" << endl;
113 } else {
114 out_keyfile << "OnDesktop Mouse4 :nextWorkspace" << endl
115 << "OnDesktop Mouse5 :prevWorkspace" << endl;
116 }
117 }
118 out_keyfile << endl; // just for good looks
119
120 // now, restore user's old keybindings
121 out_keyfile << whole_keyfile;
122 new_version = 1;
123 }
124
125 return new_version;
126}
127
128int main(int argc, char **argv) {
129 string rc_filename;
130 int i = 1;
131 pid_t fb_pid = 0;
132
133 FbTk::NLSInit("fluxbox.cat");
134 _FB_USES_NLS;
135
136 for (; i < argc; i++) {
137 if (strcmp(argv[i], "-rc") == 0) {
138 // look for alternative rc file to use
139
140 if ((++i) >= argc) {
141 cerr<<_FB_CONSOLETEXT(main, RCRequiresArg,
142 "error: '-rc' requires an argument", "the -rc option requires a file argument")<<endl;
143 exit(1);
144 }
145
146 rc_filename = argv[i];
147 } else if (strcmp(argv[i], "-pid") == 0) {
148 if ((++i) >= argc) {
149 // need translations for this, too
150 cerr<<"the -pid option requires a numeric argument"<<endl;
151 } else
152 fb_pid = atoi(argv[i]);
153 } else if (strcmp(argv[i], "-help") == 0 || strcmp(argv[i], "-h") == 0) {
154 // no NLS translations yet -- we'll just have to use English for now
155 cout << " -rc <string>\t\t\tuse alternate resource file.\n"
156 << " -pid <int>\t\t\ttell fluxbox to reload configuration.\n"
157 << " -help\t\t\t\tdisplay this help text and exit.\n\n"
158 << endl;
159 exit(0);
160 }
161 }
162
163 FbTk::ResourceManager resource_manager(rc_filename.c_str(),false);
164 if (rc_filename.empty() || !resource_manager.load(rc_filename.c_str())) {
165 // couldn't load rc file
166 if (!rc_filename.empty()) {
167 cerr<<_FB_CONSOLETEXT(Fluxbox, CantLoadRCFile, "Failed to load database", "Failed trying to read rc file")<<":"<<rc_filename<<endl;
168 cerr<<_FB_CONSOLETEXT(Fluxbox, CantLoadRCFileTrying, "Retrying with", "Retrying rc file loading with (the following file)")<<": "<<DEFAULT_INITFILE<<endl;
169 }
170 // couldn't load default rc file, either
171 if (!resource_manager.load(DEFAULT_INITFILE)) {
172 cerr<<_FB_CONSOLETEXT(Fluxbox, CantLoadRCFile, "Failed to load database", "")<<": "<<DEFAULT_INITFILE<<endl;
173 exit(1); // this is a fatal error for us
174 }
175 }
176
177 // run updates here
178 // I feel like putting this in a separate function for no apparent reason
179
180 FbTk::Resource<int> config_version(resource_manager, 0,
181 "session.configVersion", "Session.ConfigVersion");
182 int old_version = *config_version;
183 int new_version = run_updates(old_version, resource_manager);
184 if (new_version > old_version) {
185 config_version = new_version;
186 resource_manager.save(rc_filename.c_str(), rc_filename.c_str());
187
188#ifdef HAVE_SIGNAL_H
189 // if we were given a fluxbox pid, send it a reconfigure signal
190 if (fb_pid > 0)
191 kill(fb_pid, SIGUSR2);
192#endif // HAVE_SIGNAL_H
193
194 }
195
196 return 0;
197}