00001
00002
00003 #ifdef HAVE_CONFIG_H
00004 # include "../config.h"
00005 #endif
00006
00007 #include "bindings.hh"
00008 #include "screen.hh"
00009 #include "openbox.hh"
00010 #include "client.hh"
00011 #include "frame.hh"
00012 #include "python.hh"
00013 #include "otk/display.hh"
00014
00015 extern "C" {
00016 #include <X11/Xlib.h>
00017
00018 #include "gettext.h"
00019 #define _(str) gettext(str)
00020 }
00021
00022 #include <algorithm>
00023
00024 namespace ob {
00025
00026 static bool buttonvalue(const std::string &button, unsigned int *val)
00027 {
00028 if (button == "Left" || button == "1" || button == "Button1") {
00029 *val |= Button1;
00030 } else if (button == "Middle" || button == "2" || button == "Button2") {
00031 *val |= Button2;
00032 } else if (button == "Right" || button == "3" || button == "Button3") {
00033 *val |= Button3;
00034 } else if (button == "Up" || button == "4" || button == "Button4") {
00035 *val |= Button4;
00036 } else if (button == "Down" || button == "5" || button == "Button5") {
00037 *val |= Button5;
00038 } else
00039 return false;
00040 return true;
00041 }
00042
00043 static bool modvalue(const std::string &mod, unsigned int *val)
00044 {
00045 if (mod == "C") {
00046 *val |= ControlMask;
00047 } else if (mod == "S") {
00048 *val |= ShiftMask;
00049 } else if (mod == "A" ||
00050 mod == "M" ||
00051 mod == "Mod1" ||
00052 mod == "M1") {
00053 *val |= Mod1Mask;
00054 } else if (mod == "Mod2" ||
00055 mod == "M2") {
00056 *val |= Mod2Mask;
00057 } else if (mod == "Mod3" ||
00058 mod == "M3") {
00059 *val |= Mod3Mask;
00060 } else if (mod == "W" ||
00061 mod == "Mod4" ||
00062 mod == "M4") {
00063 *val |= Mod4Mask;
00064 } else if (mod == "Mod5" ||
00065 mod == "M5") {
00066 *val |= Mod5Mask;
00067 } else {
00068 return false;
00069 }
00070 return true;
00071 }
00072
00073 bool Bindings::translate(const std::string &str, Binding &b,bool askey) const
00074 {
00075
00076 std::string::size_type keybegin = str.find_last_of('-');
00077 keybegin = (keybegin == std::string::npos) ? 0 : keybegin + 1;
00078 std::string key(str, keybegin);
00079
00080
00081 unsigned int modval = 0;
00082 std::string::size_type begin = 0, end;
00083 while (begin != keybegin) {
00084 end = str.find_first_of('-', begin);
00085
00086 std::string mod(str, begin, end-begin);
00087 if (!modvalue(mod, &modval)) {
00088 printf(_("Invalid modifier element in key binding: %s\n"), mod.c_str());
00089 return false;
00090 }
00091
00092 begin = end + 1;
00093 }
00094
00095
00096 b.modifiers = modval;
00097 if (askey) {
00098 KeySym sym = XStringToKeysym(const_cast<char *>(key.c_str()));
00099 if (sym == NoSymbol) {
00100 printf(_("Invalid Key name in key binding: %s\n"), key.c_str());
00101 return false;
00102 }
00103 if (!(b.key = XKeysymToKeycode(**otk::display, sym)))
00104 printf(_("No valid keycode for Key in key binding: %s\n"), key.c_str());
00105 return b.key != 0;
00106 } else {
00107 return buttonvalue(key, &b.key);
00108 }
00109 }
00110
00111 static void destroytree(KeyBindingTree *tree)
00112 {
00113 while (tree) {
00114 KeyBindingTree *c = tree->first_child;
00115 delete tree;
00116 tree = c;
00117 }
00118 }
00119
00120 KeyBindingTree *Bindings::buildtree(const StringVect &keylist,
00121 PyObject *callback) const
00122 {
00123 if (keylist.empty()) return 0;
00124
00125 KeyBindingTree *ret = 0, *p;
00126
00127 StringVect::const_reverse_iterator it, end = keylist.rend();
00128 for (it = keylist.rbegin(); it != end; ++it) {
00129 p = ret;
00130 ret = new KeyBindingTree();
00131 if (!p) {
00132
00133 ret->chain = false;
00134 ret->callbacks.push_back(callback);
00135 }
00136 ret->first_child = p;
00137 if (!translate(*it, ret->binding)) {
00138 destroytree(ret);
00139 ret = 0;
00140 break;
00141 }
00142 }
00143 return ret;
00144 }
00145
00146
00147 Bindings::Bindings()
00148 : _curpos(&_keytree),
00149 _resetkey(0,0),
00150 _timer((otk::Timer *) 0),
00151 _keybgrab_callback(0)
00152 {
00153
00154 }
00155
00156
00157 Bindings::~Bindings()
00158 {
00159 if (_timer)
00160 delete _timer;
00161
00162 removeAllKeys();
00163
00164 removeAllEvents();
00165 }
00166
00167
00168 void Bindings::assimilate(KeyBindingTree *node)
00169 {
00170 KeyBindingTree *a, *b, *tmp, *last;
00171
00172 if (!_keytree.first_child) {
00173
00174 _keytree.first_child = node;
00175 } else {
00176 a = _keytree.first_child;
00177 last = a;
00178 b = node;
00179 while (a) {
00180 last = a;
00181 if (a->binding != b->binding) {
00182 a = a->next_sibling;
00183 } else {
00184 tmp = b;
00185 b = b->first_child;
00186 delete tmp;
00187 a = a->first_child;
00188 }
00189 }
00190 if (last->binding != b->binding)
00191 last->next_sibling = b;
00192 else {
00193 last->first_child = b->first_child;
00194 delete b;
00195 }
00196 }
00197 }
00198
00199
00200 KeyBindingTree *Bindings::find(KeyBindingTree *search,
00201 bool *conflict) const {
00202 *conflict = false;
00203 KeyBindingTree *a, *b;
00204 a = _keytree.first_child;
00205 b = search;
00206 while (a && b) {
00207 if (a->binding != b->binding) {
00208 a = a->next_sibling;
00209 } else {
00210 if (a->chain == b->chain) {
00211 if (!a->chain) {
00212
00213 return a;
00214 }
00215 } else {
00216 *conflict = true;
00217 return 0;
00218 }
00219 b = b->first_child;
00220 a = a->first_child;
00221 }
00222 }
00223 return 0;
00224 }
00225
00226
00227 bool Bindings::addKey(const StringVect &keylist, PyObject *callback)
00228 {
00229 KeyBindingTree *tree, *t;
00230 bool conflict;
00231
00232 if (!(tree = buildtree(keylist, callback)))
00233 return false;
00234
00235 t = find(tree, &conflict);
00236 if (conflict) {
00237
00238 destroytree(tree);
00239 return false;
00240 }
00241
00242 if (t) {
00243
00244 t->callbacks.push_back(callback);
00245 destroytree(tree);
00246 } else {
00247
00248 otk::display->grab();
00249 grabKeys(false);
00250
00251
00252 assimilate(tree);
00253
00254 grabKeys(true);
00255 otk::display->ungrab();
00256 }
00257
00258 Py_INCREF(callback);
00259
00260 return true;
00261 }
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299 void Bindings::setResetKey(const std::string &key)
00300 {
00301 Binding b(0, 0);
00302 if (translate(key, b)) {
00303
00304 otk::display->grab();
00305 grabKeys(false);
00306 _resetkey.key = b.key;
00307 _resetkey.modifiers = b.modifiers;
00308 grabKeys(true);
00309 otk::display->ungrab();
00310 }
00311 }
00312
00313
00314 static void remove_branch(KeyBindingTree *first)
00315 {
00316 KeyBindingTree *p = first;
00317
00318 while (p) {
00319 if (p->first_child)
00320 remove_branch(p->first_child);
00321 KeyBindingTree *s = p->next_sibling;
00322 while(!p->callbacks.empty()) {
00323 Py_XDECREF(p->callbacks.front());
00324 p->callbacks.pop_front();
00325 }
00326 delete p;
00327 p = s;
00328 }
00329 }
00330
00331
00332 void Bindings::removeAllKeys()
00333 {
00334 grabKeys(false);
00335 if (_keytree.first_child) {
00336 remove_branch(_keytree.first_child);
00337 _keytree.first_child = 0;
00338 }
00339 grabKeys(true);
00340 }
00341
00342
00343 void Bindings::grabKeys(bool grab)
00344 {
00345 for (int i = 0; i < ScreenCount(**otk::display); ++i) {
00346 Screen *sc = openbox->screen(i);
00347 if (!sc) continue;
00348 Window root = otk::display->screenInfo(i)->rootWindow();
00349
00350 KeyBindingTree *p = _curpos->first_child;
00351 while (p) {
00352 if (grab) {
00353 otk::display->grabKey(p->binding.key, p->binding.modifiers,
00354 root, false, GrabModeAsync, GrabModeAsync,
00355 false);
00356 }
00357 else
00358 otk::display->ungrabKey(p->binding.key, p->binding.modifiers,
00359 root);
00360 p = p->next_sibling;
00361 }
00362
00363 if (_resetkey.key)
00364 if (grab)
00365 otk::display->grabKey(_resetkey.key, _resetkey.modifiers,
00366 root, false, GrabModeAsync, GrabModeAsync,
00367 false);
00368 else
00369 otk::display->ungrabKey(_resetkey.key, _resetkey.modifiers,
00370 root);
00371 }
00372 }
00373
00374
00375 bool Bindings::grabKeyboard(int screen, PyObject *callback)
00376 {
00377 assert(callback);
00378 if (_keybgrab_callback) return false;
00379
00380 if (!openbox->screen(screen))
00381 return false;
00382
00383 Window root = otk::display->screenInfo(screen)->rootWindow();
00384 if (XGrabKeyboard(**otk::display, root, false, GrabModeAsync,
00385 GrabModeAsync, CurrentTime))
00386 return false;
00387 _keybgrab_callback = callback;
00388 return true;
00389 }
00390
00391
00392 void Bindings::ungrabKeyboard()
00393 {
00394 if (!_keybgrab_callback) return;
00395
00396 _keybgrab_callback = 0;
00397 XUngrabKeyboard(**otk::display, CurrentTime);
00398 XUngrabPointer(**otk::display, CurrentTime);
00399 }
00400
00401
00402 bool Bindings::grabPointer(int screen)
00403 {
00404 if (!openbox->screen(screen))
00405 return false;
00406
00407 Window root = otk::display->screenInfo(screen)->rootWindow();
00408 XGrabPointer(**otk::display, root, false, 0, GrabModeAsync,
00409 GrabModeAsync, None, None, CurrentTime);
00410 return true;
00411 }
00412
00413
00414 void Bindings::ungrabPointer()
00415 {
00416 XUngrabPointer(**otk::display, CurrentTime);
00417 }
00418
00419
00420 void Bindings::fireKey(int screen, unsigned int modifiers, unsigned int key,
00421 Time time, KeyAction::KA action)
00422 {
00423 if (_keybgrab_callback) {
00424 Client *c = openbox->focusedClient();
00425 KeyData data(screen, c, time, modifiers, key, action);
00426 python_callback(_keybgrab_callback, &data);
00427 }
00428
00429
00430 if (action == KeyAction::Release) return;
00431
00432 if (key == _resetkey.key && modifiers == _resetkey.modifiers) {
00433 resetChains(this);
00434 } else {
00435 KeyBindingTree *p = _curpos->first_child;
00436 while (p) {
00437 if (p->binding.key == key && p->binding.modifiers == modifiers) {
00438 if (p->chain) {
00439 if (_timer)
00440 delete _timer;
00441 _timer = new otk::Timer(5000,
00442 (otk::Timer::TimeoutHandler)resetChains,
00443 this);
00444
00445 otk::display->grab();
00446 grabKeys(false);
00447 _curpos = p;
00448 grabKeys(true);
00449 otk::display->ungrab();
00450 } else {
00451 Client *c = openbox->focusedClient();
00452 KeyData data(screen, c, time, modifiers, key, action);
00453 CallbackList::iterator it, end = p->callbacks.end();
00454 for (it = p->callbacks.begin(); it != end; ++it)
00455 python_callback(*it, &data);
00456 resetChains(this);
00457 }
00458 break;
00459 }
00460 p = p->next_sibling;
00461 }
00462 }
00463 }
00464
00465 void Bindings::resetChains(Bindings *self)
00466 {
00467 if (self->_timer) {
00468 delete self->_timer;
00469 self->_timer = (otk::Timer *) 0;
00470 }
00471
00472 otk::display->grab();
00473 self->grabKeys(false);
00474 self->_curpos = &self->_keytree;
00475 self->grabKeys(true);
00476 otk::display->ungrab();
00477 }
00478
00479
00480 bool Bindings::addButton(const std::string &but, MouseContext::MC context,
00481 MouseAction::MA action, PyObject *callback)
00482 {
00483 assert(context >= 0 && context < MouseContext::NUM_MOUSE_CONTEXT);
00484 assert(action >= 0 && action < MouseAction::NUM_MOUSE_ACTION);
00485
00486 Binding b(0,0);
00487 if (!translate(but, b, false))
00488 return false;
00489
00490 ButtonBindingList::iterator it, end = _buttons[context].end();
00491
00492
00493 for (it = _buttons[context].begin(); it != end; ++it)
00494 if ((*it)->binding.key == b.key &&
00495 (*it)->binding.modifiers == b.modifiers) {
00496 break;
00497 }
00498
00499 ButtonBinding *bind;
00500
00501
00502 if (it == end) {
00503 bind = new ButtonBinding();
00504 bind->binding.key = b.key;
00505 bind->binding.modifiers = b.modifiers;
00506 _buttons[context].push_back(bind);
00507
00508 for (int sn = 0; sn < ScreenCount(**otk::display); ++sn) {
00509 Screen *s = openbox->screen(sn);
00510 if (!s) continue;
00511 Client::List::iterator c_it, c_end = s->clients.end();
00512 for (c_it = s->clients.begin(); c_it != c_end; ++c_it) {
00513 grabButton(true, bind->binding, context, *c_it);
00514 }
00515 }
00516 } else
00517 bind = *it;
00518 bind->callbacks[action].push_back(callback);
00519 Py_INCREF(callback);
00520 return true;
00521 }
00522
00523 void Bindings::removeAllButtons()
00524 {
00525 for (int i = 0; i < MouseContext::NUM_MOUSE_CONTEXT; ++i) {
00526 ButtonBindingList::iterator it, end = _buttons[i].end();
00527 for (it = _buttons[i].begin(); it != end; ++it) {
00528 for (int a = 0; a < MouseAction::NUM_MOUSE_ACTION; ++a) {
00529 while (!(*it)->callbacks[a].empty()) {
00530 Py_XDECREF((*it)->callbacks[a].front());
00531 (*it)->callbacks[a].pop_front();
00532 }
00533 }
00534
00535 for (int sn = 0; sn < ScreenCount(**otk::display); ++sn) {
00536 Screen *s = openbox->screen(sn);
00537 if (!s) continue;
00538 Client::List::iterator c_it, c_end = s->clients.end();
00539 for (c_it = s->clients.begin(); c_it != c_end; ++c_it) {
00540 grabButton(false, (*it)->binding, (MouseContext::MC)i, *c_it);
00541 }
00542 }
00543 }
00544 }
00545 }
00546
00547 void Bindings::grabButton(bool grab, const Binding &b,
00548 MouseContext::MC context, Client *client)
00549 {
00550 Window win;
00551 int mode = GrabModeAsync;
00552 unsigned int mask;
00553 switch(context) {
00554 case MouseContext::Frame:
00555 win = client->frame->window();
00556 mask = ButtonPressMask | ButtonMotionMask | ButtonReleaseMask;
00557 break;
00558 case MouseContext::Window:
00559 win = client->frame->plate();
00560 mode = GrabModeSync;
00561 mask = ButtonPressMask;
00562
00563
00564 break;
00565 default:
00566
00567 return;
00568 }
00569 if (grab)
00570 otk::display->grabButton(b.key, b.modifiers, win, false, mask, mode,
00571 GrabModeAsync, None, None, false);
00572 else
00573 otk::display->ungrabButton(b.key, b.modifiers, win);
00574 }
00575
00576 void Bindings::grabButtons(bool grab, Client *client)
00577 {
00578 for (int i = 0; i < MouseContext::NUM_MOUSE_CONTEXT; ++i) {
00579 ButtonBindingList::iterator it, end = _buttons[i].end();
00580 for (it = _buttons[i].begin(); it != end; ++it)
00581 grabButton(grab, (*it)->binding, (MouseContext::MC)i, client);
00582 }
00583 }
00584
00585 void Bindings::fireButton(MouseData *data)
00586 {
00587 if (data->context == MouseContext::Window) {
00588
00589 XAllowEvents(**otk::display, ReplayPointer, data->time);
00590 }
00591
00592 ButtonBindingList::iterator it, end = _buttons[data->context].end();
00593 for (it = _buttons[data->context].begin(); it != end; ++it)
00594 if ((*it)->binding.key == data->button &&
00595 (*it)->binding.modifiers == data->state) {
00596 CallbackList::iterator c_it,c_end = (*it)->callbacks[data->action].end();
00597 for (c_it = (*it)->callbacks[data->action].begin();
00598 c_it != c_end; ++c_it)
00599 python_callback(*c_it, data);
00600 }
00601 }
00602
00603
00604 bool Bindings::addEvent(EventAction::EA action, PyObject *callback)
00605 {
00606 if (action < 0 || action >= EventAction::NUM_EVENTS) {
00607 return false;
00608 }
00609 #ifdef XKB
00610 if (action == EventAction::Bell && _eventlist[action].empty())
00611 XkbSelectEvents(**otk::display, XkbUseCoreKbd,
00612 XkbBellNotifyMask, XkbBellNotifyMask);
00613 #endif // XKB
00614 _eventlist[action].push_back(callback);
00615 Py_INCREF(callback);
00616 return true;
00617 }
00618
00619 bool Bindings::removeEvent(EventAction::EA action, PyObject *callback)
00620 {
00621 if (action < 0 || action >= EventAction::NUM_EVENTS) {
00622 return false;
00623 }
00624
00625 CallbackList::iterator it = std::find(_eventlist[action].begin(),
00626 _eventlist[action].end(),
00627 callback);
00628 if (it != _eventlist[action].end()) {
00629 Py_XDECREF(*it);
00630 _eventlist[action].erase(it);
00631 #ifdef XKB
00632 if (action == EventAction::Bell && _eventlist[action].empty())
00633 XkbSelectEvents(**otk::display, XkbUseCoreKbd,
00634 XkbBellNotifyMask, 0);
00635 #endif // XKB
00636 return true;
00637 }
00638 return false;
00639 }
00640
00641 void Bindings::removeAllEvents()
00642 {
00643 for (int i = 0; i < EventAction::NUM_EVENTS; ++i) {
00644 while (!_eventlist[i].empty()) {
00645 Py_XDECREF(_eventlist[i].front());
00646 _eventlist[i].pop_front();
00647 }
00648 }
00649 }
00650
00651 void Bindings::fireEvent(EventData *data)
00652 {
00653 CallbackList::iterator c_it, c_end = _eventlist[data->action].end();
00654 for (c_it = _eventlist[data->action].begin(); c_it != c_end; ++c_it)
00655 python_callback(*c_it, data);
00656 }
00657
00658 }