+ if (i >= openbox->screenCount())
+ return false; // couldn't find the screen.. it's not managed
+
+ Window root = otk::display->screenInfo(i)->rootWindow();
+ if (XGrabKeyboard(**otk::display, root, false, GrabModeAsync,
+ GrabModeSync, CurrentTime))
+ return false;
+ printf("****GRABBED****\n");
+ _keybgrab_callback = callback;
+ return true;
+}
+
+
+void Bindings::ungrabKeyboard()
+{
+ if (!_keybgrab_callback) return; // not grabbed
+
+ _keybgrab_callback = 0;
+ XUngrabKeyboard(**otk::display, CurrentTime);
+ printf("****UNGRABBED****\n");
+}
+
+
+void Bindings::fireKey(int screen, unsigned int modifiers, unsigned int key,
+ Time time, KeyAction action)
+{
+ if (_keybgrab_callback) {
+ Client *c = openbox->focusedClient();
+ KeyData data(screen, c, time, modifiers, key, action);
+ python_callback(_keybgrab_callback, &data);
+ } else {
+ // KeyRelease events only occur during keyboard grabs
+ if (action == EventKeyRelease) return;
+
+ if (key == _resetkey.key && modifiers == _resetkey.modifiers) {
+ resetChains(this);
+ } else {
+ KeyBindingTree *p = _curpos->first_child;
+ while (p) {
+ if (p->binding.key == key && p->binding.modifiers == modifiers) {
+ if (p->chain) {
+ if (_timer)
+ delete _timer;
+ _timer = new otk::Timer(5000, // 5 second timeout
+ (otk::Timer::TimeoutHandler)resetChains,
+ this);
+ // grab the server here to make sure no key pressed go missed
+ otk::display->grab();
+ grabKeys(false);
+ _curpos = p;
+ grabKeys(true);
+ otk::display->ungrab();
+ } else {
+ Client *c = openbox->focusedClient();
+ KeyData data(screen, c, time, modifiers, key, action);
+ CallbackList::iterator it, end = p->callbacks.end();
+ for (it = p->callbacks.begin(); it != end; ++it)
+ python_callback(*it, &data);
+ resetChains(this);
+ }
+ break;
+ }
+ p = p->next_sibling;
+ }
+ }
+ }
+}
+
+void Bindings::resetChains(Bindings *self)
+{
+ if (self->_timer) {
+ delete self->_timer;
+ self->_timer = (otk::Timer *) 0;
+ }
+ // grab the server here to make sure no key pressed go missed
+ otk::display->grab();
+ self->grabKeys(false);
+ self->_curpos = &self->_keytree;
+ self->grabKeys(true);
+ otk::display->ungrab();
+}
+
+
+bool Bindings::addButton(const std::string &but, MouseContext context,
+ MouseAction action, PyObject *callback)
+{
+ assert(context >= 0 && context < NUM_MOUSE_CONTEXT);
+
+ Binding b(0,0);
+ if (!translate(but, b, false))
+ return false;
+
+ ButtonBindingList::iterator it, end = _buttons[context].end();
+
+ // look for a duplicate binding
+ for (it = _buttons[context].begin(); it != end; ++it)
+ if ((*it)->binding.key == b.key &&
+ (*it)->binding.modifiers == b.modifiers) {
+ break;
+ }
+
+ ButtonBinding *bind;
+
+ // the binding didnt exist yet, add it
+ if (it == end) {
+ bind = new ButtonBinding();
+ bind->binding.key = b.key;
+ bind->binding.modifiers = b.modifiers;
+ _buttons[context].push_back(bind);
+ // grab the button on all clients
+ for (int sn = 0; sn < openbox->screenCount(); ++sn) {
+ Screen *s = openbox->screen(sn);
+ Client::List::iterator c_it, c_end = s->clients.end();
+ for (c_it = s->clients.begin(); c_it != c_end; ++c_it) {
+ grabButton(true, bind->binding, context, *c_it);
+ }
+ }
+ } else
+ bind = *it;
+ bind->callbacks[action].push_back(callback);
+ Py_INCREF(callback);
+ return true;
+}
+
+void Bindings::removeAllButtons()
+{
+ for (int i = 0; i < NUM_MOUSE_CONTEXT; ++i) {
+ ButtonBindingList::iterator it, end = _buttons[i].end();
+ for (it = _buttons[i].begin(); it != end; ++it) {
+ for (int a = 0; a < NUM_MOUSE_ACTION; ++a) {
+ while (!(*it)->callbacks[a].empty()) {
+ Py_XDECREF((*it)->callbacks[a].front());
+ (*it)->callbacks[a].pop_front();
+ }
+ }
+ // ungrab the button on all clients
+ for (int sn = 0; sn < openbox->screenCount(); ++sn) {
+ Screen *s = openbox->screen(sn);
+ Client::List::iterator c_it, c_end = s->clients.end();
+ for (c_it = s->clients.begin(); c_it != c_end; ++c_it) {
+ grabButton(false, (*it)->binding, (MouseContext)i, *c_it);
+ }
+ }