From a0350e27b311db5cab49035752d3852ee68bf8a2 Mon Sep 17 00:00:00 2001 From: Dana Jansens Date: Fri, 3 Jan 2003 21:36:09 +0000 Subject: [PATCH] allow "event bindings" via ebind() for new windows/window enter/leave --- scripts/config.py | 4 ++ src/actions.cc | 131 ++++++++++++++++++-------------------------- src/actions.hh | 39 ++++--------- src/openbox.i | 2 - src/openbox_wrap.cc | 34 +++++------- src/python.cc | 106 ++++++++++++++++++++++------------- src/python.hh | 29 ++++++++-- 7 files changed, 173 insertions(+), 172 deletions(-) diff --git a/scripts/config.py b/scripts/config.py index f0cd4baa..1028592e 100644 --- a/scripts/config.py +++ b/scripts/config.py @@ -19,6 +19,10 @@ theme = "/usr/local/share/openbox/styles/nyz" # the end by Openbox. titlebar_layout = "ILC" +# double_click_delay - the number of milliseconds in which 2 clicks are +# perceived as a double-click +double_click_delay = 300 + ############################################################################# ### Options that can be modified by the user to change the default hooks' ### ### behaviors. ### diff --git a/src/actions.cc b/src/actions.cc index ffa0a8f0..00d4c1bf 100644 --- a/src/actions.cc +++ b/src/actions.cc @@ -16,7 +16,6 @@ namespace ob { -const unsigned int OBActions::DOUBLECLICKDELAY = 300; const int OBActions::BUTTONS; OBActions::OBActions() @@ -24,6 +23,9 @@ OBActions::OBActions() { for (int i=0; ibindings()->fireButton(data); - if (e.time - _release.time < DOUBLECLICKDELAY && + // XXX: dont load this every time!!@* + long dblclick; + if (!python_get_long("double_click_delay", &dblclick)) + dblclick = 300; + + if (e.time - _release.time < (unsigned)dblclick && _release.win == e.window && _release.button == e.button) { // run the DOUBLECLICK python hook @@ -142,12 +149,12 @@ void OBActions::enterHandler(const XCrossingEvent &e) { OtkEventHandler::enterHandler(e); - OBWidget *w = dynamic_cast - (Openbox::instance->findHandler(e.window)); - // run the ENTER python hook - doCallback(Action_EnterWindow, e.window, - (OBWidget::WidgetType)(w ? w->type():-1), e.state, 0, 0, 0, 0); + if (_callback[EventEnterWindow]) { + EventData *data = new_event_data(e.window, EventEnterWindow, e.state); + python_callback(_callback[EventEnterWindow], (PyObject*)data); + Py_DECREF((PyObject*)data); + } } @@ -155,19 +162,18 @@ void OBActions::leaveHandler(const XCrossingEvent &e) { OtkEventHandler::leaveHandler(e); - OBWidget *w = dynamic_cast - (Openbox::instance->findHandler(e.window)); - // run the LEAVE python hook - doCallback(Action_LeaveWindow, e.window, - (OBWidget::WidgetType)(w ? w->type():-1), e.state, 0, 0, 0, 0); + if (_callback[EventLeaveWindow]) { + EventData *data = new_event_data(e.window, EventLeaveWindow, e.state); + python_callback(_callback[EventLeaveWindow], (PyObject*)data); + Py_DECREF((PyObject*)data); + } } void OBActions::keyPressHandler(const XKeyEvent &e) { -// OBWidget *w = dynamic_cast -// (Openbox::instance->findHandler(e.window)); + OtkEventHandler::keyPressHandler(e); unsigned int state = e.state & (ControlMask | ShiftMask | Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask); @@ -177,6 +183,8 @@ void OBActions::keyPressHandler(const XKeyEvent &e) void OBActions::motionHandler(const XMotionEvent &e) { + OtkEventHandler::motionHandler(e); + if (!e.same_screen) return; // this just gets stupid int x_root = e.x_root, y_root = e.y_root; @@ -211,97 +219,66 @@ void OBActions::motionHandler(const XMotionEvent &e) void OBActions::mapRequestHandler(const XMapRequestEvent &e) { - doCallback(Action_NewWindow, e.window, (OBWidget::WidgetType)-1, - 0, 0, 0, 0, 0); + OtkEventHandler::mapRequestHandler(e); + + if (_callback[EventNewWindow]) { + EventData *data = new_event_data(e.window, EventNewWindow, 0); + python_callback(_callback[EventNewWindow], (PyObject*)data); + Py_DECREF((PyObject*)data); + } } void OBActions::unmapHandler(const XUnmapEvent &e) { - (void)e; - doCallback(Action_CloseWindow, e.window, (OBWidget::WidgetType)-1, - 0, 0, 0, 0, 0); + OtkEventHandler::unmapHandler(e); + + if (_callback[EventCloseWindow]) { + EventData *data = new_event_data(e.window, EventCloseWindow, 0); + python_callback(_callback[EventCloseWindow], (PyObject*)data); + Py_DECREF((PyObject*)data); + } } void OBActions::destroyHandler(const XDestroyWindowEvent &e) { - (void)e; - doCallback(Action_CloseWindow, e.window, (OBWidget::WidgetType)-1, - 0, 0, 0, 0, 0); -} + OtkEventHandler::destroyHandler(e); -void OBActions::doCallback(ActionType action, Window window, - OBWidget::WidgetType type, unsigned int state, - unsigned int button, int xroot, int yroot, - Time time) -{ - std::pair it_pair = - _callbacks.equal_range(action); - - CallbackMap::iterator it; -// for (it = it_pair.first; it != it_pair.second; ++it) -// python_callback(it->second, action, window, type, state, -// button, xroot, yroot, time); - // XXX do a callback + if (_callback[EventCloseWindow]) { + EventData *data = new_event_data(e.window, EventCloseWindow, 0); + python_callback(_callback[EventCloseWindow], (PyObject*)data); + Py_DECREF((PyObject*)data); + } } -bool OBActions::registerCallback(ActionType action, PyObject *func, - bool atfront) +bool OBActions::bind(EventAction action, PyObject *func) { - if (action < 0 || action >= OBActions::NUM_ACTIONS) { + if (action < 0 || action >= NUM_EVENTS) { return false; } - if (!func) - return false; - std::pair it_pair = - _callbacks.equal_range(action); - - CallbackMap::iterator it; - for (it = it_pair.first; it != it_pair.second; ++it) - if (it->second == func) - return true; // already in there - if (atfront) - _callbacks.insert(_callbacks.begin(), CallbackMapPair(action, func)); - else - _callbacks.insert(CallbackMapPair(action, func)); + Py_XDECREF(_callback[action]); + _callback[action] = func; Py_INCREF(func); return true; } -bool OBActions::unregisterCallback(ActionType action, PyObject *func) +bool OBActions::unbind(EventAction action) { - if (action < 0 || action >= OBActions::NUM_ACTIONS) { + if (action < 0 || action >= NUM_EVENTS) { return false; } - if (!func) - return false; - - std::pair it_pair = - _callbacks.equal_range(action); - CallbackMap::iterator it; - for (it = it_pair.first; it != it_pair.second; ++it) - if (it->second == func) - break; - if (it != it_pair.second) { // its been registered before - Py_DECREF(func); - _callbacks.erase(it); - } + Py_XDECREF(_callback[action]); + _callback[action] = 0; return true; } -bool OBActions::unregisterAllCallbacks(ActionType action) +void OBActions::unbindAll() { - if (action < 0 || action >= OBActions::NUM_ACTIONS) { - return false; + for (int i = 0; i < NUM_EVENTS; ++i) { + Py_XDECREF(_callback[i]); + _callback[i] = 0; } - - while (!_callbacks.empty()) { - CallbackMap::iterator it = _callbacks.begin(); - Py_DECREF(it->second); - _callbacks.erase(it); - } - return true; } } diff --git a/src/actions.hh b/src/actions.hh index 2b68153a..970a18a4 100644 --- a/src/actions.hh +++ b/src/actions.hh @@ -27,15 +27,7 @@ namespace ob { */ class OBActions : public otk::OtkEventHandler { public: - // update the same enum in openbox.i when making changes to this - enum ActionType { - Action_EnterWindow, - Action_LeaveWindow, - Action_NewWindow, - Action_CloseWindow, - NUM_ACTIONS - }; - +#ifndef SWIG // get rid of a swig warning struct ButtonReleaseAction { Window win; unsigned int button; @@ -49,10 +41,9 @@ public: otk::Rect clientarea; ButtonPressAction() { button = 0; } }; - +#endif // SWIG private: // milliseconds XXX: config option - static const unsigned int DOUBLECLICKDELAY; static const int BUTTONS = 5; //! The mouse button currently being watched from a press for a CLICK @@ -68,15 +59,9 @@ private: void insertPress(const XButtonEvent &e); void removePress(const XButtonEvent &e); - - typedef std::multimap CallbackMap; - typedef std::pair CallbackMapPair; - CallbackMap _callbacks; - void doCallback(ActionType action, Window window, OBWidget::WidgetType type, - unsigned int state, unsigned int button, - int xroot, int yroot, Time time); - + PyObject *_callback[NUM_EVENTS]; + public: //! Constructs an OBActions object OBActions(); @@ -97,18 +82,14 @@ public: virtual void unmapHandler(const XUnmapEvent &e); virtual void destroyHandler(const XDestroyWindowEvent &e); - //! Add a callback funtion to the back of the hook list - /*! - Registering functions for KeyPress events is pointless. Use - OBSCript::bindKey instead to do this. - */ - bool registerCallback(ActionType action, PyObject *func, bool atfront); + //! Bind a callback for an action + bool bind(EventAction action, PyObject *func); - //! Remove a callback function from the hook list - bool unregisterCallback(ActionType action, PyObject *func); + //! Unbind the callback function from an action + bool unbind(EventAction action); - //! Remove all callback functions from the hook list - bool unregisterAllCallbacks(ActionType action); + //! Remove all callback functions + void unbindAll(); }; } diff --git a/src/openbox.i b/src/openbox.i index aeae40dd..1b227568 100644 --- a/src/openbox.i +++ b/src/openbox.i @@ -24,8 +24,6 @@ ob::Openbox *Openbox_instance() { return ob::Openbox::instance; } %}; -%rename(register) python_register; - %ignore ob::OBScreen::clients; %{ #include diff --git a/src/openbox_wrap.cc b/src/openbox_wrap.cc index 8ed3bc44..ecc21e32 100644 --- a/src/openbox_wrap.cc +++ b/src/openbox_wrap.cc @@ -2554,15 +2554,16 @@ static PyObject *_wrap_kbind(PyObject *self, PyObject *args) { } -static PyObject *_wrap_kunbind(PyObject *self, PyObject *args) { +static PyObject *_wrap_ebind(PyObject *self, PyObject *args) { PyObject *resultobj; - PyObject *arg1 = (PyObject *) 0 ; + int arg1 ; + PyObject *arg2 = (PyObject *) 0 ; PyObject *result; - PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; - if(!PyArg_ParseTuple(args,(char *)"O:kunbind",&obj0)) goto fail; - arg1 = obj0; - result = (PyObject *)ob::kunbind(arg1); + if(!PyArg_ParseTuple(args,(char *)"iO:ebind",&arg1,&obj1)) goto fail; + arg2 = obj1; + result = (PyObject *)ob::ebind((ob::EventAction )arg1,arg2); resultobj = result; return resultobj; @@ -2571,19 +2572,6 @@ static PyObject *_wrap_kunbind(PyObject *self, PyObject *args) { } -static PyObject *_wrap_kunbind_all(PyObject *self, PyObject *args) { - PyObject *resultobj; - - if(!PyArg_ParseTuple(args,(char *)":kunbind_all")) goto fail; - ob::kunbind_all(); - - Py_INCREF(Py_None); resultobj = Py_None; - return resultobj; - fail: - return NULL; -} - - static PyObject *_wrap_set_reset_key(PyObject *self, PyObject *args) { PyObject *resultobj; std::string *arg1 = 0 ; @@ -2706,8 +2694,7 @@ static PyMethodDef SwigMethods[] = { { (char *)"OBClient_swigregister", OBClient_swigregister, METH_VARARGS }, { (char *)"mbind", _wrap_mbind, METH_VARARGS }, { (char *)"kbind", _wrap_kbind, METH_VARARGS }, - { (char *)"kunbind", _wrap_kunbind, METH_VARARGS }, - { (char *)"kunbind_all", _wrap_kunbind_all, METH_VARARGS }, + { (char *)"ebind", _wrap_ebind, METH_VARARGS }, { (char *)"set_reset_key", _wrap_set_reset_key, METH_VARARGS }, { NULL, NULL } }; @@ -2867,6 +2854,11 @@ static swig_const_info swig_const_table[] = { { SWIG_PY_INT, (char *)"KC_Menu", (long) ob::KC_Menu, 0, 0, 0}, { SWIG_PY_INT, (char *)"KC_All", (long) ob::KC_All, 0, 0, 0}, { SWIG_PY_INT, (char *)"NUM_KEY_CONTEXT", (long) ob::NUM_KEY_CONTEXT, 0, 0, 0}, +{ SWIG_PY_INT, (char *)"EventEnterWindow", (long) ob::EventEnterWindow, 0, 0, 0}, +{ SWIG_PY_INT, (char *)"EventLeaveWindow", (long) ob::EventLeaveWindow, 0, 0, 0}, +{ SWIG_PY_INT, (char *)"EventNewWindow", (long) ob::EventNewWindow, 0, 0, 0}, +{ SWIG_PY_INT, (char *)"EventCloseWindow", (long) ob::EventCloseWindow, 0, 0, 0}, +{ SWIG_PY_INT, (char *)"NUM_EVENTS", (long) ob::NUM_EVENTS, 0, 0, 0}, { SWIG_PY_INT, (char *)"X_PROTOCOL", (long) 11, 0, 0, 0}, { SWIG_PY_INT, (char *)"X_PROTOCOL_REVISION", (long) 0, 0, 0, 0}, { SWIG_PY_INT, (char *)"None", (long) 0L, 0, 0, 0}, diff --git a/src/python.cc b/src/python.cc index 818115ca..4bddce8f 100644 --- a/src/python.cc +++ b/src/python.cc @@ -171,6 +171,28 @@ static PyMethodDef ButtonData_methods[] = { {NULL, NULL, 0, NULL} }; +PyObject *EventData_action(EventData *self, PyObject *args) +{ + if(!PyArg_ParseTuple(args,":action")) return NULL; + return PyLong_FromLong((int)self->action); +} + +PyObject *EventData_modifiers(EventData *self, PyObject *args) +{ + if(!PyArg_ParseTuple(args,":modifiers")) return NULL; + return PyLong_FromUnsignedLong(self->state); +} + +static PyMethodDef EventData_methods[] = { + {"window", (PyCFunction)MotionData_window, METH_VARARGS, + "Return the client window id."}, + {"action", (PyCFunction)EventData_action, METH_VARARGS, + "Return the action being executed."}, + {"modifiers", (PyCFunction)EventData_modifiers, METH_VARARGS, + "Return the modifier keys state."}, + {NULL, NULL, 0, NULL} +}; + PyObject *KeyData_key(KeyData *self, PyObject *args) { if(!PyArg_ParseTuple(args,":key")) return NULL; @@ -201,6 +223,11 @@ static PyObject *ButtonDataGetAttr(PyObject *obj, char *name) return Py_FindMethod(ButtonData_methods, obj, name); } +static PyObject *EventDataGetAttr(PyObject *obj, char *name) +{ + return Py_FindMethod(EventData_methods, obj, name); +} + static PyObject *KeyDataGetAttr(PyObject *obj, char *name) { return Py_FindMethod(KeyData_methods, obj, name); @@ -230,6 +257,18 @@ static PyTypeObject ButtonData_Type = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; +static PyTypeObject EventData_Type = { + PyObject_HEAD_INIT(NULL) + 0, + "EventData", + sizeof(EventData), + 0, + dealloc, + 0, + (getattrfunc)EventDataGetAttr, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +}; + static PyTypeObject KeyData_Type = { PyObject_HEAD_INIT(NULL) 0, @@ -279,6 +318,16 @@ ButtonData *new_button_data(Window window, Time time, unsigned int state, return data; } +EventData *new_event_data(Window window, EventAction action, + unsigned int state) +{ + EventData *data = PyObject_New(EventData, &EventData_Type); + data->window = window; + data->action = action; + data->state = state; + return data; +} + KeyData *new_key_data(Window window, Time time, unsigned int state, unsigned int key) { @@ -348,6 +397,15 @@ void python_callback(PyObject *func, PyObject *data) Py_DECREF(arglist); } +bool python_get_long(const char *name, long *value) +{ + PyObject *val = PyDict_GetItemString(obdict, const_cast(name)); + if (!(val && PyLong_Check(val))) return false; + + *value = PyLong_AsLong(val); + return true; +} + bool python_get_string(const char *name, std::string *value) { PyObject *val = PyDict_GetItemString(obdict, const_cast(name)); @@ -374,65 +432,37 @@ bool python_get_stringlist(const char *name, std::vector *value) // Stuff for calling from Python scripts // // ************************************* // -/* -PyObject * python_register(int action, PyObject *func, bool infront = false) -{ - if (!PyCallable_Check(func)) { - PyErr_SetString(PyExc_TypeError, "Invalid callback function."); - return NULL; - } - - if (!ob::Openbox::instance->actions()->registerCallback( - (ob::OBActions::ActionType)action, func, infront)) { - PyErr_SetString(PyExc_RuntimeError, "Unable to register action callback."); - return NULL; - } - Py_INCREF(Py_None); return Py_None; -} - -PyObject *unregister(int action, PyObject *func) +PyObject *mbind(const std::string &button, ob::MouseContext context, + ob::MouseAction action, PyObject *func) { if (!PyCallable_Check(func)) { PyErr_SetString(PyExc_TypeError, "Invalid callback function."); return NULL; } - - if (!ob::Openbox::instance->actions()->unregisterCallback( - (ob::OBActions::ActionType)action, func)) { - PyErr_SetString(PyExc_RuntimeError, "Unable to unregister action callback."); + + if (!ob::Openbox::instance->bindings()->addButton(button, context, + action, func)) { + PyErr_SetString(PyExc_RuntimeError,"Unable to add binding."); return NULL; } Py_INCREF(Py_None); return Py_None; } -PyObject *unregister_all(int action) -{ - if (!ob::Openbox::instance->actions()->unregisterAllCallbacks( - (ob::OBActions::ActionType)action)) { - PyErr_SetString(PyExc_RuntimeError, - "Unable to unregister action callbacks."); - return NULL; - } - Py_INCREF(Py_None); return Py_None; -} -*/ -PyObject * mbind(const std::string &button, ob::MouseContext context, - ob::MouseAction action, PyObject *func) +PyObject *ebind(ob::EventAction action, PyObject *func) { if (!PyCallable_Check(func)) { PyErr_SetString(PyExc_TypeError, "Invalid callback function."); return NULL; } - if (!ob::Openbox::instance->bindings()->addButton(button, context, - action, func)) { + if (!ob::Openbox::instance->actions()->bind(action, func)) { PyErr_SetString(PyExc_RuntimeError,"Unable to add binding."); return NULL; } Py_INCREF(Py_None); return Py_None; } -PyObject * kbind(PyObject *keylist, ob::KeyContext context, PyObject *func) +PyObject *kbind(PyObject *keylist, ob::KeyContext context, PyObject *func) { if (!PyCallable_Check(func)) { PyErr_SetString(PyExc_TypeError, "Invalid callback function."); @@ -461,7 +491,7 @@ PyObject * kbind(PyObject *keylist, ob::KeyContext context, PyObject *func) Py_INCREF(Py_None); return Py_None; } -PyObject * kunbind(PyObject *keylist) +PyObject *kunbind(PyObject *keylist) { if (!PyList_Check(keylist)) { PyErr_SetString(PyExc_TypeError, "Invalid keylist. Not a list."); diff --git a/src/python.hh b/src/python.hh index 67943a84..2bf656d8 100644 --- a/src/python.hh +++ b/src/python.hh @@ -48,6 +48,14 @@ enum KeyContext { NUM_KEY_CONTEXT }; +enum EventAction { + EventEnterWindow, + EventLeaveWindow, + EventNewWindow, + EventCloseWindow, + NUM_EVENTS +}; + #ifndef SWIG // *** MotionData can be (and is) cast ButtonData!! (in actions.cc) *** // @@ -80,6 +88,13 @@ typedef struct { MouseAction action; } ButtonData; +typedef struct { + PyObject_HEAD; + Window window; + unsigned int state; + EventAction action; +} EventData; + typedef struct { PyObject_HEAD; Window window; @@ -100,21 +115,25 @@ MotionData *new_motion_data(Window window, Time time, unsigned int state, ButtonData *new_button_data(Window window, Time time, unsigned int state, unsigned int button, MouseContext context, MouseAction action); +EventData *new_event_data(Window window, EventAction action, + unsigned int state); KeyData *new_key_data(Window window, Time time, unsigned int state, unsigned int key); void python_callback(PyObject *func, PyObject *data); +bool python_get_long(const char *name, long *value); bool python_get_string(const char *name, std::string *value); bool python_get_stringlist(const char *name, std::vector *value); #endif -PyObject * mbind(const std::string &button, ob::MouseContext context, - ob::MouseAction action, PyObject *func); +PyObject *mbind(const std::string &button, ob::MouseContext context, + ob::MouseAction action, PyObject *func); + +PyObject *kbind(PyObject *keylist, ob::KeyContext context, PyObject *func); + +PyObject *ebind(ob::EventAction action, PyObject *func); -PyObject * kbind(PyObject *keylist, ob::KeyContext context, PyObject *func); -PyObject * kunbind(PyObject *keylist); -void kunbind_all(); void set_reset_key(const std::string &key); } -- 2.45.2