all repos — fluxbox @ 46261a8284730a16d664fa89423fc5728ed284b4

custom fork of the fluxbox windowmanager

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
Mathias Gumz akira at fluxbox dot org
commit

46261a8284730a16d664fa89423fc5728ed284b4

parent

79859c94482e4602eb22c35b988027ab199734a6

M ChangeLogChangeLog

@@ -1,6 +1,10 @@

(Format: Year/Month/Day) Changes for 1.1.2 +*09/12/18: + * Implemented new 'MoveN' and 'ClickN' support for keys file (Mathias) + Keys.cc Window.cc/hh CurrentWindowCmd.cc FbTk/KeyUtil.cc + *09/12/15: * Updated fluxbox-keys documentation, added 'Fullscreen' (thanx Paul Tagliamonte)
M doc/asciidoc/fluxbox-keys.txtdoc/asciidoc/fluxbox-keys.txt

@@ -55,7 +55,7 @@

where *Mod1* is the Alt key on the PC keyboard and *Mod4* is usually a key branded with a familiar company logo. -There are also some special modifiers that refer to mouse button presses::: +There are also some special modifiers that refer to mouse button events::: *OnDesktop*;; The mouse cursor is over the desktop (root window), and not any window.

@@ -84,13 +84,21 @@ 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 *xev(1)*, you can just use the keycode (NOT the keysym!) in your keys file. -Commands can also be bound to mouse button presses, for which the proper "key" -name is *Mouse*'n' where 'n' is the number of the mouse button. For example, -*Mouse1* is the primary button, and *Mouse4* / *Mouse5* are the scroll wheel -events, in normal configurations. *xev(1)* can also be used to tell the button -number. +Commands can also be bound to mouse events ('N' denotes the number of the +button, eg. '1' is the primary button, '4'/'5' are the wheel buttons): -There are some special "keys" that let you bind events to non-keyboard events::: +*MouseN*;; + The mouse button 'N' is pressed down and holded. +*ClickN*;; + The mouse button 'N' is clicked (pressed and released with no + movement in between) +*MoveN*;; + The mouse button 'N' is currently holded, the binded action is triggered + as often as the mouse moves. + + +There are some special "keys" that let you bind events to non-keyboard events: + *ChangeWorkspace*;; Fires when the workspace changes. This can be used to change backgrounds or do anything else you like when you switch to a new workspace. See the
M doc/fluxbox-keys.5.indoc/fluxbox-keys.5.in

@@ -2,12 +2,12 @@ '\" t

.\" Title: fluxbox-keys .\" Author: [see the "AUTHORS" section] .\" Generator: DocBook XSL Stylesheets v1.75.1 <http://docbook.sf.net/> -.\" Date: 12/14/2009 +.\" Date: 12/17/2009 .\" Manual: Fluxbox Manual .\" Source: fluxbox-keys.txt .\" Language: English .\" -.TH "FLUXBOX\-KEYS" "5" "12/14/2009" "fluxbox\-keys\&.txt" "Fluxbox Manual" +.TH "FLUXBOX\-KEYS" "5" "12/17/2009" "fluxbox\-keys\&.txt" "Fluxbox Manual" .\" ----------------------------------------------------------------- .\" * set default formatting .\" -----------------------------------------------------------------

@@ -53,7 +53,7 @@ \fBShift Control Mod1 Mod4\fR

.sp where \fBMod1\fR is the Alt key on the PC keyboard and \fBMod4\fR is usually a key branded with a familiar company logo\&. .PP -There are also some special modifiers that refer to mouse button presses +There are also some special modifiers that refer to mouse button events .RS 4 .PP \fBOnDesktop\fR

@@ -90,17 +90,36 @@ You may specify a key by its key name (for example, \fBa\fR or \fBspace\fR) or by its numeric keycode (for example, \fB38\fR or \fB0xf3\fR)\&.

