]> Dogcows Code - chaz/openbox/commitdiff
allow to bind multiple functions to everything
authorDana Jansens <danakj@orodu.net>
Mon, 6 Jan 2003 19:01:49 +0000 (19:01 +0000)
committerDana Jansens <danakj@orodu.net>
Mon, 6 Jan 2003 19:01:49 +0000 (19:01 +0000)
src/bindings.cc
src/bindings.hh
src/python.cc

index 6a135b6d6821a94c4e2b812741529371af171730..f68dc65a2383faf3d9a00097aa573d129a243144 100644 (file)
@@ -116,7 +116,7 @@ static void destroytree(KeyBindingTree *tree)
 }
 
 KeyBindingTree *OBBindings::buildtree(const StringVect &keylist,
-                                   PyObject *callback) const
+                                      PyObject *callback) const
 {
   if (keylist.empty()) return 0; // nothing in the list.. return 0
 
@@ -125,8 +125,12 @@ KeyBindingTree *OBBindings::buildtree(const StringVect &keylist,
   StringVect::const_reverse_iterator it, end = keylist.rend();
   for (it = keylist.rbegin(); it != end; ++it) {
     p = ret;
-    ret = new KeyBindingTree(callback);
-    if (!p) ret->chain = false; // only the first built node
+    ret = new KeyBindingTree();
+    if (!p) {
+      // this is the first built node, the bottom node of the tree
+      ret->chain = false;
+      ret->callbacks.push_back(callback);
+    }
     ret->first_child = p;
     if (!translate(*it, ret->binding)) {
       destroytree(ret);
@@ -147,9 +151,6 @@ OBBindings::OBBindings()
   _timer.setTimeout(5000); // chains reset after 5 seconds
   
 //  setResetKey("C-g"); // set the default reset key
-
-  for (int i = 0; i < NUM_EVENTS; ++i)
-    _events[i] = 0;
 }
 
 
@@ -194,7 +195,8 @@ void OBBindings::assimilate(KeyBindingTree *node)
 }
 
 
-PyObject *OBBindings::find(KeyBindingTree *search, bool *conflict) const {
+KeyBindingTree *OBBindings::find(KeyBindingTree *search,
+                                 bool *conflict) const {
   *conflict = false;
   KeyBindingTree *a, *b;
   a = _keytree.first_child;
@@ -206,7 +208,7 @@ PyObject *OBBindings::find(KeyBindingTree *search, bool *conflict) const {
       if (a->chain == b->chain) {
        if (!a->chain) {
           // found it! (return the actual id, not the search's)
-         return a->callback;
+         return a;
         }
       } else {
         *conflict = true;
@@ -222,32 +224,40 @@ PyObject *OBBindings::find(KeyBindingTree *search, bool *conflict) const {
 
 bool OBBindings::addKey(const StringVect &keylist, PyObject *callback)
 {
-  KeyBindingTree *tree;
+  KeyBindingTree *tree, *t;
   bool conflict;
 
   if (!(tree = buildtree(keylist, callback)))
     return false; // invalid binding requested
 
-  if (find(tree, &conflict) || conflict) {
+  t = find(tree, &conflict);
+  if (conflict) {
     // conflicts with another binding
     destroytree(tree);
     return false;
   }
 
-  grabKeys(false);
-  
-  // assimilate this built tree into the main tree
-  assimilate(tree); // assimilation destroys/uses the tree
+  if (t) {
+    // already bound to something
+    // XXX: look if callback is already bound to this key?
+    t->callbacks.push_back(callback);
+    destroytree(tree);
+  } else {
+    grabKeys(false);
 
-  Py_INCREF(callback);
+    // assimilate this built tree into the main tree
+    assimilate(tree); // assimilation destroys/uses the tree
 
-  grabKeys(true); 
+    grabKeys(true); 
+  }
  
+  Py_INCREF(callback);
+
   return true;
 }
 
 
-bool OBBindings::removeKey(const StringVect &keylist)
+bool OBBindings::removeKey(const StringVect &keylist, PyObject *callback)
 {
   assert(false); // XXX: function not implemented yet
 
@@ -257,17 +267,22 @@ bool OBBindings::removeKey(const StringVect &keylist)
   if (!(tree = buildtree(keylist, 0)))
     return false; // invalid binding requested
 
-  PyObject *func = find(tree, &conflict);
-  if (func) {
-    grabKeys(false);
-
-    _curpos = &_keytree;
-    
-    // XXX do shit here ...
-    Py_DECREF(func);
-    
-    grabKeys(true);
-    return true;
+  KeyBindingTree *t = find(tree, &conflict);
+  if (t) {
+    CallbackList::iterator it = std::find(t->callbacks.begin(),
+                                          t->callbacks.end(),
+                                          callback);
+    if (it != t->callbacks.end()) {
+      grabKeys(false);
+      
+      _curpos = &_keytree;
+      
+      // XXX do shit here ...
+      Py_XDECREF(*it);
+      
+      grabKeys(true);
+      return true;
+    }
   }
   return false;
 }
@@ -293,7 +308,10 @@ static void remove_branch(KeyBindingTree *first)
     if (p->first_child)
       remove_branch(p->first_child);
     KeyBindingTree *s = p->next_sibling;
-    Py_XDECREF(p->callback);
+    while(!p->callbacks.empty()) {
+      Py_XDECREF(p->callbacks.front());
+      p->callbacks.pop_front();
+    }
     delete p;
     p = s;
   }
@@ -359,8 +377,10 @@ void OBBindings::fireKey(unsigned int modifiers, unsigned int key, Time time)
           OBClient *c = Openbox::instance->focusedClient();
           if (c) win = c->window();
           KeyData *data = new_key_data(win, time, modifiers, key);
-          python_callback(p->callback, (PyObject*)data);
-          Py_DECREF((PyObject*)data);
+          CallbackList::iterator it, end = p->callbacks.end();
+          for (it = p->callbacks.begin(); it != end; ++it)
+            python_callback(*it, (PyObject*)data);
+          Py_XDECREF((PyObject*)data);
           resetChains(this);
         }
         break;
@@ -394,8 +414,6 @@ bool OBBindings::addButton(const std::string &but, MouseContext context,
   for (it = _buttons[context].begin(); it != end; ++it)
     if ((*it)->binding.key == b.key &&
         (*it)->binding.modifiers == b.modifiers) {
-      if ((*it)->callback[action] == callback)
-        return true; // already bound
       break;
     }
 
@@ -417,8 +435,7 @@ bool OBBindings::addButton(const std::string &but, MouseContext context,
     }
   } else
     bind = *it;
-  Py_XDECREF(bind->callback[action]); // if it was already bound, unbind it
-  bind->callback[action] = callback;
+  bind->callbacks[action].push_back(callback);
   Py_INCREF(callback);
   return true;
 }
@@ -429,8 +446,10 @@ void OBBindings::removeAllButtons()
     ButtonBindingList::iterator it, end = _buttons[i].end();
     for (it = _buttons[i].begin(); it != end; ++it) {
       for (int a = 0; a < NUM_MOUSE_ACTION; ++a) {
-        Py_XDECREF((*it)->callback[a]);
-        (*it)->callback[a] = 0;
+        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::instance->screenCount(); ++sn) {
@@ -491,8 +510,10 @@ void OBBindings::fireButton(ButtonData *data)
   for (it = _buttons[data->context].begin(); it != end; ++it)
     if ((*it)->binding.key == data->button &&
         (*it)->binding.modifiers == data->state) {
-      if ((*it)->callback[data->action])
-        python_callback((*it)->callback[data->action], (PyObject*)data);
+      CallbackList::iterator c_it,c_end = (*it)->callbacks[data->action].end();
+      for (c_it = (*it)->callbacks[data->action].begin();
+           c_it != c_end; ++c_it)
+        python_callback(*c_it, (PyObject*)data);
     }
 }
 
@@ -503,35 +524,43 @@ bool OBBindings::addEvent(EventAction action, PyObject *callback)
     return false;
   }
 
-  Py_XDECREF(_events[action]);
-  _events[action] = callback;
+  _eventlist[action].push_back(callback);
   Py_INCREF(callback);
   return true;
 }
 
-bool OBBindings::removeEvent(EventAction action)
+bool OBBindings::removeEvent(EventAction action, PyObject *callback)
 {
   if (action < 0 || action >= NUM_EVENTS) {
     return false;
   }
   
-  Py_XDECREF(_events[action]);
-  _events[action] = 0;
-  return true;
+  CallbackList::iterator it = std::find(_eventlist[action].begin(),
+                                        _eventlist[action].end(),
+                                        callback);
+  if (it != _eventlist[action].end()) {
+    Py_XDECREF(*it);
+    _eventlist[action].erase(it);
+    return true;
+  }
+  return false;
 }
 
 void OBBindings::removeAllEvents()
 {
   for (int i = 0; i < NUM_EVENTS; ++i) {
-    Py_XDECREF(_events[i]);
-    _events[i] = 0;
+    while (!_eventlist[i].empty()) {
+      Py_XDECREF(_eventlist[i].front());
+      _eventlist[i].pop_front();
+    }
   }
 }
 
 void OBBindings::fireEvent(EventData *data)
 {
-  if (_events[data->action])
-    python_callback(_events[data->action], (PyObject*)data);
+  CallbackList::iterator c_it, c_end = _eventlist[data->action].end();
+  for (c_it = _eventlist[data->action].begin(); c_it != c_end; ++c_it)
+    python_callback(*c_it, (PyObject*)data);
 }
 
 }
index 8e91b5b681323acb63fe4b48c39f2aca0d44a400..8a2f03e1df2371550bcd7084fbf4ed958f4bbe7d 100644 (file)
@@ -22,6 +22,8 @@ namespace ob {
 
 class OBClient;
 
+typedef std::list<PyObject *> CallbackList;
+
 typedef struct Binding {
   unsigned int modifiers;
   unsigned int key;
@@ -35,27 +37,22 @@ typedef struct Binding {
 
 typedef struct KeyBindingTree {
   Binding binding;
-  PyObject *callback; // the callback given for the binding in add()
+  CallbackList callbacks; // the callbacks given for the binding in add()
   bool chain;     // true if this is a chain to another key (not an action)
 
   struct KeyBindingTree *next_sibling; // the next binding in the tree at the same
                                     // level
   struct KeyBindingTree *first_child;  // the first child of this binding (next
                                     // binding in a chained sequence).
-  KeyBindingTree(PyObject *callback) : binding(0, 0) {
-    this->callback = callback; chain = true; next_sibling = first_child = 0;
-  }
   KeyBindingTree() : binding(0, 0) {
-    this->callback = 0; chain = true; next_sibling = first_child = 0;
+    chain = true; next_sibling = first_child = 0;
   }
 } KeyBindingTree;
 
 typedef struct ButtonBinding {
   Binding binding;
-  PyObject *callback[NUM_MOUSE_ACTION];
-  ButtonBinding() : binding(0, 0) {
-    for(int i=0; i<NUM_MOUSE_ACTION; ++i) callback[i] = 0;
-  }
+  CallbackList callbacks[NUM_MOUSE_ACTION];
+  ButtonBinding() : binding(0, 0) {}
 };
 
 class OBBindings {
@@ -72,7 +69,7 @@ private:
 
   otk::OBTimer _timer;
   
-  PyObject *find(KeyBindingTree *search, bool *conflict) const;
+  KeyBindingTree *find(KeyBindingTree *search, bool *conflict) const;
   KeyBindingTree *buildtree(const StringVect &keylist,
                             PyObject *callback) const;
   void assimilate(KeyBindingTree *node);
@@ -85,7 +82,7 @@ private:
   void grabButton(bool grab, const Binding &b, MouseContext context,
                   OBClient *client);
 
-  PyObject *_events[NUM_EVENTS];
+  CallbackList _eventlist[NUM_EVENTS];
   
 public:
   //! Initializes an OBBindings object
@@ -109,7 +106,7 @@ public:
     @return The callbackid of the binding, or '< 0' if there was no binding to
             be removed.
   */
-  bool removeKey(const StringVect &keylist);
+  bool removeKey(const StringVect &keylist, PyObject *callback);
 
   //! Removes all key bindings
   void removeAllKeys();
@@ -134,7 +131,7 @@ public:
   bool addEvent(EventAction action, PyObject *callback);
 
   //! Unbind the callback function from an event
-  bool removeEvent(EventAction action);
+  bool removeEvent(EventAction action, PyObject *callback);
 
   //! Remove all callback functions
   void removeAllEvents();
index 60c3e012f2b4d3929897ed3471a53fdedd77cb8b..c463fdc824d0edca37e2465a09f9cdc31757fa64 100644 (file)
@@ -496,13 +496,17 @@ PyObject *kbind(PyObject *keylist, ob::KeyContext context, PyObject *func)
   Py_INCREF(Py_None); return Py_None;
 }
 
-PyObject *kunbind(PyObject *keylist)
+PyObject *kunbind(PyObject *keylist, PyObject *func)
 {
   if (!PyList_Check(keylist)) {
     PyErr_SetString(PyExc_TypeError, "Invalid keylist. Not a list.");
     return NULL;
   }
-
+  if (!PyCallable_Check(func)) {
+    PyErr_SetString(PyExc_TypeError, "Invalid callback function.");
+    return NULL;
+  }
+  
   ob::OBBindings::StringVect vectkeylist;
   for (int i = 0, end = PyList_Size(keylist); i < end; ++i) {
     PyObject *str = PyList_GetItem(keylist, i);
@@ -514,7 +518,10 @@ PyObject *kunbind(PyObject *keylist)
     vectkeylist.push_back(PyString_AsString(str));
   }
 
-  ob::Openbox::instance->bindings()->removeKey(vectkeylist);
+  if (!ob::Openbox::instance->bindings()->removeKey(vectkeylist, func)) {
+      PyErr_SetString(PyExc_RuntimeError, "Could not remove callback.");
+      return NULL;
+  }
   Py_INCREF(Py_None); return Py_None;
 }
 
This page took 0.031947 seconds and 4 git commands to generate.