keybindings underway. dont work yet

This commit is contained in:
Dana Jansens 2002-12-30 06:31:45 +00:00
parent b8653c3ab8
commit 98c4b4cfe5
11 changed files with 554 additions and 8 deletions

View file

@ -19,7 +19,7 @@ openbox3_LDADD=-L../otk -lotk @LIBINTL@
openbox3_SOURCES= actions.cc client.cc frame.cc openbox.cc screen.cc \
main.cc rootwindow.cc backgroundwidget.cc labelwidget.cc \
buttonwidget.cc python.cc openbox_wrap.cc
buttonwidget.cc python.cc bindings.cc openbox_wrap.cc
MAINTAINERCLEANFILES= Makefile.in

View file

@ -1,4 +1,4 @@
// -*- mode: C++; indent-tabs-mode: nil; -*-
// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
#ifdef HAVE_CONFIG_H
# include "../config.h"

View file

@ -1,4 +1,4 @@
// -*- mode: C++; indent-tabs-mode: nil; -*-
// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
#ifndef __actions_hh
#define __actions_hh

257
src/bindings.cc Normal file
View file

@ -0,0 +1,257 @@
// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
#ifdef HAVE_CONFIG_H
# include "../config.h"
#endif
#include "bindings.hh"
#include "otk/display.hh"
extern "C" {
#include <X11/Xlib.h>
}
namespace ob {
#include <stdio.h>
static void print_branch(BindingTree *first, std::string str)
{
BindingTree *p = first;
while (p) {
if (p->first_child)
print_branch(p->first_child, str + " " + p->text);
printf("%d%s\n", p->id, (str + " " + p->text).c_str());
BindingTree *s = p->next_sibling;
delete p;
p = s;
}
}
void OBBindings::display()
{
if (_bindings.first_child)
print_branch(_bindings.first_child, "");
}
static bool translate(const std::string str, Binding &b)
{
KeySym sym = XStringToKeysym(const_cast<char *>(str.c_str()));
if (sym == NoSymbol) return false;
b.modifiers = Mod1Mask;
b.key = XKeysymToKeycode(otk::OBDisplay::display, sym);
return b.key != 0;
}
static BindingTree *buildtree(const OBBindings::StringVect &keylist, int id)
{
if (keylist.empty()) return 0; // nothing in the list.. return 0
BindingTree *ret = new BindingTree(id), *p = 0;
OBBindings::StringVect::const_iterator it, end = keylist.end();
for (it = keylist.begin(); it != end; ++it) {
if (p)
p = p->first_child = new BindingTree(id);
else
p = ret; // the first node
if (!translate(*it, p->binding))
break;
p->text = *it;
}
if (it != end) {
// build failed.. clean up and return 0
p = ret;
while (p->first_child) {
BindingTree *c = p->first_child;
delete p;
p = c;
}
delete p;
return 0;
} else {
// set the proper chain status on the last node
p->chain = false;
}
printf("<BUILDING>\n");
print_branch(ret);
printf("</BUILDING>\n");
// successfully built a tree
return ret;
}
static void destroytree(BindingTree *tree)
{
while (tree) {
BindingTree *c = tree->first_child;
delete tree;
tree = c;
}
}
OBBindings::OBBindings()
{
}
OBBindings::~OBBindings()
{
remove_all();
}
static void assimilate(BindingTree *parent, BindingTree *node)
{
BindingTree *p, *lastsib, *nextparent, *nextnode = node->first_child;
if (!parent->first_child) {
// there are no nodes at this level yet
parent->first_child = node;
nextparent = node;
} else {
p = lastsib = parent->first_child;
while (p->next_sibling) {
p = p->next_sibling;
lastsib = p; // finds the last sibling
if (p->binding == node->binding) {
// found an identical binding..
assert(node->chain && p->chain);
delete node; // kill the one we aren't using
break;
}
}
if (!p) {
// couldn't find an existing binding, use this new one, and insert it
// into the list
p = lastsib->next_sibling = node;
}
nextparent = p;
}
if (nextnode)
assimilate(nextparent, nextnode);
}
static int find_bind(BindingTree *tree, BindingTree *search) {
BindingTree *a, *b;
a = tree;
b = search;
while (a && b) {
if (a->binding != b->binding) {
a = a->next_sibling;
} else {
if (a->chain == b->chain) {
if (!a->chain)
return a->id; // found it! (return the actual id, not the search's)
} else
return -2; // the chain status' don't match (conflict!)
b = b->first_child;
a = a->first_child;
}
}
return -1; // it just isn't in here
}
/*
static int find(BindingTree *parent, BindingTree *node) {
BindingTree *p, *lastsib, *nextparent, *nextnode = node->first_child;
if (!parent->first_child)
return -1;
p = parent->first_child;
while (p) {
if (node->binding == p->binding) {
if (node->chain == p->chain) {
if (!node->chain) {
return p->id; // found it! (return the actual id, not the search's)
} else {
break; // go on to the next child in the chain
}
} else {
return -2; // the chain status' don't match (conflict!)
}
}
p = p->next_sibling;
}
if (!p) return -1; // doesn't exist
if (node->chain) {
assert(node->first_child);
return find(p, node->first_child);
} else
return -1; // it just isnt in here
}
*/
bool OBBindings::add(const StringVect &keylist, int id)
{
BindingTree *tree;
if (!(tree = buildtree(keylist, id)))
return false; // invalid binding requested
if (find_bind(_bindings.first_child, tree) < -1) {
// conflicts with another binding
destroytree(tree);
return false;
}
// assimilate this built tree into the main tree
assimilate(&_bindings, tree); // assimilation destroys/uses the tree
return true;
}
int OBBindings::find(const StringVect &keylist)
{
BindingTree *tree;
bool ret;
if (!(tree = buildtree(keylist, 0)))
return false; // invalid binding requested
ret = find_bind(_bindings.first_child, tree) >= 0;
destroytree(tree);
return ret;
}
int OBBindings::remove(const StringVect &keylist)
{
(void)keylist;
assert(false); // XXX: function not implemented yet
}
static void remove_branch(BindingTree *first)
{
BindingTree *p = first;
while (p) {
if (p->first_child)
remove_branch(p->first_child);
BindingTree *s = p->next_sibling;
delete p;
p = s;
}
}
void OBBindings::remove_all()
{
if (_bindings.first_child)
remove_branch(_bindings.first_child);
}
}