.sp If 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\&. .sp -Commands 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\&. +Commands 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): +.PP +\fBMouseN\fR +.RS 4 +The mouse button +\fIN\fR +is pressed down and holded\&. +.RE +.PP +\fBClickN\fR +.RS 4 +The mouse button +\fIN\fR +is clicked (pressed and released with no movement in between) +.RE .PP -There are some special "keys" that let you bind events to non\-keyboard events +\fBMoveN\fR .RS 4 +The mouse button +\fIN\fR +is currently holded, the binded action is triggered as often as the mouse moves\&. +.RE +.sp +There are some special "keys" that let you bind events to non\-keyboard events: .PP \fBChangeWorkspace\fR .RS 4 Fires when the workspace changes\&. This can be used to change backgrounds or do anything else you like when you switch to a new workspace\&. See the \fBEXAMPLES\fR below for one idea\&. -.RE .RE .if n \{\ .sp
M src/CurrentWindowCmd.ccsrc/CurrentWindowCmd.cc

@@ -262,11 +262,26 @@

REGISTER_COMMAND(startmoving, StartMovingCmd, void); void StartMovingCmd::real_execute() { + + int x; + int y; const XEvent &last = Fluxbox::instance()->lastEvent(); - if (last.type == ButtonPress) { - const XButtonEvent &be = last.xbutton; - fbwindow().startMoving(be.x_root, be.y_root); + switch (last.type) { + case ButtonPress: + x = last.xbutton.x_root; + y = last.xbutton.y_root; + break; + + case MotionNotify: + x = last.xmotion.x_root; + y = last.xmotion.y_root; + break; + + default: + return; } + + fbwindow().startMoving(x, y); } FbTk::Command<void> *StartResizingCmd::parse(const string &cmd, const string &args,

@@ -305,15 +320,27 @@

REGISTER_COMMAND_PARSER(startresizing, StartResizingCmd::parse, void); void StartResizingCmd::real_execute() { + + int x; + int y; const XEvent &last = Fluxbox::instance()->lastEvent(); - if (last.type == ButtonPress) { - const XButtonEvent &be = last.xbutton; - int x = be.x_root - fbwindow().x() - - fbwindow().frame().window().borderWidth(); - int y = be.y_root - fbwindow().y() - - fbwindow().frame().window().borderWidth(); - fbwindow().startResizing(x, y, fbwindow().getResizeDirection(x, y, m_mode)); + switch (last.type) { + case ButtonPress: + x = last.xbutton.x_root; + y = last.xbutton.y_root; + break; + case MotionNotify: + x = last.xmotion.x_root; + y = last.xmotion.y_root; + break; + default: + return; } + + x -= fbwindow().x() - fbwindow().frame().window().borderWidth(); + y -= fbwindow().y() - fbwindow().frame().window().borderWidth(); + + fbwindow().startResizing(x, y, fbwindow().getResizeDirection(x, y, m_mode)); } REGISTER_COMMAND(starttabbing, StartTabbingCmd, void);
M src/FbTk/KeyUtil.ccsrc/FbTk/KeyUtil.cc

@@ -42,16 +42,16 @@ }

}; const struct t_modlist modlist[] = { - {"SHIFT", ShiftMask}, - {"LOCK", LockMask}, - {"CONTROL", ControlMask}, - {"MOD1", Mod1Mask}, - {"MOD2", Mod2Mask}, - {"MOD3", Mod3Mask}, - {"MOD4", Mod4Mask}, - {"MOD5", Mod5Mask}, - {"ALT", Mod1Mask}, - {"CTRL", ControlMask}, + {"shift", ShiftMask}, + {"lock", LockMask}, + {"control", ControlMask}, + {"mod1", Mod1Mask}, + {"mod2", Mod2Mask}, + {"mod3", Mod3Mask}, + {"mod4", Mod4Mask}, + {"mod5", Mod5Mask}, + {"alt", Mod1Mask}, + {"ctrl", ControlMask}, {0, 0} };

@@ -88,7 +88,7 @@ if (m_modmap)

XFreeModifiermap(m_modmap); m_modmap = XGetModifierMapping(App::instance()->display()); - + // find modifiers and set them for (int i=0, realkey=0; i<8; ++i) { for (int key=0; key<m_modmap->max_keypermod; ++key, ++realkey) {

@@ -96,7 +96,7 @@

if (m_modmap->modifiermap[realkey] == 0) continue; - KeySym ks = XKeycodeToKeysym(App::instance()->display(), + KeySym ks = XKeycodeToKeysym(App::instance()->display(), m_modmap->modifiermap[realkey], 0); switch (ks) {

@@ -154,12 +154,18 @@ @return keycode of keystr on success else 0

*/ unsigned int KeyUtil::getKey(const char *keystr) { - if (!keystr) - return 0; - KeySym sym = XStringToKeysym(keystr); - if (sym==NoSymbol) - return 0; - return XKeysymToKeycode(App::instance()->display(), sym); + + KeyCode code = 0; + + if (keystr) { + + KeySym sym = XStringToKeysym(keystr); + if (sym != NoSymbol) { + code = XKeysymToKeycode(App::instance()->display(), sym); + } + } + + return code; }

@@ -169,14 +175,14 @@ */

unsigned int KeyUtil::getModifier(const char *modstr) { if (!modstr) return 0; - + // find mod mask string for (unsigned int i=0; modlist[i].str !=0; i++) { - if (modlist[i] == modstr) - return modlist[i].mask; + if (modlist[i] == modstr) + return modlist[i].mask; } - - return 0; + + return 0; } /// Ungrabs the keys

@@ -193,7 +199,7 @@

unsigned int KeyUtil::keycodeToModmask(unsigned int keycode) { XModifierKeymap *modmap = instance().m_modmap; - if (!modmap) + if (!modmap) return 0; // search through modmap for this keycode

@@ -204,7 +210,7 @@ // each max_keypermod long, but in a linear array.

if (modmap->modifiermap[modmap->max_keypermod*mod + key] == keycode) { return modlist[mod].mask; } - } + } } // no luck return 0;
M src/Keys.ccsrc/Keys.cc

@@ -106,6 +106,28 @@ using std::pair;

using FbTk::STLUtil::destroyAndClearSecond; +namespace { + +// candidate for FbTk::StringUtil ? +int extractKeyFromString(const std::string& in, const char* start_pattern, unsigned int& key) { + + int ret = 0; + + if (strstr(in.c_str(), start_pattern) != 0) { + + unsigned int tmp_key = 0; + if (FbTk::StringUtil::extractNumber(in.substr(strlen(start_pattern)), tmp_key)) { + + key = tmp_key; + ret = 1; + } + } + + return ret; +} + +} // end of anonymouse namespace + // helper class 'keytree' class Keys::t_key { public:

@@ -254,10 +276,12 @@ // keys are only grabbed in global context

if ((win_it->second & Keys::GLOBAL) > 0 && (*it)->type == KeyPress) FbTk::KeyUtil::grabKey((*it)->key, (*it)->mod, win); // ON_DESKTOP buttons don't need to be grabbed - else if ((win_it->second & (*it)->context & ~Keys::ON_DESKTOP) > 0 && - (*it)->type == ButtonPress) - FbTk::KeyUtil::grabButton((*it)->key, (*it)->mod, win, - ButtonPressMask|ButtonReleaseMask); + else if ((win_it->second & (*it)->context & ~Keys::ON_DESKTOP) > 0) { + + if ((*it)->type == ButtonPress || (*it)->type == ButtonRelease || (*it)->type == MotionNotify) { + FbTk::KeyUtil::grabButton((*it)->key, (*it)->mod, win, ButtonPressMask|ButtonReleaseMask|ButtonMotionMask); + } + } } }

@@ -363,85 +387,84 @@ }

// for each argument for (; argc < val.size(); argc++) { - if (val[argc][0] != ':') { // parse key(s) + std::string arg = FbTk::StringUtil::toLower(val[argc]); - int tmpmod = FbTk::KeyUtil::getModifier(val[argc].c_str()); + if (arg[0] != ':') { // parse key(s) + + int tmpmod = FbTk::KeyUtil::getModifier(arg.c_str()); if(tmpmod) mod |= tmpmod; //If it's a modifier - else if (strcasecmp("ondesktop", val[argc].c_str()) == 0) + else if (arg == "ondesktop") context |= ON_DESKTOP; - else if (strcasecmp("ontoolbar", val[argc].c_str()) == 0) + else if (arg == "ontoolbar") context |= ON_TOOLBAR; - else if (strcasecmp("onwindow", val[argc].c_str()) == 0) + else if (arg == "onwindow") context |= ON_WINDOW; - else if (strcasecmp("ontitlebar", val[argc].c_str()) == 0) + else if (arg == "ontitlebar") context |= ON_TITLEBAR; - else if (strcasecmp("double", val[argc].c_str()) == 0) + else if (arg == "double") isdouble = true; - else if (strcasecmp("NONE",val[argc].c_str())) { - // check if it's a mouse button - if (strcasecmp("focusin", val[argc].c_str()) == 0) { + else if (arg != "none") { + if (arg == "focusin") { context = ON_WINDOW; mod = key = 0; type = FocusIn; - } else if (strcasecmp("focusout", val[argc].c_str()) == 0) { + } else if (arg == "focusout") { context = ON_WINDOW; mod = key = 0; type = FocusOut; - } else if (strcasecmp("changeworkspace", - val[argc].c_str()) == 0) { + } else if (arg == "changeworkspace") { context = ON_DESKTOP; mod = key = 0; type = FocusIn; - } else if (strcasecmp("mouseover", val[argc].c_str()) == 0) { + } else if (arg == "mouseover") { type = EnterNotify; if (!(context & (ON_WINDOW|ON_TOOLBAR))) context |= ON_WINDOW; key = 0; - } else if (strcasecmp("mouseout", val[argc].c_str()) == 0) { + } else if (arg == "mouseout") { type = LeaveNotify; if (!(context & (ON_WINDOW|ON_TOOLBAR))) context |= ON_WINDOW; key = 0; - } else if (strcasecmp(val[argc].substr(0,5).c_str(), - "mouse") == 0 && - val[argc].length() > 5) { + + // check if it's a mouse button + } else if (extractKeyFromString(arg, "mouse", key)) { type = ButtonPress; - key = atoi(val[argc].substr(5, - val[argc].length()-5).c_str()); + // fluxconf mangles things like OnWindow Mouse# to Mouse#ow - if (strstr(val[argc].c_str(), "top")) + if (strstr(arg.c_str(), "top")) context = ON_DESKTOP; - else if (strstr(val[argc].c_str(), "ebar")) + else if (strstr(arg.c_str(), "ebar")) context = ON_TITLEBAR; - else if (strstr(val[argc].c_str(), "bar")) + else if (strstr(arg.c_str(), "bar")) context = ON_TOOLBAR; - else if (strstr(val[argc].c_str(), "ow")) + else if (strstr(arg.c_str(), "ow")) context = ON_WINDOW; + } else if (extractKeyFromString(arg, "click", key)) { + type = ButtonRelease; + } else if (extractKeyFromString(arg, "move", key)) { + type = MotionNotify; + + } else if (key = FbTk::KeyUtil::getKey(val[argc].c_str())) { // convert from string symbol + type = KeyPress; + // keycode covers the following three two-byte cases: // 0x - hex // +[1-9] - number between +1 and +9 // numbers 10 and above // - } else if (!val[argc].empty() && ((isdigit(val[argc][0]) && - (isdigit(val[argc][1]) || val[argc][1] == 'x')) || - (val[argc][0] == '+' && isdigit(val[argc][1])))) { - - key = strtoul(val[argc].c_str(), NULL, 0); - type = KeyPress; - - if (errno == EINVAL || errno == ERANGE) - key = 0; - - } else { // convert from string symbol - key = FbTk::KeyUtil::getKey(val[argc].c_str()); + } else { + FbTk::StringUtil::extractNumber(arg, key); type = KeyPress; } - if (key == 0 && (type == KeyPress || type == ButtonPress)) + if (key == 0 && (type == KeyPress || type == ButtonPress || type == ButtonRelease)) return false; + if (type != ButtonPress) isdouble = false; + if (!first_new_key) { first_new_keylist = current_key; current_key = current_key->find(type, mod, key, context,

@@ -470,7 +493,7 @@ if (!first_new_key)

return false; const char *str = FbTk::StringUtil::strcasestr(linebuffer.c_str(), - val[argc].c_str()); + val[argc].c_str()); if (str) // +1 to skip ':' current_key->m_command = FbTk::CommandParser<void>::instance().parse(str + 1);

@@ -504,10 +527,11 @@ // actual value used for searching

bool isdouble = false; if (type == ButtonPress) { - if (time > last_button_time) + if (time > last_button_time) { double_click = (time - last_button_time < Fluxbox::instance()->getDoubleClickInterval()) && last_button == key; + } last_button_time = time; last_button = key; isdouble = double_click;
M src/Window.ccsrc/Window.cc

@@ -280,6 +280,7 @@ display(FbTk::App::instance()->display()),

m_button_grab_x(0), m_button_grab_y(0), m_last_move_x(0), m_last_move_y(0), m_last_resize_h(1), m_last_resize_w(1), + m_last_pressed_button(0), m_workspace_number(0), m_current_state(0), m_old_decoration_mask(0),

@@ -1073,7 +1074,6 @@ frame().window().window(), True, ButtonPressMask,

GrabModeSync, GrabModeSync, None, None); XUngrabButton(display, Button1, Mod1Mask|Mod2Mask|Mod3Mask, frame().window().window()); - }

@@ -1478,7 +1478,7 @@

FluxboxWindow *foc = FocusControl::focusedFbWindow(); // if another window on the same head is focused, make sure we can see it if (isFocused() || !foc || &foc->screen() != &screen() || - getOnHead() != foc->getOnHead() || + getOnHead() != foc->getOnHead() || (foc->winClient().isTransient() && foc->winClient().transientFor()->fbwindow() == this)) { moveToLayer(::Layer::ABOVE_DOCK);

@@ -2370,13 +2370,16 @@

void FluxboxWindow::buttonPressEvent(XButtonEvent &be) { m_last_button_x = be.x_root; m_last_button_y = be.y_root; + m_last_pressed_button = be.button; bool onTitlebar = frame().insideTitlebar( be.window ) && frame().handle().window() != be.window; +#if 0 // disabled if (onTitlebar && be.button == 1) raise(); +#endif // check keys file first Keys *k = Fluxbox::instance()->keys();

@@ -2411,6 +2414,10 @@ }

} void FluxboxWindow::buttonReleaseEvent(XButtonEvent &re) { + + if (m_last_pressed_button == re.button) { + m_last_pressed_button = 0; + } if (isMoving()) stopMoving();

@@ -2418,13 +2425,17 @@ else if (isResizing())

stopResizing(); else if (m_attaching_tab) attachTo(re.x_root, re.y_root); - else - frame().tabcontainer().tryButtonReleaseEvent(re); + else if (!frame().tabcontainer().tryButtonReleaseEvent(re)) { + if (m_last_button_x == re.x_root && m_last_button_y == re.y_root) { + Fluxbox::instance()->keys()->doAction(re.type, re.state, re.button, Keys::ON_WINDOW, &winClient(), re.time); + } + } } void FluxboxWindow::motionNotifyEvent(XMotionEvent &me) { + if (isMoving() && me.window == parent()) { me.window = frame().window().window(); }

@@ -2452,6 +2463,13 @@ return;

} } + + // in case someone put MoveX :StartMoving etc into keys, we have + // to activate it before doing the actual motionNotify code + Fluxbox::instance()->keys()->doAction(me.type, me.state, m_last_pressed_button, + inside_titlebar ? Keys::ON_TITLEBAR : Keys::ON_WINDOW, + &winClient(), me.time); + if (moving || ((me.state & Button1Mask) && functions.move && inside_titlebar && !isResizing() && m_attaching_tab == 0)) {

