1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
4 # include "../config.h"
12 #include "otk/display.hh"
18 #define _(str) gettext(str)
25 static bool buttonvalue(const std::string
&button
, unsigned int *val
)
27 if (button
== "Left" || button
== "1" || button
== "Button1") {
29 } else if (button
== "Middle" || button
== "2" || button
== "Button2") {
31 } else if (button
== "Right" || button
== "3" || button
== "Button3") {
33 } else if (button
== "Up" || button
== "4" || button
== "Button4") {
35 } else if (button
== "Down" || button
== "5" || button
== "Button5") {
42 static bool modvalue(const std::string
&mod
, unsigned int *val
)
44 if (mod
== "C") { // control
46 } else if (mod
== "S") { // shift
48 } else if (mod
== "A" || // alt/mod1
53 } else if (mod
== "Mod2" || // mod2
56 } else if (mod
== "Mod3" || // mod3
59 } else if (mod
== "W" || // windows/mod4
63 } else if (mod
== "Mod5" || // mod5
72 bool Bindings::translate(const std::string
&str
, Binding
&b
,bool askey
) const
74 // parse out the base key name
75 std::string::size_type keybegin
= str
.find_last_of('-');
76 keybegin
= (keybegin
== std::string::npos
) ? 0 : keybegin
+ 1;
77 std::string
key(str
, keybegin
);
79 // parse out the requested modifier keys
80 unsigned int modval
= 0;
81 std::string::size_type begin
= 0, end
;
82 while (begin
!= keybegin
) {
83 end
= str
.find_first_of('-', begin
);
85 std::string
mod(str
, begin
, end
-begin
);
86 if (!modvalue(mod
, &modval
)) {
87 printf(_("Invalid modifier element in key binding: %s\n"), mod
.c_str());
97 KeySym sym
= XStringToKeysym(const_cast<char *>(key
.c_str()));
98 if (sym
== NoSymbol
) {
99 printf(_("Invalid Key name in key binding: %s\n"), key
.c_str());
102 if (!(b
.key
= XKeysymToKeycode(**otk::display
, sym
)))
103 printf(_("No valid keycode for Key in key binding: %s\n"), key
.c_str());
106 return buttonvalue(key
, &b
.key
);
110 static void destroytree(KeyBindingTree
*tree
)
113 KeyBindingTree
*c
= tree
->first_child
;
119 KeyBindingTree
*Bindings::buildtree(const StringVect
&keylist
,
120 KeyCallback callback
, void *data
) const
122 if (keylist
.empty()) return 0; // nothing in the list.. return 0
124 KeyBindingTree
*ret
= 0, *p
;
126 StringVect::const_reverse_iterator it
, end
= keylist
.rend();
127 for (it
= keylist
.rbegin(); it
!= end
; ++it
) {
129 ret
= new KeyBindingTree();
131 // this is the first built node, the bottom node of the tree
133 ret
->callbacks
.push_back(KeyCallbackData(callback
, data
));
135 ret
->first_child
= p
;
136 if (!translate(*it
, ret
->binding
)) {
147 : _curpos(&_keytree
),
149 _timer((otk::Timer
*) 0),
150 _keybgrab_callback(0, 0)
152 // setResetKey("C-g"); // set the default reset key
156 Bindings::~Bindings()
162 //removeAllButtons(); // this is done by each client as they are unmanaged
167 void Bindings::assimilate(KeyBindingTree
*node
)
169 KeyBindingTree
*a
, *b
, *tmp
, *last
;
171 if (!_keytree
.first_child
) {
172 // there are no nodes at this level yet
173 _keytree
.first_child
= node
;
175 a
= _keytree
.first_child
;
180 if (a
->binding
!= b
->binding
) {
189 if (last
->binding
!= b
->binding
)
190 last
->next_sibling
= b
;
192 last
->first_child
= b
->first_child
;
199 KeyBindingTree
*Bindings::find(KeyBindingTree
*search
,
200 bool *conflict
) const {
202 KeyBindingTree
*a
, *b
;
203 a
= _keytree
.first_child
;
206 if (a
->binding
!= b
->binding
) {
209 if (a
->chain
== b
->chain
) {
211 // found it! (return the actual id, not the search's)
216 return 0; // the chain status' don't match (conflict!)
222 return 0; // it just isn't in here
226 bool Bindings::addKey(const StringVect
&keylist
, KeyCallback callback
,
229 KeyBindingTree
*tree
, *t
;
232 if (!(tree
= buildtree(keylist
, callback
, data
)))
233 return false; // invalid binding requested
235 t
= find(tree
, &conflict
);
237 // conflicts with another binding
243 // already bound to something
244 t
->callbacks
.push_back(KeyCallbackData(callback
, data
));
247 // grab the server here to make sure no key pressed go missed
248 otk::display
->grab();
251 // assimilate this built tree into the main tree
252 assimilate(tree
); // assimilation destroys/uses the tree
255 otk::display
->ungrab();
262 bool Bindings::removeKey(const StringVect &keylist, KeyCallback callback, void *data)
264 assert(false); // XXX: function not implemented yet
266 KeyBindingTree *tree;
269 if (!(tree = buildtree(keylist, 0)))
270 return false; // invalid binding requested
272 KeyBindingTree *t = find(tree, &conflict);
274 KeyCallbackList::iterator it = std::find(t->callbacks.begin(),
277 if (it != t->callbacks.end()) {
278 // grab the server here to make sure no key pressed go missed
279 otk::display->grab();
284 // XXX do shit here ...
288 otk::display->ungrab();
297 void Bindings::setResetKey(const std::string
&key
)
300 if (translate(key
, b
)) {
301 // grab the server here to make sure no key pressed go missed
302 otk::display
->grab();
304 _resetkey
.key
= b
.key
;
305 _resetkey
.modifiers
= b
.modifiers
;
307 otk::display
->ungrab();
312 static void remove_branch(KeyBindingTree
*first
)
314 KeyBindingTree
*p
= first
;
318 remove_branch(p
->first_child
);
319 KeyBindingTree
*s
= p
->next_sibling
;
320 while(!p
->callbacks
.empty()) {
321 p
->callbacks
.pop_front();
329 void Bindings::removeAllKeys()
332 if (_keytree
.first_child
) {
333 remove_branch(_keytree
.first_child
);
334 _keytree
.first_child
= 0;
340 void Bindings::grabKeys(bool grab
)
342 for (int i
= 0; i
< ScreenCount(**otk::display
); ++i
) {
343 Screen
*sc
= openbox
->screen(i
);
344 if (!sc
) continue; // not a managed screen
345 Window root
= otk::display
->screenInfo(i
)->rootWindow();
347 KeyBindingTree
*p
= _curpos
->first_child
;
350 otk::display
->grabKey(p
->binding
.key
, p
->binding
.modifiers
,
351 root
, false, GrabModeAsync
, GrabModeAsync
,
355 otk::display
->ungrabKey(p
->binding
.key
, p
->binding
.modifiers
,
362 otk::display
->grabKey(_resetkey
.key
, _resetkey
.modifiers
,
363 root
, false, GrabModeAsync
, GrabModeAsync
,
366 otk::display
->ungrabKey(_resetkey
.key
, _resetkey
.modifiers
,
372 bool Bindings::grabKeyboard(int screen
, KeyCallback callback
, void *data
)
375 if (_keybgrab_callback
.callback
) return false; // already grabbed
377 if (!openbox
->screen(screen
))
378 return false; // the screen is not managed
380 Window root
= otk::display
->screenInfo(screen
)->rootWindow();
381 if (XGrabKeyboard(**otk::display
, root
, false, GrabModeAsync
,
382 GrabModeAsync
, CurrentTime
))
384 _keybgrab_callback
.callback
= callback
;
385 _keybgrab_callback
.data
= data
;
390 void Bindings::ungrabKeyboard()
392 if (!_keybgrab_callback
.callback
) return; // not grabbed
394 _keybgrab_callback
= KeyCallbackData(0, 0);
395 XUngrabKeyboard(**otk::display
, CurrentTime
);
396 XUngrabPointer(**otk::display
, CurrentTime
);
400 bool Bindings::grabPointer(int screen
)
402 if (!openbox
->screen(screen
))
403 return false; // the screen is not managed
405 Window root
= otk::display
->screenInfo(screen
)->rootWindow();
406 XGrabPointer(**otk::display
, root
, false, 0, GrabModeAsync
,
407 GrabModeAsync
, None
, None
, CurrentTime
);
412 void Bindings::ungrabPointer()
414 XUngrabPointer(**otk::display
, CurrentTime
);
418 void Bindings::fireKey(int screen
, unsigned int modifiers
, unsigned int key
,
419 Time time
, KeyAction::KA action
)
421 if (_keybgrab_callback
.callback
) {
422 Client
*c
= openbox
->focusedClient();
423 KeyData
data(screen
, c
, time
, modifiers
, key
, action
);
424 _keybgrab_callback
.fire(&data
);
427 // KeyRelease events only occur during keyboard grabs
428 if (action
== KeyAction::Release
) return;
430 if (key
== _resetkey
.key
&& modifiers
== _resetkey
.modifiers
) {
433 KeyBindingTree
*p
= _curpos
->first_child
;
435 if (p
->binding
.key
== key
&& p
->binding
.modifiers
== modifiers
) {
439 _timer
= new otk::Timer(5000, // 5 second timeout
440 (otk::Timer::TimeoutHandler
)resetChains
,
442 // grab the server here to make sure no key presses get missed
443 otk::display
->grab();
447 otk::display
->ungrab();
449 Client
*c
= openbox
->focusedClient();
450 KeyData
data(screen
, c
, time
, modifiers
, key
, action
);
451 KeyCallbackList::iterator it
, end
= p
->callbacks
.end();
452 for (it
= p
->callbacks
.begin(); it
!= end
; ++it
)
463 void Bindings::resetChains(Bindings
*self
)
467 self
->_timer
= (otk::Timer
*) 0;
469 // grab the server here to make sure no key pressed go missed
470 otk::display
->grab();
471 self
->grabKeys(false);
472 self
->_curpos
= &self
->_keytree
;
473 self
->grabKeys(true);
474 otk::display
->ungrab();
478 bool Bindings::addButton(const std::string
&but
, MouseContext::MC context
,
479 MouseAction::MA action
, MouseCallback callback
,
482 assert(context
>= 0 && context
< MouseContext::NUM_MOUSE_CONTEXT
);
483 assert(action
>= 0 && action
< MouseAction::NUM_MOUSE_ACTION
);
486 if (!translate(but
, b
, false))
489 ButtonBindingList::iterator it
, end
= _buttons
[context
].end();
491 // look for a duplicate binding
492 for (it
= _buttons
[context
].begin(); it
!= end
; ++it
)
493 if ((*it
)->binding
.key
== b
.key
&&
494 (*it
)->binding
.modifiers
== b
.modifiers
) {
500 // the binding didnt exist yet, add it
502 bind
= new ButtonBinding();
503 bind
->binding
.key
= b
.key
;
504 bind
->binding
.modifiers
= b
.modifiers
;
505 _buttons
[context
].push_back(bind
);
506 // grab the button on all clients
507 for (int sn
= 0; sn
< ScreenCount(**otk::display
); ++sn
) {
508 Screen
*s
= openbox
->screen(sn
);
509 if (!s
) continue; // not managed
510 Client::List::iterator c_it
, c_end
= s
->clients
.end();
511 for (c_it
= s
->clients
.begin(); c_it
!= c_end
; ++c_it
) {
512 grabButton(true, bind
->binding
, context
, *c_it
);
517 bind
->callbacks
[action
].push_back(MouseCallbackData(callback
, data
));
521 void Bindings::removeAllButtons()
523 for (int i
= 0; i
< MouseContext::NUM_MOUSE_CONTEXT
; ++i
) {
524 ButtonBindingList::iterator it
, end
= _buttons
[i
].end();
525 for (it
= _buttons
[i
].begin(); it
!= end
; ++it
) {
526 for (int a
= 0; a
< MouseAction::NUM_MOUSE_ACTION
; ++a
) {
527 while (!(*it
)->callbacks
[a
].empty()) {
528 (*it
)->callbacks
[a
].pop_front();
531 // ungrab the button on all clients
532 for (int sn
= 0; sn
< ScreenCount(**otk::display
); ++sn
) {
533 Screen
*s
= openbox
->screen(sn
);
534 if (!s
) continue; // not managed
535 Client::List::iterator c_it
, c_end
= s
->clients
.end();
536 for (c_it
= s
->clients
.begin(); c_it
!= c_end
; ++c_it
) {
537 grabButton(false, (*it
)->binding
, (MouseContext::MC
)i
, *c_it
);
544 void Bindings::grabButton(bool grab
, const Binding
&b
,
545 MouseContext::MC context
, Client
*client
)
548 int mode
= GrabModeAsync
;
551 case MouseContext::Frame
:
552 win
= client
->frame
->window();
553 mask
= ButtonPressMask
| ButtonMotionMask
| ButtonReleaseMask
;
555 case MouseContext::Window
:
556 win
= client
->frame
->plate();
557 mode
= GrabModeSync
; // this is handled in fireButton
558 mask
= ButtonPressMask
; // can't catch more than this with Sync mode
559 // the release event is manufactured by the
560 // master buttonPressHandler
563 // any other elements already get button events, don't grab on them
567 otk::display
->grabButton(b
.key
, b
.modifiers
, win
, false, mask
, mode
,
568 GrabModeAsync
, None
, None
, false);
570 otk::display
->ungrabButton(b
.key
, b
.modifiers
, win
);
573 void Bindings::grabButtons(bool grab
, Client
*client
)
575 for (int i
= 0; i
< MouseContext::NUM_MOUSE_CONTEXT
; ++i
) {
576 ButtonBindingList::iterator it
, end
= _buttons
[i
].end();
577 for (it
= _buttons
[i
].begin(); it
!= end
; ++it
)
578 grabButton(grab
, (*it
)->binding
, (MouseContext::MC
)i
, client
);
582 void Bindings::fireButton(MouseData
*data
)
584 if (data
->context
== MouseContext::Window
) {
585 // Replay the event, so it goes to the client
586 XAllowEvents(**otk::display
, ReplayPointer
, data
->time
);
589 ButtonBindingList::iterator it
, end
= _buttons
[data
->context
].end();
590 for (it
= _buttons
[data
->context
].begin(); it
!= end
; ++it
)
591 if ((*it
)->binding
.key
== data
->button
&&
592 (*it
)->binding
.modifiers
== data
->state
) {
593 MouseCallbackList::iterator c_it
,
594 c_end
= (*it
)->callbacks
[data
->action
].end();
595 for (c_it
= (*it
)->callbacks
[data
->action
].begin();
596 c_it
!= c_end
; ++c_it
)
602 bool Bindings::addEvent(EventAction::EA action
, EventCallback callback
,
605 if (action
< 0 || action
>= EventAction::NUM_EVENT_ACTION
) {
609 if (action
== EventAction::Bell
&& _eventlist
[action
].empty())
610 XkbSelectEvents(**otk::display
, XkbUseCoreKbd
,
611 XkbBellNotifyMask
, XkbBellNotifyMask
);
613 _eventlist
[action
].push_back(EventCallbackData(callback
, data
));
617 bool Bindings::removeEvent(EventAction::EA action
, EventCallback callback
,
620 if (action
< 0 || action
>= EventAction::NUM_EVENT_ACTION
) {
624 EventCallbackList::iterator it
= std::find(_eventlist
[action
].begin(),
625 _eventlist
[action
].end(),
626 EventCallbackData(callback
,
628 if (it
!= _eventlist
[action
].end()) {
629 _eventlist
[action
].erase(it
);
631 if (action
== EventAction::Bell
&& _eventlist
[action
].empty())
632 XkbSelectEvents(**otk::display
, XkbUseCoreKbd
,
633 XkbBellNotifyMask
, 0);
640 void Bindings::removeAllEvents()
642 for (int i
= 0; i
< EventAction::NUM_EVENT_ACTION
; ++i
) {
643 while (!_eventlist
[i
].empty()) {
644 _eventlist
[i
].pop_front();
649 void Bindings::fireEvent(EventData
*data
)
651 EventCallbackList::iterator c_it
, c_end
= _eventlist
[data
->action
].end();
652 for (c_it
= _eventlist
[data
->action
].begin(); c_it
!= c_end
; ++c_it
)