aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMathias Gumz <akira at fluxbox dot org>2009-12-18 07:05:07 (GMT)
committerMathias Gumz <akira at fluxbox dot org>2009-12-18 07:05:07 (GMT)
commit46261a8284730a16d664fa89423fc5728ed284b4 (patch)
treec81d7962fe924f5bfca44dc0254304cb537544b9
parent79859c94482e4602eb22c35b988027ab199734a6 (diff)
downloadfluxbox-46261a8284730a16d664fa89423fc5728ed284b4.zip
fluxbox-46261a8284730a16d664fa89423fc5728ed284b4.tar.bz2
implemented 'MoveN' and 'ClickN' support in keys file.
the hardcoded 'OnTitlebar Mouse1 :Raise' (see Window.cc, FluxboxWindow::buttonPressEvent()) is disabled for now, should be added to fluxbox-update_configs
-rw-r--r--ChangeLog4
-rw-r--r--doc/asciidoc/fluxbox-keys.txt22
-rw-r--r--doc/fluxbox-keys.5.in31
-rw-r--r--src/CurrentWindowCmd.cc47
-rw-r--r--src/FbTk/KeyUtil.cc56
-rw-r--r--src/Keys.cc110
-rw-r--r--src/Window.cc43
-rw-r--r--src/Window.hh1
8 files changed, 216 insertions, 98 deletions
diff --git a/ChangeLog b/ChangeLog
index 3087640..cc9e8a9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,10 @@
1 (Format: Year/Month/Day) 1 (Format: Year/Month/Day)
2Changes for 1.1.2 2Changes for 1.1.2
3 3
4*09/12/18:
5 * Implemented new 'MoveN' and 'ClickN' support for keys file (Mathias)
6 Keys.cc Window.cc/hh CurrentWindowCmd.cc FbTk/KeyUtil.cc
7
4*09/12/15: 8*09/12/15:
5 * Updated fluxbox-keys documentation, added 'Fullscreen' (thanx Paul Tagliamonte) 9 * Updated fluxbox-keys documentation, added 'Fullscreen' (thanx Paul Tagliamonte)
6 10
diff --git a/doc/asciidoc/fluxbox-keys.txt b/doc/asciidoc/fluxbox-keys.txt
index ed69a57..3f3431d 100644
--- a/doc/asciidoc/fluxbox-keys.txt
+++ b/doc/asciidoc/fluxbox-keys.txt
@@ -55,7 +55,7 @@ are most commonly used:
55where *Mod1* is the Alt key on the PC keyboard and *Mod4* is usually a key 55where *Mod1* is the Alt key on the PC keyboard and *Mod4* is usually a key
56branded with a familiar company logo. 56branded with a familiar company logo.
57 57
58There are also some special modifiers that refer to mouse button presses::: 58There are also some special modifiers that refer to mouse button events:::
59*OnDesktop*;; 59*OnDesktop*;;
60 The mouse cursor is over the desktop (root window), and not any 60 The mouse cursor is over the desktop (root window), and not any
61 window. 61 window.
@@ -84,13 +84,21 @@ the key, and see the name in the output. If you have some "special" keys that
84do not produce a key name in the output of *xev(1)*, you can just use the 84do not produce a key name in the output of *xev(1)*, you can just use the
85keycode (NOT the keysym!) in your keys file. 85keycode (NOT the keysym!) in your keys file.
86 86
87Commands can also be bound to mouse button presses, for which the proper "key" 87Commands can also be bound to mouse events ('N' denotes the number of the
88name is *Mouse*'n' where 'n' is the number of the mouse button. For example, 88button, eg. '1' is the primary button, '4'/'5' are the wheel buttons):
89*Mouse1* is the primary button, and *Mouse4* / *Mouse5* are the scroll wheel 89
90events, in normal configurations. *xev(1)* can also be used to tell the button 90*MouseN*;;
91number. 91 The mouse button 'N' is pressed down and holded.
92*ClickN*;;
93 The mouse button 'N' is clicked (pressed and released with no
94 movement in between)
95*MoveN*;;
96 The mouse button 'N' is currently holded, the binded action is triggered
97 as often as the mouse moves.
98
99
100There are some special "keys" that let you bind events to non-keyboard events:
92 101
93There are some special "keys" that let you bind events to non-keyboard events:::
94*ChangeWorkspace*;; 102*ChangeWorkspace*;;
95 Fires when the workspace changes. This can be used to change backgrounds or 103 Fires when the workspace changes. This can be used to change backgrounds or
96 do anything else you like when you switch to a new workspace. See the 104 do anything else you like when you switch to a new workspace. See the
diff --git a/doc/fluxbox-keys.5.in b/doc/fluxbox-keys.5.in
index 6e641f9..2b29891 100644
--- a/doc/fluxbox-keys.5.in
+++ b/doc/fluxbox-keys.5.in
@@ -2,12 +2,12 @@
2.\" Title: fluxbox-keys 2.\" Title: fluxbox-keys
3.\" Author: [see the "AUTHORS" section] 3.\" Author: [see the "AUTHORS" section]
4.\" Generator: DocBook XSL Stylesheets v1.75.1 <http://docbook.sf.net/> 4.\" Generator: DocBook XSL Stylesheets v1.75.1 <http://docbook.sf.net/>
5.\" Date: 12/14/2009 5.\" Date: 12/17/2009
6.\" Manual: Fluxbox Manual 6.\" Manual: Fluxbox Manual
7.\" Source: fluxbox-keys.txt 7.\" Source: fluxbox-keys.txt
8.\" Language: English 8.\" Language: English
9.\" 9.\"
10.TH "FLUXBOX\-KEYS" "5" "12/14/2009" "fluxbox\-keys\&.txt" "Fluxbox Manual" 10.TH "FLUXBOX\-KEYS" "5" "12/17/2009" "fluxbox\-keys\&.txt" "Fluxbox Manual"
11.\" ----------------------------------------------------------------- 11.\" -----------------------------------------------------------------
12.\" * set default formatting 12.\" * set default formatting
13.\" ----------------------------------------------------------------- 13.\" -----------------------------------------------------------------
@@ -53,7 +53,7 @@ You can get a list of possible modifiers by calling \(oqxmodmap \-pm\(cq\&. This
53.sp 53.sp
54where \fBMod1\fR is the Alt key on the PC keyboard and \fBMod4\fR is usually a key branded with a familiar company logo\&. 54where \fBMod1\fR is the Alt key on the PC keyboard and \fBMod4\fR is usually a key branded with a familiar company logo\&.
55.PP 55.PP
56There are also some special modifiers that refer to mouse button presses 56There are also some special modifiers that refer to mouse button events
57.RS 4 57.RS 4
58.PP 58.PP
59\fBOnDesktop\fR 59\fBOnDesktop\fR
@@ -90,10 +90,30 @@ You may specify a key by its key name (for example, \fBa\fR or \fBspace\fR) or b
90.sp 90.sp
91If you don\(cqt know the name of a key, you can run \fBxev(1)\fR in a terminal, push the key, and see the name in the output\&. If you have some "special" keys that do not produce a key name in the output of \fBxev(1)\fR, you can just use the keycode (NOT the keysym!) in your keys file\&. 91If you don\(cqt know the name of a key, you can run \fBxev(1)\fR in a terminal, push the key, and see the name in the output\&. If you have some "special" keys that do not produce a key name in the output of \fBxev(1)\fR, you can just use the keycode (NOT the keysym!) in your keys file\&.
92.sp 92.sp
93Commands can also be bound to mouse button presses, for which the proper "key" name is \fBMouse\fR\fIn\fR where \fIn\fR is the number of the mouse button\&. For example, \fBMouse1\fR is the primary button, and \fBMouse4\fR / \fBMouse5\fR are the scroll wheel events, in normal configurations\&. \fBxev(1)\fR can also be used to tell the button number\&. 93Commands can also be bound to mouse events (\fIN\fR denotes the number of the button, eg\&. \fI1\fR is the primary button, \fI4\fR/\fI5\fR are the wheel buttons):
94.PP 94.PP
95There are some special "keys" that let you bind events to non\-keyboard events 95\fBMouseN\fR
96.RS 4 96.RS 4
97The mouse button
98\fIN\fR
99is pressed down and holded\&.
100.RE
101.PP
102\fBClickN\fR
103.RS 4
104The mouse button
105\fIN\fR
106is clicked (pressed and released with no movement in between)
107.RE
108.PP
109\fBMoveN\fR
110.RS 4
111The mouse button
112\fIN\fR
113is currently holded, the binded action is triggered as often as the mouse moves\&.
114.RE
115.sp
116There are some special "keys" that let you bind events to non\-keyboard events:
97.PP 117.PP
98\fBChangeWorkspace\fR 118\fBChangeWorkspace\fR
99.RS 4 119.RS 4
@@ -101,7 +121,6 @@ Fires when the workspace changes\&. This can be used to change backgrounds or do
101\fBEXAMPLES\fR 121\fBEXAMPLES\fR
102below for one idea\&. 122below for one idea\&.
103.RE 123.RE
104.RE
105.if n \{\ 124.if n \{\
106.sp 125.sp
107.\} 126.\}
diff --git a/src/CurrentWindowCmd.cc b/src/CurrentWindowCmd.cc
index b73de01..f896009 100644
--- a/src/CurrentWindowCmd.cc
+++ b/src/CurrentWindowCmd.cc
@@ -262,11 +262,26 @@ void GoToTabCmd::real_execute() {
262REGISTER_COMMAND(startmoving, StartMovingCmd, void); 262REGISTER_COMMAND(startmoving, StartMovingCmd, void);
263 263
264void StartMovingCmd::real_execute() { 264void StartMovingCmd::real_execute() {
265
266 int x;
267 int y;
265 const XEvent &last = Fluxbox::instance()->lastEvent(); 268 const XEvent &last = Fluxbox::instance()->lastEvent();
266 if (last.type == ButtonPress) { 269 switch (last.type) {
267 const XButtonEvent &be = last.xbutton; 270 case ButtonPress:
268 fbwindow().startMoving(be.x_root, be.y_root); 271 x = last.xbutton.x_root;
272 y = last.xbutton.y_root;
273 break;
274
275 case MotionNotify:
276 x = last.xmotion.x_root;
277 y = last.xmotion.y_root;
278 break;
279
280 default:
281 return;
269 } 282 }
283
284 fbwindow().startMoving(x, y);
270} 285}
271 286
272FbTk::Command<void> *StartResizingCmd::parse(const string &cmd, const string &args, 287FbTk::Command<void> *StartResizingCmd::parse(const string &cmd, const string &args,
@@ -305,15 +320,27 @@ FbTk::Command<void> *StartResizingCmd::parse(const string &cmd, const string &ar
305REGISTER_COMMAND_PARSER(startresizing, StartResizingCmd::parse, void); 320REGISTER_COMMAND_PARSER(startresizing, StartResizingCmd::parse, void);
306 321
307void StartResizingCmd::real_execute() { 322void StartResizingCmd::real_execute() {
323
324 int x;
325 int y;
308 const XEvent &last = Fluxbox::instance()->lastEvent(); 326 const XEvent &last = Fluxbox::instance()->lastEvent();
309 if (last.type == ButtonPress) { 327 switch (last.type) {
310 const XButtonEvent &be = last.xbutton; 328 case ButtonPress:
311 int x = be.x_root - fbwindow().x() 329 x = last.xbutton.x_root;
312 - fbwindow().frame().window().borderWidth(); 330 y = last.xbutton.y_root;
313 int y = be.y_root - fbwindow().y() 331 break;
314 - fbwindow().frame().window().borderWidth(); 332 case MotionNotify:
315 fbwindow().startResizing(x, y, fbwindow().getResizeDirection(x, y, m_mode)); 333 x = last.xmotion.x_root;
334 y = last.xmotion.y_root;
335 break;
336 default:
337 return;
316 } 338 }
339
340 x -= fbwindow().x() - fbwindow().frame().window().borderWidth();
341 y -= fbwindow().y() - fbwindow().frame().window().borderWidth();
342
343 fbwindow().startResizing(x, y, fbwindow().getResizeDirection(x, y, m_mode));
317} 344}
318 345
319REGISTER_COMMAND(starttabbing, StartTabbingCmd, void); 346REGISTER_COMMAND(starttabbing, StartTabbingCmd, void);
diff --git a/src/FbTk/KeyUtil.cc b/src/FbTk/KeyUtil.cc
index 0578b9c..6ffe2a2 100644
--- a/src/FbTk/KeyUtil.cc
+++ b/src/FbTk/KeyUtil.cc
@@ -42,16 +42,16 @@ struct t_modlist{
42}; 42};
43 43
44const struct t_modlist modlist[] = { 44const struct t_modlist modlist[] = {
45 {"SHIFT", ShiftMask}, 45 {"shift", ShiftMask},
46 {"LOCK", LockMask}, 46 {"lock", LockMask},
47 {"CONTROL", ControlMask}, 47 {"control", ControlMask},
48 {"MOD1", Mod1Mask}, 48 {"mod1", Mod1Mask},
49 {"MOD2", Mod2Mask}, 49 {"mod2", Mod2Mask},
50 {"MOD3", Mod3Mask}, 50 {"mod3", Mod3Mask},
51 {"MOD4", Mod4Mask}, 51 {"mod4", Mod4Mask},
52 {"MOD5", Mod5Mask}, 52 {"mod5", Mod5Mask},
53 {"ALT", Mod1Mask}, 53 {"alt", Mod1Mask},
54 {"CTRL", ControlMask}, 54 {"ctrl", ControlMask},
55 {0, 0} 55 {0, 0}
56}; 56};
57 57
@@ -88,7 +88,7 @@ void KeyUtil::loadModmap() {
88 XFreeModifiermap(m_modmap); 88 XFreeModifiermap(m_modmap);
89 89
90 m_modmap = XGetModifierMapping(App::instance()->display()); 90 m_modmap = XGetModifierMapping(App::instance()->display());
91 91
92 // find modifiers and set them 92 // find modifiers and set them
93 for (int i=0, realkey=0; i<8; ++i) { 93 for (int i=0, realkey=0; i<8; ++i) {
94 for (int key=0; key<m_modmap->max_keypermod; ++key, ++realkey) { 94 for (int key=0; key<m_modmap->max_keypermod; ++key, ++realkey) {
@@ -96,7 +96,7 @@ void KeyUtil::loadModmap() {
96 if (m_modmap->modifiermap[realkey] == 0) 96 if (m_modmap->modifiermap[realkey] == 0)
97 continue; 97 continue;
98 98
99 KeySym ks = XKeycodeToKeysym(App::instance()->display(), 99 KeySym ks = XKeycodeToKeysym(App::instance()->display(),
100 m_modmap->modifiermap[realkey], 0); 100 m_modmap->modifiermap[realkey], 0);
101 101
102 switch (ks) { 102 switch (ks) {
@@ -154,12 +154,18 @@ void KeyUtil::grabButton(unsigned int button, unsigned int mod, Window win,
154*/ 154*/
155 155
156unsigned int KeyUtil::getKey(const char *keystr) { 156unsigned int KeyUtil::getKey(const char *keystr) {
157 if (!keystr) 157
158 return 0; 158 KeyCode code = 0;
159 KeySym sym = XStringToKeysym(keystr); 159
160 if (sym==NoSymbol) 160 if (keystr) {
161 return 0; 161
162 return XKeysymToKeycode(App::instance()->display(), sym); 162 KeySym sym = XStringToKeysym(keystr);
163 if (sym != NoSymbol) {
164 code = XKeysymToKeycode(App::instance()->display(), sym);
165 }
166 }
167
168 return code;
163} 169}
164 170
165 171
@@ -169,14 +175,14 @@ unsigned int KeyUtil::getKey(const char *keystr) {
169unsigned int KeyUtil::getModifier(const char *modstr) { 175unsigned int KeyUtil::getModifier(const char *modstr) {
170 if (!modstr) 176 if (!modstr)
171 return 0; 177 return 0;
172 178
173 // find mod mask string 179 // find mod mask string
174 for (unsigned int i=0; modlist[i].str !=0; i++) { 180 for (unsigned int i=0; modlist[i].str !=0; i++) {
175 if (modlist[i] == modstr) 181 if (modlist[i] == modstr)
176 return modlist[i].mask; 182 return modlist[i].mask;
177 } 183 }
178 184
179 return 0; 185 return 0;
180} 186}
181 187
182/// Ungrabs the keys 188/// Ungrabs the keys
@@ -193,7 +199,7 @@ void KeyUtil::ungrabButtons(Window win) {
193unsigned int KeyUtil::keycodeToModmask(unsigned int keycode) { 199unsigned int KeyUtil::keycodeToModmask(unsigned int keycode) {
194 XModifierKeymap *modmap = instance().m_modmap; 200 XModifierKeymap *modmap = instance().m_modmap;
195 201
196 if (!modmap) 202 if (!modmap)
197 return 0; 203 return 0;
198 204
199 // search through modmap for this keycode 205 // search through modmap for this keycode
@@ -204,7 +210,7 @@ unsigned int KeyUtil::keycodeToModmask(unsigned int keycode) {
204 if (modmap->modifiermap[modmap->max_keypermod*mod + key] == keycode) { 210 if (modmap->modifiermap[modmap->max_keypermod*mod + key] == keycode) {
205 return modlist[mod].mask; 211 return modlist[mod].mask;
206 } 212 }
207 } 213 }
208 } 214 }
209 // no luck 215 // no luck
210 return 0; 216 return 0;
diff --git a/src/Keys.cc b/src/Keys.cc
index 0b8efe5..935d54b 100644
--- a/src/Keys.cc
+++ b/src/Keys.cc
@@ -106,6 +106,28 @@ using std::pair;
106 106
107using FbTk::STLUtil::destroyAndClearSecond; 107using FbTk::STLUtil::destroyAndClearSecond;
108 108
109namespace {
110
111// candidate for FbTk::StringUtil ?
112int extractKeyFromString(const std::string& in, const char* start_pattern, unsigned int& key) {
113
114 int ret = 0;
115
116 if (strstr(in.c_str(), start_pattern) != 0) {
117
118 unsigned int tmp_key = 0;
119 if (FbTk::StringUtil::extractNumber(in.substr(strlen(start_pattern)), tmp_key)) {
120
121 key = tmp_key;
122 ret = 1;
123 }
124 }
125
126 return ret;
127}
128
129} // end of anonymouse namespace
130
109// helper class 'keytree' 131// helper class 'keytree'
110class Keys::t_key { 132class Keys::t_key {
111public: 133public:
@@ -254,10 +276,12 @@ void Keys::grabWindow(Window win) {
254 if ((win_it->second & Keys::GLOBAL) > 0 && (*it)->type == KeyPress) 276 if ((win_it->second & Keys::GLOBAL) > 0 && (*it)->type == KeyPress)
255 FbTk::KeyUtil::grabKey((*it)->key, (*it)->mod, win); 277 FbTk::KeyUtil::grabKey((*it)->key, (*it)->mod, win);
256 // ON_DESKTOP buttons don't need to be grabbed 278 // ON_DESKTOP buttons don't need to be grabbed
257 else if ((win_it->second & (*it)->context & ~Keys::ON_DESKTOP) > 0 && 279 else if ((win_it->second & (*it)->context & ~Keys::ON_DESKTOP) > 0) {
258 (*it)->type == ButtonPress) 280
259 FbTk::KeyUtil::grabButton((*it)->key, (*it)->mod, win, 281 if ((*it)->type == ButtonPress || (*it)->type == ButtonRelease || (*it)->type == MotionNotify) {
260 ButtonPressMask|ButtonReleaseMask); 282 FbTk::KeyUtil::grabButton((*it)->key, (*it)->mod, win, ButtonPressMask|ButtonReleaseMask|ButtonMotionMask);
283 }
284 }
261 } 285 }
262} 286}
263 287
@@ -363,85 +387,84 @@ bool Keys::addBinding(const string &linebuffer) {
363 // for each argument 387 // for each argument
364 for (; argc < val.size(); argc++) { 388 for (; argc < val.size(); argc++) {
365 389
366 if (val[argc][0] != ':') { // parse key(s) 390 std::string arg = FbTk::StringUtil::toLower(val[argc]);
391
392 if (arg[0] != ':') { // parse key(s)
367 393
368 int tmpmod = FbTk::KeyUtil::getModifier(val[argc].c_str()); 394 int tmpmod = FbTk::KeyUtil::getModifier(arg.c_str());
369 if(tmpmod) 395 if(tmpmod)
370 mod |= tmpmod; //If it's a modifier 396 mod |= tmpmod; //If it's a modifier
371 else if (strcasecmp("ondesktop", val[argc].c_str()) == 0) 397 else if (arg == "ondesktop")
372 context |= ON_DESKTOP; 398 context |= ON_DESKTOP;
373 else if (strcasecmp("ontoolbar", val[argc].c_str()) == 0) 399 else if (arg == "ontoolbar")
374 context |= ON_TOOLBAR; 400 context |= ON_TOOLBAR;
375 else if (strcasecmp("onwindow", val[argc].c_str()) == 0) 401 else if (arg == "onwindow")
376 context |= ON_WINDOW; 402 context |= ON_WINDOW;
377 else if (strcasecmp("ontitlebar", val[argc].c_str()) == 0) 403 else if (arg == "ontitlebar")
378 context |= ON_TITLEBAR; 404 context |= ON_TITLEBAR;
379 else if (strcasecmp("double", val[argc].c_str()) == 0) 405 else if (arg == "double")
380 isdouble = true; 406 isdouble = true;
381 else if (strcasecmp("NONE",val[argc].c_str())) { 407 else if (arg != "none") {
382 // check if it's a mouse button 408 if (arg == "focusin") {
383 if (strcasecmp("focusin", val[argc].c_str()) == 0) {
384 context = ON_WINDOW; 409 context = ON_WINDOW;
385 mod = key = 0; 410 mod = key = 0;
386 type = FocusIn; 411 type = FocusIn;
387 } else if (strcasecmp("focusout", val[argc].c_str()) == 0) { 412 } else if (arg == "focusout") {
388 context = ON_WINDOW; 413 context = ON_WINDOW;
389 mod = key = 0; 414 mod = key = 0;
390 type = FocusOut; 415 type = FocusOut;
391 } else if (strcasecmp("changeworkspace", 416 } else if (arg == "changeworkspace") {
392 val[argc].c_str()) == 0) {
393 context = ON_DESKTOP; 417 context = ON_DESKTOP;
394 mod = key = 0; 418 mod = key = 0;
395 type = FocusIn; 419 type = FocusIn;
396 } else if (strcasecmp("mouseover", val[argc].c_str()) == 0) { 420 } else if (arg == "mouseover") {
397 type = EnterNotify; 421 type = EnterNotify;
398 if (!(context & (ON_WINDOW|ON_TOOLBAR))) 422 if (!(context & (ON_WINDOW|ON_TOOLBAR)))
399 context |= ON_WINDOW; 423 context |= ON_WINDOW;
400 key = 0; 424 key = 0;
401 } else if (strcasecmp("mouseout", val[argc].c_str()) == 0) { 425 } else if (arg == "mouseout") {
402 type = LeaveNotify; 426 type = LeaveNotify;
403 if (!(context & (ON_WINDOW|ON_TOOLBAR))) 427 if (!(context & (ON_WINDOW|ON_TOOLBAR)))
404 context |= ON_WINDOW; 428 context |= ON_WINDOW;
405 key = 0; 429 key = 0;
406 } else if (strcasecmp(val[argc].substr(0,5).c_str(), 430
407 "mouse") == 0 && 431 // check if it's a mouse button
408 val[argc].length() > 5) { 432 } else if (extractKeyFromString(arg, "mouse", key)) {
409 type = ButtonPress; 433 type = ButtonPress;
410 key = atoi(val[argc].substr(5, 434
411 val[argc].length()-5).c_str());
412 // fluxconf mangles things like OnWindow Mouse# to Mouse#ow 435 // fluxconf mangles things like OnWindow Mouse# to Mouse#ow
413 if (strstr(val[argc].c_str(), "top")) 436 if (strstr(arg.c_str(), "top"))
414 context = ON_DESKTOP; 437 context = ON_DESKTOP;
415 else if (strstr(val[argc].c_str(), "ebar")) 438 else if (strstr(arg.c_str(), "ebar"))
416 context = ON_TITLEBAR; 439 context = ON_TITLEBAR;
417 else if (strstr(val[argc].c_str(), "bar")) 440 else if (strstr(arg.c_str(), "bar"))
418 context = ON_TOOLBAR; 441 context = ON_TOOLBAR;
419 else if (strstr(val[argc].c_str(), "ow")) 442 else if (strstr(arg.c_str(), "ow"))
420 context = ON_WINDOW; 443 context = ON_WINDOW;
444 } else if (extractKeyFromString(arg, "click", key)) {
445 type = ButtonRelease;
446 } else if (extractKeyFromString(arg, "move", key)) {
447 type = MotionNotify;
448
449 } else if (key = FbTk::KeyUtil::getKey(val[argc].c_str())) { // convert from string symbol
450 type = KeyPress;
451
421 // keycode covers the following three two-byte cases: 452 // keycode covers the following three two-byte cases:
422 // 0x - hex 453 // 0x - hex
423 // +[1-9] - number between +1 and +9 454 // +[1-9] - number between +1 and +9
424 // numbers 10 and above 455 // numbers 10 and above
425 // 456 //
426 } else if (!val[argc].empty() && ((isdigit(val[argc][0]) && 457 } else {
427 (isdigit(val[argc][1]) || val[argc][1] == 'x')) || 458 FbTk::StringUtil::extractNumber(arg, key);
428 (val[argc][0] == '+' && isdigit(val[argc][1])))) {
429
430 key = strtoul(val[argc].c_str(), NULL, 0);
431 type = KeyPress;
432
433 if (errno == EINVAL || errno == ERANGE)
434 key = 0;
435
436 } else { // convert from string symbol
437 key = FbTk::KeyUtil::getKey(val[argc].c_str());
438 type = KeyPress; 459 type = KeyPress;
439 } 460 }
440 461
441 if (key == 0 && (type == KeyPress || type == ButtonPress)) 462 if (key == 0 && (type == KeyPress || type == ButtonPress || type == ButtonRelease))
442 return false; 463 return false;
464
443 if (type != ButtonPress) 465 if (type != ButtonPress)
444 isdouble = false; 466 isdouble = false;
467
445 if (!first_new_key) { 468 if (!first_new_key) {
446 first_new_keylist = current_key; 469 first_new_keylist = current_key;
447 current_key = current_key->find(type, mod, key, context, 470 current_key = current_key->find(type, mod, key, context,
@@ -470,7 +493,7 @@ bool Keys::addBinding(const string &linebuffer) {
470 return false; 493 return false;
471 494
472 const char *str = FbTk::StringUtil::strcasestr(linebuffer.c_str(), 495 const char *str = FbTk::StringUtil::strcasestr(linebuffer.c_str(),
473 val[argc].c_str()); 496 val[argc].c_str());
474 if (str) // +1 to skip ':' 497 if (str) // +1 to skip ':'
475 current_key->m_command = FbTk::CommandParser<void>::instance().parse(str + 1); 498 current_key->m_command = FbTk::CommandParser<void>::instance().parse(str + 1);
476 499
@@ -504,10 +527,11 @@ bool Keys::doAction(int type, unsigned int mods, unsigned int key,
504 bool isdouble = false; 527 bool isdouble = false;
505 528
506 if (type == ButtonPress) { 529 if (type == ButtonPress) {
507 if (time > last_button_time) 530 if (time > last_button_time) {
508 double_click = (time - last_button_time < 531 double_click = (time - last_button_time <
509 Fluxbox::instance()->getDoubleClickInterval()) && 532 Fluxbox::instance()->getDoubleClickInterval()) &&
510 last_button == key; 533 last_button == key;
534 }
511 last_button_time = time; 535 last_button_time = time;
512 last_button = key; 536 last_button = key;
513 isdouble = double_click; 537 isdouble = double_click;
diff --git a/src/Window.cc b/src/Window.cc
index c03447c..0fb674c 100644
--- a/src/Window.cc
+++ b/src/Window.cc
@@ -280,6 +280,7 @@ FluxboxWindow::FluxboxWindow(WinClient &client):
280 m_button_grab_x(0), m_button_grab_y(0), 280 m_button_grab_x(0), m_button_grab_y(0),
281 m_last_move_x(0), m_last_move_y(0), 281 m_last_move_x(0), m_last_move_y(0),
282 m_last_resize_h(1), m_last_resize_w(1), 282 m_last_resize_h(1), m_last_resize_w(1),
283 m_last_pressed_button(0),
283 m_workspace_number(0), 284 m_workspace_number(0),
284 m_current_state(0), 285 m_current_state(0),
285 m_old_decoration_mask(0), 286 m_old_decoration_mask(0),
@@ -1073,7 +1074,6 @@ void FluxboxWindow::grabButtons() {
1073 GrabModeSync, GrabModeSync, None, None); 1074 GrabModeSync, GrabModeSync, None, None);
1074 XUngrabButton(display, Button1, Mod1Mask|Mod2Mask|Mod3Mask, 1075 XUngrabButton(display, Button1, Mod1Mask|Mod2Mask|Mod3Mask,
1075 frame().window().window()); 1076 frame().window().window());
1076
1077} 1077}
1078 1078
1079 1079
@@ -1478,7 +1478,7 @@ void FluxboxWindow::setFullscreenLayer() {
1478 FluxboxWindow *foc = FocusControl::focusedFbWindow(); 1478 FluxboxWindow *foc = FocusControl::focusedFbWindow();
1479 // if another window on the same head is focused, make sure we can see it 1479 // if another window on the same head is focused, make sure we can see it
1480 if (isFocused() || !foc || &foc->screen() != &screen() || 1480 if (isFocused() || !foc || &foc->screen() != &screen() ||
1481 getOnHead() != foc->getOnHead() || 1481 getOnHead() != foc->getOnHead() ||
1482 (foc->winClient().isTransient() && 1482 (foc->winClient().isTransient() &&
1483 foc->winClient().transientFor()->fbwindow() == this)) { 1483 foc->winClient().transientFor()->fbwindow() == this)) {
1484 moveToLayer(::Layer::ABOVE_DOCK); 1484 moveToLayer(::Layer::ABOVE_DOCK);
@@ -2370,13 +2370,16 @@ bool FluxboxWindow::isTyping() const {
2370void FluxboxWindow::buttonPressEvent(XButtonEvent &be) { 2370void FluxboxWindow::buttonPressEvent(XButtonEvent &be) {
2371 m_last_button_x = be.x_root; 2371 m_last_button_x = be.x_root;
2372 m_last_button_y = be.y_root; 2372 m_last_button_y = be.y_root;
2373 m_last_pressed_button = be.button;
2373 2374
2374 bool onTitlebar = 2375 bool onTitlebar =
2375 frame().insideTitlebar( be.window ) && 2376 frame().insideTitlebar( be.window ) &&
2376 frame().handle().window() != be.window; 2377 frame().handle().window() != be.window;
2377 2378
2379#if 0 // disabled
2378 if (onTitlebar && be.button == 1) 2380 if (onTitlebar && be.button == 1)
2379 raise(); 2381 raise();
2382#endif
2380 2383
2381 // check keys file first 2384 // check keys file first
2382 Keys *k = Fluxbox::instance()->keys(); 2385 Keys *k = Fluxbox::instance()->keys();
@@ -2412,19 +2415,27 @@ void FluxboxWindow::buttonPressEvent(XButtonEvent &be) {
2412 2415
2413void FluxboxWindow::buttonReleaseEvent(XButtonEvent &re) { 2416void FluxboxWindow::buttonReleaseEvent(XButtonEvent &re) {
2414 2417
2418 if (m_last_pressed_button == re.button) {
2419 m_last_pressed_button = 0;
2420 }
2421
2415 if (isMoving()) 2422 if (isMoving())
2416 stopMoving(); 2423 stopMoving();
2417 else if (isResizing()) 2424 else if (isResizing())
2418 stopResizing(); 2425 stopResizing();
2419 else if (m_attaching_tab) 2426 else if (m_attaching_tab)
2420 attachTo(re.x_root, re.y_root); 2427 attachTo(re.x_root, re.y_root);
2421 else 2428 else if (!frame().tabcontainer().tryButtonReleaseEvent(re)) {
2422 frame().tabcontainer().tryButtonReleaseEvent(re);
2423 2429
2430 if (m_last_button_x == re.x_root && m_last_button_y == re.y_root) {
2431 Fluxbox::instance()->keys()->doAction(re.type, re.state, re.button, Keys::ON_WINDOW, &winClient(), re.time);
2432 }
2433 }
2424} 2434}
2425 2435
2426 2436
2427void FluxboxWindow::motionNotifyEvent(XMotionEvent &me) { 2437void FluxboxWindow::motionNotifyEvent(XMotionEvent &me) {
2438
2428 if (isMoving() && me.window == parent()) { 2439 if (isMoving() && me.window == parent()) {
2429 me.window = frame().window().window(); 2440 me.window = frame().window().window();
2430 } 2441 }
@@ -2452,6 +2463,13 @@ void FluxboxWindow::motionNotifyEvent(XMotionEvent &me) {
2452 } 2463 }
2453 } 2464 }
2454 2465
2466
2467 // in case someone put MoveX :StartMoving etc into keys, we have
2468 // to activate it before doing the actual motionNotify code
2469 Fluxbox::instance()->keys()->doAction(me.type, me.state, m_last_pressed_button,
2470 inside_titlebar ? Keys::ON_TITLEBAR : Keys::ON_WINDOW,
2471 &winClient(), me.time);
2472
2455 if (moving || ((me.state & Button1Mask) && functions.move && 2473 if (moving || ((me.state & Button1Mask) && functions.move &&
2456 inside_titlebar && !isResizing() && m_attaching_tab == 0)) { 2474 inside_titlebar && !isResizing() && m_attaching_tab == 0)) {
2457 2475
@@ -2818,8 +2836,14 @@ void FluxboxWindow::setDecorationMask(unsigned int mask, bool apply) {
2818} 2836}
2819 2837
2820void FluxboxWindow::startMoving(int x, int y) { 2838void FluxboxWindow::startMoving(int x, int y) {
2821 if (s_num_grabs > 0) 2839
2840 if (isMoving()) {
2841 return;
2842 }
2843
2844 if (s_num_grabs > 0) {
2822 return; 2845 return;
2846 }
2823 2847
2824 if (isMaximized() && screen().getMaxDisableMove()) 2848 if (isMaximized() && screen().getMaxDisableMove())
2825 return; 2849 return;
@@ -3062,6 +3086,7 @@ void FluxboxWindow::doSnapping(int &orig_left, int &orig_top) {
3062 3086
3063FluxboxWindow::ReferenceCorner FluxboxWindow::getResizeDirection(int x, int y, 3087FluxboxWindow::ReferenceCorner FluxboxWindow::getResizeDirection(int x, int y,
3064 ResizeModel model) const { 3088 ResizeModel model) const {
3089
3065 int cx = frame().width() / 2; 3090 int cx = frame().width() / 2;
3066 int cy = frame().height() / 2; 3091 int cy = frame().height() / 2;
3067 if (model == CENTERRESIZE) 3092 if (model == CENTERRESIZE)
@@ -3088,6 +3113,9 @@ FluxboxWindow::ReferenceCorner FluxboxWindow::getResizeDirection(int x, int y,
3088 3113
3089void FluxboxWindow::startResizing(int x, int y, ReferenceCorner dir) { 3114void FluxboxWindow::startResizing(int x, int y, ReferenceCorner dir) {
3090 3115
3116 if (isResizing())
3117 return;
3118
3091 if (s_num_grabs > 0 || isShaded() || isIconic() ) 3119 if (s_num_grabs > 0 || isShaded() || isIconic() )
3092 return; 3120 return;
3093 3121
@@ -3550,7 +3578,7 @@ void FluxboxWindow::updateButtons() {
3550 need_update = true; 3578 need_update = true;
3551 } 3579 }
3552 } 3580 }
3553 3581
3554 } 3582 }
3555 3583
3556 if (!need_update) 3584 if (!need_update)
@@ -3680,6 +3708,7 @@ void FluxboxWindow::grabPointer(Window grab_window,
3680 Window confine_to, 3708 Window confine_to,
3681 Cursor cursor, 3709 Cursor cursor,
3682 Time time) { 3710 Time time) {
3711
3683 XGrabPointer(FbTk::App::instance()->display(), 3712 XGrabPointer(FbTk::App::instance()->display(),
3684 grab_window, 3713 grab_window,
3685 owner_events, 3714 owner_events,
@@ -3870,7 +3899,7 @@ void FluxboxWindow::setWindowType(WindowState::WindowType type) {
3870 */ 3899 */
3871} 3900}
3872 3901
3873void FluxboxWindow::focusedWindowChanged(BScreen &screen, 3902void FluxboxWindow::focusedWindowChanged(BScreen &screen,
3874 FluxboxWindow *focused_win, WinClient* client) { 3903 FluxboxWindow *focused_win, WinClient* client) {
3875 if (focused_win) { 3904 if (focused_win) {
3876 setFullscreenLayer(); 3905 setFullscreenLayer();
diff --git a/src/Window.hh b/src/Window.hh
index 92d20d7..9cefd55 100644
--- a/src/Window.hh
+++ b/src/Window.hh
@@ -547,6 +547,7 @@ private:
547 int m_last_resize_x, m_last_resize_y; // handles last button press event for resize 547 int m_last_resize_x, m_last_resize_y; // handles last button press event for resize
548 int m_last_move_x, m_last_move_y; // handles last pos for non opaque moving 548 int m_last_move_x, m_last_move_y; // handles last pos for non opaque moving
549 int m_last_resize_h, m_last_resize_w; // handles height/width for resize "window" 549 int m_last_resize_h, m_last_resize_w; // handles height/width for resize "window"
550 int m_last_pressed_button;
550 551
551 timeval m_last_keypress_time; 552 timeval m_last_keypress_time;
552 553