@@ -2818,8 +2836,14 @@ applyDecorations();

} void FluxboxWindow::startMoving(int x, int y) { - if (s_num_grabs > 0) + + if (isMoving()) { return; + } + + if (s_num_grabs > 0) { + return; + } if (isMaximized() && screen().getMaxDisableMove()) return;

@@ -3062,6 +3086,7 @@ }

FluxboxWindow::ReferenceCorner FluxboxWindow::getResizeDirection(int x, int y, ResizeModel model) const { + int cx = frame().width() / 2; int cy = frame().height() / 2; if (model == CENTERRESIZE)

@@ -3087,6 +3112,9 @@ return RIGHTBOTTOM;

} void FluxboxWindow::startResizing(int x, int y, ReferenceCorner dir) { + + if (isResizing()) + return; if (s_num_grabs > 0 || isShaded() || isIconic() ) return;

@@ -3550,7 +3578,7 @@ if ((*(*titlebar_side[i]))[j] != m_titlebar_buttons[i][j])

need_update = true; } } - + } if (!need_update)

@@ -3680,6 +3708,7 @@ int pointer_mode, int keyboard_mode,

Window confine_to, Cursor cursor, Time time) { + XGrabPointer(FbTk::App::instance()->display(), grab_window, owner_events,

@@ -3870,7 +3899,7 @@ * _NET_WM_WINDOW_TYPE_UTILITY

*/ } -void FluxboxWindow::focusedWindowChanged(BScreen &screen, +void FluxboxWindow::focusedWindowChanged(BScreen &screen, FluxboxWindow *focused_win, WinClient* client) { if (focused_win) { setFullscreenLayer();
M src/Window.hhsrc/Window.hh

@@ -547,6 +547,7 @@ int m_button_grab_x, m_button_grab_y; // handles last button press event for move

int m_last_resize_x, m_last_resize_y; // handles last button press event for resize int m_last_move_x, m_last_move_y; // handles last pos for non opaque moving int m_last_resize_h, m_last_resize_w; // handles height/width for resize "window" + int m_last_pressed_button; timeval m_last_keypress_time;