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 }