91
src/bindings.hh Normal file
View file

@ -0,0 +1,91 @@
// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
#ifndef __binding_hh
#define __binding_hh
/*! @file binding.hh
@brief I dunno.. some binding stuff?
*/
#include <string>
#include <vector>
namespace ob {
typedef struct Binding {
unsigned int modifiers;
unsigned int key;
bool operator==(struct Binding &b2) { return key == b2.key &&
modifiers == b2.modifiers; }
bool operator!=(struct Binding &b2) { return key != b2.key ||
modifiers != b2.modifiers; }
Binding(unsigned int mod, unsigned int k) { modifiers = mod; key = k; }
} Binding;
typedef struct BindingTree {
Binding binding;
std::string text;
int id; // the id given for the binding in add()
bool chain; // true if this is a chain to another key (not an action)
struct BindingTree *next_sibling; // the next binding in the tree at the same
// level
struct BindingTree *first_child; // the first child of this binding (next
// binding in a chained sequence).
BindingTree(int id) : binding(0, 0) {
this->id = id; chain = true; next_sibling = first_child = 0;
}
BindingTree() : binding(0, 0) {
this->id = -1; chain = true; next_sibling = first_child = 0;
}
} BindingTree;
class OBBindings {
public:
//! A list of strings
typedef std::vector<std::string> StringVect;
private:
BindingTree _bindings;// root nodes (these dont have siblings!)
public:
//! Initializes an OBBinding object
OBBindings();
//! Destroys the OBBinding object
virtual ~OBBindings();
//! Adds a new binding
/*!
A binding will fail to be added if the binding already exists (as part of
a chain or not), or if any of the strings in the keylist are invalid.
@return true if the binding could be added; false if it could not.
*/
bool add(const StringVect &keylist, int id);
//! Removes a key binding
/*!
@return The id of the binding that was removed, or '< 0' if none were
removed.
*/
int remove(const StringVect &keylist);
//! Removes all key bindings
void remove_all();
//! Finds a keybinding and returns its id or '< 0' if it isn't found.
/*!
@return -1 if the keybinding was not found but does not conflict with
any others; -2 if the keybinding conflicts with another.
*/
int find(const StringVect &keylist);
// XXX: need an exec() function or something that will be used by openbox
// and hold state for which chain we're in etc. (it could have a timer
// for reseting too...)
void display();
};
}
#endif // __binding_hh

View file

