-#include "focus.h"
-#include "openbox.h"
-#include "keyboard.h"
-#include "clientwrap.h"
-
-#include <Python.h>
-#include <glib.h>
-#ifdef HAVE_STRING_H
-# include <string.h>
-#endif
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
-typedef struct KeyBindingTree {
- guint state;
- guint key;
- GList *keylist;
- PyObject *func;
+ keyboard.c for the Openbox window manager
+ Copyright (c) 2006 Mikael Magnusson
+ Copyright (c) 2003-2007 Dana Jansens
- /* the next binding in the tree at the same level */
- struct KeyBindingTree *next_sibling;
- /* the first child of this binding (next binding in a chained sequence).*/
- struct KeyBindingTree *first_child;
-} KeyBindingTree;
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
-static KeyBindingTree *firstnode, *curpos;
-static guint reset_key, reset_state;
-static gboolean grabbed, user_grabbed;
-static PyObject *grab_func;
+ See the COPYING file for a copy of the GNU General Public License.
+*/
-/***************************************************************************
-
- Define the type 'KeyboardData'
-
- ***************************************************************************/
-
-typedef struct KeyboardData {
- PyObject_HEAD
- PyObject *keychain;
- guint state;
- guint keycode;
- gboolean press;
-} KeyboardData;
+#include "focus.h"
+#include "screen.h"
+#include "frame.h"
+#include "openbox.h"
+#include "event.h"
+#include "grab.h"
+#include "client.h"
+#include "actions.h"
+#include "menuframe.h"
+#include "config.h"
+#include "keytree.h"
+#include "keyboard.h"
+#include "translate.h"
+#include "moveresize.h"
+#include "popup.h"
+#include "gettext.h"
+#include "obt/keyboard.h"
-staticforward PyTypeObject KeyboardDataType;
+#include <glib.h>
-/***************************************************************************
-
- Type methods/struct
-
- ***************************************************************************/
+KeyBindingTree *keyboard_firstnode = NULL;
+static ObPopup *popup = NULL;
+static KeyBindingTree *curpos;
+static guint chain_timer = 0;
-static PyObject *keybdata_new(PyObject *keychain, guint state,
- guint keycode, gboolean press)
+static void grab_keys(gboolean grab)
{
- KeyboardData *data = PyObject_New(KeyboardData, &KeyboardDataType);
- data->keychain = keychain;
- Py_INCREF(keychain);
- data->state = state;
- data->keycode = keycode;
- data->press = press;
- return (PyObject*) data;
+ KeyBindingTree *p;
+
+ ungrab_all_keys(obt_root(ob_screen));
+
+ if (grab) {
+ p = curpos ? curpos->first_child : keyboard_firstnode;
+ while (p) {
+ if (p->key)
+ grab_key(p->key, p->state, obt_root(ob_screen),
+ GrabModeAsync);
+ p = p->next_sibling;
+ }
+ if (curpos)
+ grab_key(config_keyboard_reset_keycode,
+ config_keyboard_reset_state,
+ obt_root(ob_screen), GrabModeAsync);
+ }
}
-static void keybdata_dealloc(KeyboardData *self)
+static gboolean chain_timeout(gpointer data)
{
- Py_DECREF(self->keychain);
- PyObject_Del((PyObject*)self);
+ keyboard_reset_chains(0);
+ return FALSE; /* don't repeat */
}
-static PyObject *keybdata_getattr(KeyboardData *self, char *name)
+static void chain_done(gpointer data)
{
- if (!strcmp(name, "keychain")) {
- Py_INCREF(self->keychain);
- return self->keychain;
- } else if (!strcmp(name, "state"))
- return PyInt_FromLong(self->state);
- else if (!strcmp(name, "keycode"))
- return PyInt_FromLong(self->keycode);
- else if (!strcmp(name, "press"))
- return PyInt_FromLong(!!self->press);
-
- PyErr_Format(PyExc_AttributeError, "no such attribute '%s'", name);
- return NULL;
+ chain_timer = 0;
}
-static PyTypeObject KeyboardDataType = {
- PyObject_HEAD_INIT(NULL)
- 0,
- "KeyboardData",
- sizeof(KeyboardData),
- 0,
- (destructor) keybdata_dealloc, /*tp_dealloc*/
- 0, /*tp_print*/
- (getattrfunc) keybdata_getattr, /*tp_getattr*/
- 0, /*tp_setattr*/
- 0, /*tp_compare*/
- 0, /*tp_repr*/
- 0, /*tp_as_number*/
- 0, /*tp_as_sequence*/
- 0, /*tp_as_mapping*/
- 0, /*tp_hash */
-};
-
-/***************************************************************************/
-
-guint keyboard_translate_modifier(char *str)
+static void set_curpos(KeyBindingTree *newpos)
{
- if (!strcmp("Mod1", str)) return Mod1Mask;
- else if (!strcmp("Mod2", str)) return Mod2Mask;
- else if (!strcmp("Mod3", str)) return Mod3Mask;
- else if (!strcmp("Mod4", str)) return Mod4Mask;
- else if (!strcmp("Mod5", str)) return Mod5Mask;
- else if (!strcmp("C", str)) return ControlMask;
- else if (!strcmp("S", str)) return ShiftMask;
- g_warning("Invalid modifier '%s' in binding.", str);
- return 0;
-}
+ if (curpos == newpos) return;
-static gboolean translate(char *str, guint *state, guint *keycode)
-{
- char **parsed;
- char *l;
- int i;
- gboolean ret = FALSE;
- KeySym sym;
-
- parsed = g_strsplit(str, "-", -1);
-
- /* first, find the key (last token) */
- l = NULL;
- for (i = 0; parsed[i] != NULL; ++i)
- l = parsed[i];
- if (l == NULL)
- goto translation_fail;
-
- /* figure out the mod mask */
- *state = 0;
- for (i = 0; parsed[i] != l; ++i) {
- guint m = keyboard_translate_modifier(parsed[i]);
- if (!m) goto translation_fail;
- *state |= m;
- }
+ grab_keys(FALSE);
+ curpos = newpos;
+ grab_keys(TRUE);
- /* figure out the keycode */
- sym = XStringToKeysym(l);
- if (sym == NoSymbol) {
- g_warning("Invalid key name '%s' in key binding.", l);
- goto translation_fail;
- }
- *keycode = XKeysymToKeycode(ob_display, sym);
- if (!keycode) {
- g_warning("Key '%s' does not exist on the display.", l);
- goto translation_fail;
+ if (curpos != NULL) {
+ gchar *text = NULL;
+ GList *it;
+ const Rect *a;
+
+ for (it = curpos->keylist; it; it = g_list_next(it)) {
+ gchar *oldtext = text;
+ if (text == NULL)
+ text = g_strdup(it->data);
+ else
+ text = g_strconcat(text, " - ", it->data, NULL);
+ g_free(oldtext);
+ }
+
+ a = screen_physical_area_primary(FALSE);
+ popup_position(popup, NorthWestGravity, a->x + 10, a->y + 10);
+ /* 1 second delay for the popup to show */
+ popup_delay_show(popup, 1000, text);
+ g_free(text);
+ } else {
+ popup_hide(popup);
}
-
- ret = TRUE;
-
-translation_fail:
- g_strfreev(parsed);
- return ret;
}
-static void destroytree(KeyBindingTree *tree)
+void keyboard_reset_chains(gint break_chroots)
{
- KeyBindingTree *c;
-
- while (tree) {
- destroytree(tree->next_sibling);
- c = tree->first_child;
- if (c == NULL) {
- GList *it;
- for (it = tree->keylist; it != NULL; it = it->next)
- g_free(it->data);
- g_list_free(tree->keylist);
- Py_XDECREF(tree->func);
- }
- g_free(tree);
- tree = c;
+ KeyBindingTree *p;
+
+ for (p = curpos; p; p = p->parent) {
+ if (p->chroot) {
+ if (break_chroots == 0) break; /* stop here */
+ if (break_chroots > 0)
+ --break_chroots;
+ }
}
+ set_curpos(p);
}
-static KeyBindingTree *buildtree(GList *keylist)
+void keyboard_unbind_all(void)
{
- GList *it;
- KeyBindingTree *ret = NULL, *p;
-
- if (g_list_length(keylist) <= 0)
- return NULL; /* nothing in the list.. */
-
- for (it = g_list_last(keylist); it != NULL; it = it->prev) {
- p = ret;
- ret = g_new(KeyBindingTree, 1);
- ret->next_sibling = NULL;
- ret->func = NULL;
- if (p == NULL) {
- GList *it;
-
- /* this is the first built node, the bottom node of the tree */
- ret->keylist = g_list_copy(keylist); /* shallow copy */
- for (it = ret->keylist; it != NULL; it = it->next) /* deep copy */
- it->data = g_strdup(it->data);
- }
- ret->first_child = p;
- if (!translate(it->data, &ret->state, &ret->key)) {
- destroytree(ret);
- return NULL;
- }
- }
- return ret;
+ tree_destroy(keyboard_firstnode);
+ keyboard_firstnode = NULL;
}
-static void assimilate(KeyBindingTree *node)
+void keyboard_chroot(GList *keylist)
{
- KeyBindingTree *a, *b, *tmp, *last;
-
- if (firstnode == NULL) {
- /* there are no nodes at this level yet */
- firstnode = node;
- } else {
- a = firstnode;
- last = a;
- b = node;
- while (a) {
- last = a;
- if (!(a->state == b->state && a->key == b->key)) {
- a = a->next_sibling;
- } else {
- tmp = b;
- b = b->first_child;
- g_free(tmp);
- a = a->first_child;
- }
- }
- if (!(last->state == b->state && last->key == b->key))
- last->next_sibling = b;
- else {
- last->first_child = b->first_child;
- g_free(b);
- }
+ /* try do it in the existing tree. if we can't that means it is an empty
+ chroot binding. so add it to the tree then. */
+ if (!tree_chroot(keyboard_firstnode, keylist)) {
+ KeyBindingTree *tree;
+ if (!(tree = tree_build(keylist)))
+ return;
+ tree_chroot(tree, keylist);
+ tree_assimilate(tree);
}
}
-static KeyBindingTree *find(KeyBindingTree *search, gboolean *conflict)
+gboolean keyboard_bind(GList *keylist, ObActionsAct *action)
{
- KeyBindingTree *a, *b;
-
- *conflict = FALSE;
-
- a = firstnode;
- b = search;
- while (a && b) {
- if (!(a->state == b->state && a->key == b->key)) {
- a = a->next_sibling;
- } else {
- if ((a->first_child == NULL) == (b->first_child == NULL)) {
- if (a->first_child == NULL) {
- /* found it! (return the actual node, not the search's) */
- return a;
- }
- } else {
- *conflict = TRUE;
- return NULL; /* the chain status' don't match (conflict!) */
- }
- b = b->first_child;
- a = a->first_child;
- }
- }
- return NULL; // it just isn't in here
-}
+ KeyBindingTree *tree, *t;
+ gboolean conflict;
-static void grab_keys(gboolean grab)
-{
- if (!grab) {
- XUngrabKey(ob_display, AnyKey, AnyModifier, ob_root);
- } else {
- KeyBindingTree *p = firstnode;
- while (p) {
- XGrabKey(ob_display, p->key, p->state, ob_root, FALSE,
- GrabModeAsync, GrabModeSync);
- p = p->next_sibling;
- }
- }
-}
+ g_assert(keylist != NULL);
+ g_assert(action != NULL);
-static void reset_chains()
-{
- /* XXX kill timer */
- curpos = NULL;
- if (grabbed) {
- grabbed = FALSE;
- g_message("reset chains. user_grabbed: %d", user_grabbed);
- if (!user_grabbed)
- XUngrabKeyboard(ob_display, CurrentTime);
- }
-}
+ if (!(tree = tree_build(keylist)))
+ return FALSE;
-void keyboard_event(XKeyEvent *e)
-{
- PyObject *chain, *client, *args, *keybdata, *ret;
- gboolean press = e->type == KeyPress;
-
- if (focus_client) client = clientwrap_new(focus_client);
- else client = Py_None;
-
- if (user_grabbed) {
- GString *str = g_string_sized_new(0);
- KeySym sym;
-
- /* build the 'chain' */
- if (e->state & ControlMask)
- g_string_append(str, "C-");
- if (e->state & ShiftMask)
- g_string_append(str, "S-");
- if (e->state & Mod1Mask)
- g_string_append(str, "Mod1-");
- if (e->state & Mod2Mask)
- g_string_append(str, "Mod2-");
- if (e->state & Mod3Mask)
- g_string_append(str, "Mod3-");
- if (e->state & Mod4Mask)
- g_string_append(str, "Mod4-");
- if (e->state & Mod5Mask)
- g_string_append(str, "Mod5-");
-
- sym = XKeycodeToKeysym(ob_display, e->keycode, 0);
- if (sym == NoSymbol)
- g_string_append(str, "NoSymbol");
- else {
- char *name = XKeysymToString(sym);
- if (name == NULL)
- name = "Undefined";
- g_string_append(str, name);
- }
-
- chain = PyTuple_New(1);
- PyTuple_SET_ITEM(chain, 0, PyString_FromString(str->str));
- g_string_free(str, TRUE);
-
- keybdata = keybdata_new(chain, e->state, e->keycode, press);
-
- args = Py_BuildValue("OO", keybdata, client);
-
- ret = PyObject_CallObject(grab_func, args);
- if (ret == NULL) PyErr_Print();
- Py_XDECREF(ret);
-
- Py_DECREF(args);
- Py_DECREF(keybdata);
- Py_DECREF(chain);
- }
+ if ((t = tree_find(tree, &conflict)) != NULL) {
+ /* already bound to something, use the existing tree */
+ tree_destroy(tree);
+ tree = NULL;
+ } else
+ t = tree;
- if (press) {
- if (e->keycode == reset_key && e->state == reset_state) {
- reset_chains();
- XAllowEvents(ob_display, AsyncKeyboard, CurrentTime);
- } else {
- KeyBindingTree *p;
- if (curpos == NULL)
- p = firstnode;
- else
- p = curpos->first_child;
- while (p) {
- if (p->key == e->keycode && p->state == e->state) {
- if (p->first_child != NULL) { /* part of a chain */
- /* XXX TIMER */
- if (!grabbed && !user_grabbed) {
- /*grab should never fail because we should have a
- sync grab at this point */
- XGrabKeyboard(ob_display, ob_root, 0,
- GrabModeAsync, GrabModeSync,
- CurrentTime);
- }
- grabbed = TRUE;
- curpos = p;
- XAllowEvents(ob_display, AsyncKeyboard, CurrentTime);
- } else {
- GList *it;
- int i;
-
- chain = PyTuple_New(g_list_length(p->keylist));
- for (i = 0, it = p->keylist; it != NULL;
- it = it->next, ++i)
- PyTuple_SET_ITEM(chain, i,
- PyString_FromString(it->data));
-
- keybdata = keybdata_new(chain, e->state, e->keycode,
- press);
-
- args = Py_BuildValue("OO", keybdata, client);
-
- ret = PyObject_CallObject(p->func, args);
- if (ret == NULL) PyErr_Print();
- Py_XDECREF(ret);
-
- Py_DECREF(args);
- Py_DECREF(keybdata);
- Py_DECREF(chain);
-
- XAllowEvents(ob_display, AsyncKeyboard, CurrentTime);
- reset_chains();
- }
- break;
- }
- p = p->next_sibling;
- }
- }
+ if (conflict) {
+ g_message(_("Conflict with key binding in config file"));
+ tree_destroy(tree);
+ return FALSE;
}
- if (client != Py_None) { Py_DECREF(client); }
-}
+ /* find the bottom node */
+ for (; t->first_child; t = t->first_child);
-static void clearall()
-{
- grab_keys(FALSE);
- destroytree(firstnode);
- firstnode = NULL;
- grab_keys(TRUE);
+ /* set the action */
+ t->actions = g_slist_append(t->actions, action);
+ /* assimilate this built tree into the main tree. assimilation
+ destroys/uses the tree */
+ if (tree) tree_assimilate(tree);
+
+ return TRUE;
}
-static gboolean grab_keyboard(gboolean grab)
+#if 0
+gboolean keyboard_process_interactive_grab(const XEvent *e, ObClient **client)
{
- gboolean ret = TRUE;
-
- g_message("grab_keyboard(%s). grabbed: %d", (grab?"True":"False"),grabbed);
-
- user_grabbed = grab;
- if (!grabbed) {
- if (grab)
- ret = XGrabKeyboard(ob_display, ob_root, 0, GrabModeAsync,
- GrabModeAsync, CurrentTime) == GrabSuccess;
- else
- XUngrabKeyboard(ob_display, CurrentTime);
+ gboolean handled = FALSE;
+ gboolean done = FALSE;
+ gboolean cancel = FALSE;
+ guint mods;
+
+ mods = obt_keyboard_only_modmasks(ev->xkey.state);
+
+ if (istate.active) {
+ if ((e->type == KeyRelease && !(istate.state & mods))) {
+ done = TRUE;
+ handled = TRUE;
+ } else if (e->type == KeyPress) {
+ /*if (e->xkey.keycode == ob_keycode(OB_KEY_RETURN))
+ done = TRUE;
+ else */if (e->xkey.keycode == ob_keycode(OB_KEY_ESCAPE)) {
+ cancel = done = TRUE;
+ handled = TRUE;
+ }
+ } else if (e->type == ButtonPress) {
+ cancel = TRUE;
+ done = TRUE;
+ handled = FALSE;
+ }
+
+ if (done)
+ keyboard_interactive_end(e->xkey.state, cancel, e->xkey.time,TRUE);
+
+ if (handled)
+ *client = istate.client;
}
- return ret;
-}
-
-/***************************************************************************
-
- Define the type 'Keyboard'
-
- ***************************************************************************/
-#define IS_KEYBOARD(v) ((v)->ob_type == &KeyboardType)
-#define CHECK_KEYBOARD(self, funcname) { \
- if (!IS_KEYBOARD(self)) { \
- PyErr_SetString(PyExc_TypeError, \
- "descriptor '" funcname "' requires a 'Keyboard' " \
- "object"); \
- return NULL; \
- } \
+ return handled;
}
+#endif
-typedef struct Keyboard {
- PyObject_HEAD
-} Keyboard;
-
-staticforward PyTypeObject KeyboardType;
-
-static PyObject *keyb_bind(Keyboard *self, PyObject *args)
+gboolean keyboard_event(ObClient *client, const XEvent *e)
{
- KeyBindingTree *tree = NULL, *t;
- gboolean conflict;
- PyObject *item, *tuple, *func;
- GList *keylist = NULL, *it;
- int i, s;
-
- CHECK_KEYBOARD(self, "grab");
- if (!PyArg_ParseTuple(args, "OO:grab", &tuple, &func))
- return NULL;
+ KeyBindingTree *p;
+ gboolean used;
+ guint mods;
- if (!PyTuple_Check(tuple)) {
- PyErr_SetString(PyExc_ValueError, "expected a tuple of strings");
- goto binderror;
- }
- if (!PyCallable_Check(func)) {
- PyErr_SetString(PyExc_ValueError, "expected a callable object");
- goto binderror;
+ if (e->type == KeyRelease) {
+ grab_key_passive_count(-1);
+ return FALSE;
}
- s = PyTuple_GET_SIZE(tuple);
- if (s <= 0) {
- PyErr_SetString(PyExc_ValueError, "expected a tuple of strings");
- goto binderror;
- }
+ g_assert(e->type == KeyPress);
+ grab_key_passive_count(1);
- for (i = 0; i < s; ++i) {
- item = PyTuple_GET_ITEM(tuple, i);
- if (!PyString_Check(item)) {
- PyErr_SetString(PyExc_ValueError, "expected a tuple of strings");
- goto binderror;
- }
- keylist = g_list_append(keylist,
- g_strdup(PyString_AsString(item)));
- }
+ mods = obt_keyboard_only_modmasks(e->xkey.state);
- if (!(tree = buildtree(keylist))) {
- PyErr_SetString(PyExc_ValueError, "invalid binding");
- goto binderror;
+ if (e->xkey.keycode == config_keyboard_reset_keycode &&
+ mods == config_keyboard_reset_state)
+ {
+ if (chain_timer) g_source_remove(chain_timer);
+ keyboard_reset_chains(-1);
+ return TRUE;
}
- t = find(tree, &conflict);
- if (conflict) {
- PyErr_SetString(PyExc_ValueError, "conflict with binding");
- goto binderror;
- }
- if (t != NULL) {
- /* already bound to something */
- PyErr_SetString(PyExc_ValueError, "keychain is already bound");
- goto binderror;
+ used = FALSE;
+ if (curpos == NULL)
+ p = keyboard_firstnode;
+ else
+ p = curpos->first_child;
+ while (p) {
+ if (p->key == e->xkey.keycode && p->state == mods) {
+ /* if we hit a key binding, then close any open menus and run it */
+ if (menu_frame_visible)
+ menu_frame_hide_all();
+
+ if (p->first_child != NULL) { /* part of a chain */
+ if (chain_timer) g_source_remove(chain_timer);
+ /* 3 second timeout for chains */
+ chain_timer =
+ g_timeout_add_full(G_PRIORITY_DEFAULT,
+ 3000, chain_timeout, NULL,
+ chain_done);
+ set_curpos(p);
+ } else if (p->chroot) /* an empty chroot */
+ set_curpos(p);
+ else {
+ GSList *it;
+
+ for (it = p->actions; it; it = g_slist_next(it))
+ if (actions_act_is_interactive(it->data)) break;
+ if (it == NULL) /* reset if the actions are not interactive */
+ keyboard_reset_chains(0);
+
+ actions_run_acts(p->actions, OB_USER_ACTION_KEYBOARD_KEY,
+ e->xkey.state, e->xkey.x_root, e->xkey.y_root,
+ 0, OB_FRAME_CONTEXT_NONE, client);
+ }
+ break;
+ used = TRUE;
+ }
+ p = p->next_sibling;
}
-
- /* grab the server here to make sure no key pressed go missed */
- XGrabServer(ob_display);
- XSync(ob_display, FALSE);
-
- grab_keys(FALSE);
-
- /* set the function */
- t = tree;
- while (t->first_child) t = t->first_child;
- t->func = func;
- Py_INCREF(func);
-
- /* assimilate this built tree into the main tree */
- assimilate(tree); // assimilation destroys/uses the tree
-
- grab_keys(TRUE);
-
- XUngrabServer(ob_display);
- XFlush(ob_display);
-
- for (it = keylist; it != NULL; it = it->next)
- g_free(it->data);
- g_list_free(it);
-
- Py_INCREF(Py_None);
- return Py_None;
-
-binderror:
- if (tree != NULL) destroytree(tree);
- for (it = keylist; it != NULL; it = it->next)
- g_free(it->data);
- g_list_free(it);
- return NULL;
+ return used;
}
-static PyObject *keyb_clearBinds(Keyboard *self, PyObject *args)
+static void node_rebind(KeyBindingTree *node)
{
- CHECK_KEYBOARD(self, "clearBinds");
- if (!PyArg_ParseTuple(args, ":clearBinds"))
- return NULL;
- clearall();
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-static PyObject *keyb_grab(Keyboard *self, PyObject *args)
-{
- PyObject *func;
-
- CHECK_KEYBOARD(self, "grab");
- if (!PyArg_ParseTuple(args, "O:grab", &func))
- return NULL;
- if (!PyCallable_Check(func)) {
- PyErr_SetString(PyExc_ValueError, "expected a callable object");
- return NULL;
+ if (node->first_child) {
+ /* find leaf nodes */
+ node_rebind(node->first_child);
+
+ /* for internal nodes, add them to the tree if they
+ are a chroot, but do this after adding their
+ children */
+ if (node->chroot)
+ keyboard_chroot(node->keylist);
}
- if (!grab_keyboard(TRUE)) {
- PyErr_SetString(PyExc_RuntimeError, "failed to grab keyboard");
- return NULL;
+ else {
+ /* for leaf nodes, rebind each action assigned to it */
+ while (node->actions) {
+ /* add each action, and remove them from the original tree so
+ they don't get free'd on us */
+ keyboard_bind(node->keylist, node->actions->data);
+ node->actions = g_slist_delete_link(node->actions, node->actions);
+ }
+
+ if (node->chroot)
+ keyboard_chroot(node->keylist);
}
- grab_func = func;
- Py_INCREF(grab_func);
- Py_INCREF(Py_None);
- return Py_None;
+
+ /* go through each sibling */
+ if (node->next_sibling) node_rebind(node->next_sibling);
}
-static PyObject *keyb_ungrab(Keyboard *self, PyObject *args)
+void keyboard_rebind(void)
{
- CHECK_KEYBOARD(self, "ungrab");
- if (!PyArg_ParseTuple(args, ":ungrab"))
- return NULL;
- grab_keyboard(FALSE);
- Py_XDECREF(grab_func);
- grab_func = NULL;
- Py_INCREF(Py_None);
- return Py_None;
+ KeyBindingTree *old;
+
+ old = keyboard_firstnode;
+ keyboard_firstnode = NULL;
+ node_rebind(old);
+
+ tree_destroy(old);
+ set_curpos(NULL);
+ grab_keys(TRUE);
}
-#define METH(n, d) {#n, (PyCFunction)keyb_##n, METH_VARARGS, #d}
-
-static PyMethodDef KeyboardMethods[] = {
- METH(bind,
- "bind(keychain, func)\n\n"
- "Binds a key-chain to a function. The keychain is a tuple of strings "
- "which define a chain of key presses. Each member of the tuple has "
- "the format [Modifier-]...[Key]. Modifiers can be 'mod1', 'mod2', "
- "'mod3', 'mod4', 'mod5', 'control', and 'shift'. The keys on your "
- "keyboard that are bound to each of these modifiers can be found by "
- "running 'xmodmap'. The Key can be any valid key definition. Key "
- "definitions can be found by running 'xev', pressing the key while "
- "its window is focused, and watching its output. Here are some "
- "examples of valid keychains: ('a'), ('F7'), ('control-a', 'd'), "
- "('control-mod1-x', 'control-mod4-g'), ('F1', 'space'). The func "
- "must have a definition similar to 'def func(keydata, client)'. A "
- "keychain cannot be bound to more than one function."),
- METH(clearBinds,
- "clearBinds()\n\n"
- "Removes all bindings that were previously made by bind()."),
- METH(grab,
- "grab(func)\n\n"
- "Grabs the entire keyboard, causing all possible keyboard events to "
- "be passed to the given function. CAUTION: Be sure when you grab() "
- "that you also have an ungrab() that will execute, or you will not "
- "be able to type until you restart Openbox. The func must have a "
- "definition similar to 'def func(keydata)'. The keyboard cannot be "
- "grabbed if it is already grabbed."),
- METH(ungrab,
- "ungrab()\n\n"
- "Ungrabs the keyboard. The keyboard cannot be ungrabbed if it is not "
- "grabbed."),
- { NULL, NULL, 0, NULL }
-};
-
-/***************************************************************************
-
- Type methods/struct
-
- ***************************************************************************/
-
-static void keyb_dealloc(PyObject *self)
+void keyboard_startup(gboolean reconfig)
{
- PyObject_Del(self);
+ grab_keys(TRUE);
+ popup = popup_new();
+ popup_set_text_align(popup, RR_JUSTIFY_CENTER);
}
-static PyTypeObject KeyboardType = {
- PyObject_HEAD_INIT(NULL)
- 0,
- "Keyboard",
- sizeof(Keyboard),
- 0,
- (destructor) keyb_dealloc, /*tp_dealloc*/
- 0, /*tp_print*/
- 0, /*tp_getattr*/
- 0, /*tp_setattr*/
- 0, /*tp_compare*/
- 0, /*tp_repr*/
- 0, /*tp_as_number*/
- 0, /*tp_as_sequence*/
- 0, /*tp_as_mapping*/
- 0, /*tp_hash */
-};
-
-/**************************************************************************/
-
-void keyboard_startup()
+void keyboard_shutdown(gboolean reconfig)
{
- PyObject *input, *inputdict, *ptr;
- gboolean b;
-
- curpos = firstnode = NULL;
- grabbed = user_grabbed = FALSE;
-
- b = translate("C-G", &reset_state, &reset_key);
- g_assert(b);
+ if (chain_timer) g_source_remove(chain_timer);
- KeyboardType.ob_type = &PyType_Type;
- KeyboardType.tp_methods = KeyboardMethods;
- PyType_Ready(&KeyboardType);
- PyType_Ready(&KeyboardDataType);
+ keyboard_unbind_all();
+ set_curpos(NULL);
- /* get the input module/dict */
- input = PyImport_ImportModule("input"); /* new */
- g_assert(input != NULL);
- inputdict = PyModule_GetDict(input); /* borrowed */
- g_assert(inputdict != NULL);
-
- /* add a Keyboard instance to the input module */
- ptr = (PyObject*) PyObject_New(Keyboard, &KeyboardType);
- PyDict_SetItemString(inputdict, "Keyboard", ptr);
- Py_DECREF(ptr);
-
- Py_DECREF(input);
+ popup_free(popup);
+ popup = NULL;
}
-
-void keyboard_shutdown()
-{
- if (grabbed || user_grabbed) {
- grabbed = FALSE;
- grab_keyboard(FALSE);
- }
- grab_keys(FALSE);
- destroytree(firstnode);
- firstnode = NULL;
-}
-