@ -9,6 +9,7 @@
#include "client.hh"
#include "screen.hh"
#include "actions.hh"
#include "bindings.hh"
#include "otk/property.hh"
#include "otk/display.hh"
#include "otk/assassin.hh"
@ -145,8 +146,22 @@ Openbox::Openbox(int argc, char **argv)
sigaction(SIGHUP, &action, (struct sigaction *) 0);
_property = new otk::OBProperty();
_actions = new OBActions();
_bindings = new OBBindings();
OBBindings::StringVect v;
// v.push_back("C-x");
// v.push_back("C-y");
v.push_back("v");
_bindings->add(v, 1);
v.clear();
// v.push_back("C-x");
// v.push_back("C-z");
v.push_back("a");
_bindings->add(v, 2);
_bindings->display();
::exit(0);
setMasterHandler(_actions); // set as the master event handler
@ -198,6 +213,10 @@ Openbox::~Openbox()
_state = State_Exiting; // time to kill everything
std::for_each(_screens.begin(), _screens.end(), otk::PointerAssassin());
delete _bindings;
delete _actions;
delete _property;
// close the X display
otk::OBDisplay::destroy();

View file

@ -30,6 +30,7 @@ namespace ob {
class OBScreen;
class OBClient;
class OBActions;
class OBBindings;
//! Mouse cursors used throughout Openbox
struct Cursors {
@ -121,6 +122,9 @@ private:
//! The action interface through which all user-available actions occur
OBActions *_actions;
//! The interface through which keys/buttons are grabbed and handled
OBBindings *_bindings;
//! Run the application in synchronous mode? (for debugging)
bool _sync;
@ -184,6 +188,9 @@ public:
//! Returns the otk::OBProperty instance for the window manager
inline const otk::OBProperty *property() const { return _property; }
//! Returns the OBBinding instance for the window manager
inline OBBindings *bindings() const { return _bindings; }
//! Returns a managed screen
inline OBScreen *screen(int num) {
assert(num >= 0); assert(num < (signed)_screens.size());

View file

@ -56,6 +56,9 @@
%rename(preregister) ob::python_preregister;
%rename(unregister) ob::python_unregister;
%rename(unregister_all) ob::python_unregister_all;
%rename(bind) ob::python_bind;
%rename(unbind) ob::python_unbind;
%rename(unbind_all) ob::python_unbind_all;
%ignore ob::OBScreen::clients;
%{

View file

@ -667,10 +667,11 @@ SWIG_InstallConstants(PyObject *d, swig_const_info constants[]) {
#define SWIGTYPE_p_XDestroyWindowEvent swig_types[19]
#define SWIGTYPE_p_otk__BImageControl swig_types[20]
#define SWIGTYPE_p_PyObject swig_types[21]
#define SWIGTYPE_p_ob__MwmHints swig_types[22]
#define SWIGTYPE_p_otk__Configuration swig_types[23]
#define SWIGTYPE_p_XUnmapEvent swig_types[24]
static swig_type_info *swig_types[26];
#define SWIGTYPE_p_ob__OBBindings swig_types[22]
#define SWIGTYPE_p_ob__MwmHints swig_types[23]
#define SWIGTYPE_p_otk__Configuration swig_types[24]
#define SWIGTYPE_p_XUnmapEvent swig_types[25]
static swig_type_info *swig_types[27];
/* -------- TYPES TABLE (END) -------- */
@ -1112,6 +1113,23 @@ static PyObject *_wrap_Openbox_property(PyObject *self, PyObject *args) {
}
static PyObject *_wrap_Openbox_bindings(PyObject *self, PyObject *args) {
PyObject *resultobj;
ob::Openbox *arg1 = (ob::Openbox *) 0 ;
ob::OBBindings *result;
PyObject * obj0 = 0 ;
if(!PyArg_ParseTuple(args,(char *)"O:Openbox_bindings",&obj0)) goto fail;
if ((SWIG_ConvertPtr(obj0,(void **) &arg1, SWIGTYPE_p_ob__Openbox,SWIG_POINTER_EXCEPTION | 0 )) == -1) SWIG_fail;
result = (ob::OBBindings *)((ob::Openbox const *)arg1)->bindings();
resultobj = SWIG_NewPointerObj((void *) result, SWIGTYPE_p_ob__OBBindings, 0);
return resultobj;
fail:
return NULL;
}
static PyObject *_wrap_Openbox_screen(PyObject *self, PyObject *args) {
PyObject *resultobj;
ob::Openbox *arg1 = (ob::Openbox *) 0 ;
@ -2551,6 +2569,57 @@ static PyObject *_wrap_unregister_all(PyObject *self, PyObject *args) {
}
static PyObject *_wrap_bind(PyObject *self, PyObject *args) {
PyObject *resultobj;
PyObject *arg1 = (PyObject *) 0 ;
PyObject *arg2 = (PyObject *) 0 ;
bool result;
PyObject * obj0 = 0 ;
PyObject * obj1 = 0 ;
if(!PyArg_ParseTuple(args,(char *)"OO:bind",&obj0,&obj1)) goto fail;
arg1 = obj0;
arg2 = obj1;
result = (bool)ob::python_bind(arg1,arg2);
resultobj = PyInt_FromLong((long)result);
return resultobj;
fail:
return NULL;
}
static PyObject *_wrap_unbind(PyObject *self, PyObject *args) {
PyObject *resultobj;
PyObject *arg1 = (PyObject *) 0 ;
bool result;
PyObject * obj0 = 0 ;
if(!PyArg_ParseTuple(args,(char *)"O:unbind",&obj0)) goto fail;
arg1 = obj0;
result = (bool)ob::python_unbind(arg1);
resultobj = PyInt_FromLong((long)result);
return resultobj;
fail:
return NULL;
}
static PyObject *_wrap_unbind_all(PyObject *self, PyObject *args) {
PyObject *resultobj;
bool result;
if(!PyArg_ParseTuple(args,(char *)":unbind_all")) goto fail;
result = (bool)ob::python_unbind_all();
resultobj = PyInt_FromLong((long)result);
return resultobj;
fail:
return NULL;
}
static PyMethodDef SwigMethods[] = {
{ (char *)"Openbox_instance", _wrap_Openbox_instance, METH_VARARGS },
{ (char *)"Cursors_session_set", _wrap_Cursors_session_set, METH_VARARGS },
@ -2569,6 +2638,7 @@ static PyMethodDef SwigMethods[] = {
{ (char *)"Openbox_state", _wrap_Openbox_state, METH_VARARGS },
{ (char *)"Openbox_timerManager", _wrap_Openbox_timerManager, METH_VARARGS },
{ (char *)"Openbox_property", _wrap_Openbox_property, METH_VARARGS },
{ (char *)"Openbox_bindings", _wrap_Openbox_bindings, METH_VARARGS },
{ (char *)"Openbox_screen", _wrap_Openbox_screen, METH_VARARGS },
{ (char *)"Openbox_screenCount", _wrap_Openbox_screenCount, METH_VARARGS },
{ (char *)"Openbox_cursors", _wrap_Openbox_cursors, METH_VARARGS },
@ -2649,6 +2719,9 @@ static PyMethodDef SwigMethods[] = {
{ (char *)"preregister", _wrap_preregister, METH_VARARGS },
{ (char *)"unregister", _wrap_unregister, METH_VARARGS },
{ (char *)"unregister_all", _wrap_unregister_all, METH_VARARGS },
{ (char *)"bind", _wrap_bind, METH_VARARGS },
{ (char *)"unbind", _wrap_unbind, METH_VARARGS },
{ (char *)"unbind_all", _wrap_unbind_all, METH_VARARGS },
{ NULL, NULL }
};
@ -2689,6 +2762,7 @@ static swig_type_info _swigt__p_XPropertyEvent[] = {{"_p_XPropertyEvent", 0, "XP
static swig_type_info _swigt__p_XDestroyWindowEvent[] = {{"_p_XDestroyWindowEvent", 0, "XDestroyWindowEvent *", 0},{"_p_XDestroyWindowEvent"},{0}};
static swig_type_info _swigt__p_otk__BImageControl[] = {{"_p_otk__BImageControl", 0, "otk::BImageControl *", 0},{"_p_otk__BImageControl"},{0}};
static swig_type_info _swigt__p_PyObject[] = {{"_p_PyObject", 0, "PyObject *", 0},{"_p_PyObject"},{0}};
static swig_type_info _swigt__p_ob__OBBindings[] = {{"_p_ob__OBBindings", 0, "ob::OBBindings *", 0},{"_p_ob__OBBindings"},{0}};
static swig_type_info _swigt__p_ob__MwmHints[] = {{"_p_ob__MwmHints", 0, "ob::MwmHints *", 0},{"_p_ob__MwmHints"},{0}};
static swig_type_info _swigt__p_otk__Configuration[] = {{"_p_otk__Configuration", 0, "otk::Configuration *", 0},{"_p_otk__Configuration"},{0}};
static swig_type_info _swigt__p_XUnmapEvent[] = {{"_p_XUnmapEvent", 0, "XUnmapEvent *", 0},{"_p_XUnmapEvent"},{0}};
@ -2716,6 +2790,7 @@ _swigt__p_XPropertyEvent,
_swigt__p_XDestroyWindowEvent,
_swigt__p_otk__BImageControl,
_swigt__p_PyObject,
_swigt__p_ob__OBBindings,
_swigt__p_ob__MwmHints,
_swigt__p_otk__Configuration,
_swigt__p_XUnmapEvent,

View file

@ -1,6 +1,7 @@
// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
#include "python.hh"
#include "openbox.hh"
#include <vector>
#include <algorithm>
@ -10,6 +11,7 @@ namespace ob {
typedef std::vector<PyObject*> FunctionList;
static FunctionList callbacks[OBActions::NUM_ACTIONS];
static FunctionList bindfuncs;
bool python_register(int action, PyObject *callback)
{
@ -125,4 +127,83 @@ void python_callback(OBActions::ActionType action, Window window,
Py_DECREF(arglist);
}
bool python_bind(PyObject *keylist, PyObject *callback)
{
if (!PyList_Check(keylist)) {
PyErr_SetString(PyExc_AssertionError, "Invalid keylist. Not a list.");
return false;
}
if (!PyCallable_Check(callback)) {
PyErr_SetString(PyExc_AssertionError, "Invalid callback function.");
return false;
}
OBBindings::StringVect vectkeylist;
for (int i = 0, end = PyList_Size(keylist); i < end; ++i) {
PyObject *str = PyList_GetItem(keylist, i);
if (!PyString_Check(str)) {
PyErr_SetString(PyExc_AssertionError,
"Invalid keylist. It must contain only strings.");
return false;
}
vectkeylist.push_back(PyString_AsString(str));
}
// the id is what the binding class can call back with so it doesnt have to
// worry about the python function pointer
int id = bindfuncs.size();
if (Openbox::instance->bindings()->add(vectkeylist, id)) {
Py_XINCREF(callback); // Add a reference to new callback
bindfuncs.push_back(callback);
return true;
} else {
PyErr_SetString(PyExc_AssertionError,"Unable to create binding. Invalid.");
return false;
}
}
bool python_unbind(PyObject *keylist)
{
if (!PyList_Check(keylist)) {
PyErr_SetString(PyExc_AssertionError, "Invalid keylist. Not a list.");
return false;
}
OBBindings::StringVect vectkeylist;
for (int i = 0, end = PyList_Size(keylist); i < end; ++i) {
PyObject *str = PyList_GetItem(keylist, i);
if (!PyString_Check(str)) {
PyErr_SetString(PyExc_AssertionError,
"Invalid keylist. It must contain only strings.");
return false;
}
vectkeylist.push_back(PyString_AsString(str));
}
int id;
if ((id =
Openbox::instance->bindings()->remove(vectkeylist)) >= 0) {
assert(bindfuncs[id]); // shouldn't be able to remove it twice
Py_XDECREF(bindfuncs[id]); // Dispose of previous callback
// important note: we don't erase the item from the list cuz that would
// ruin all the id's that are in use. simply nullify it.
bindfuncs[id] = 0;
return true;
}
return false;
}
bool python_unbind_all()
{
Openbox::instance->bindings()->remove_all();
return true;
}
}

View file

@ -8,6 +8,7 @@
#include "actions.hh"
#include "widget.hh"
#include "bindings.hh"
extern "C" {
#include <Python.h>
@ -25,6 +26,18 @@ bool python_unregister(int action, PyObject *callback);
//! Removes all python callback functions from the hook list
bool python_unregister_all(int action);
//! Add a mouse/keybinding
/*!
@param keylist A python list of modifier/key/buttons, in the form:
"C-A-space" or "A-Button1" etc.
@param callback A python function to call when the binding is used.
*/
bool python_bind(PyObject *keylist, PyObject *callback);
bool python_unbind(PyObject *keylist);
bool python_unbind_all();
//! Fire a python callback function
void python_callback(OBActions::ActionType action, Window window,
OBWidget::WidgetType type, unsigned int state,