]> Dogcows Code - chaz/openbox/blobdiff - openbox/keyboard.c
ungrab the keyboard for passive grabs. kill interactive actions for exec actions...
[chaz/openbox] / openbox / keyboard.c
index 87cd5036a26b348a23210476fb4ece5be47d8d6f..ab9d05b09859c631b026bbf31d307adeba1b0c83 100644 (file)
-#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'
+#include "mainloop.h"
+#include "focus.h"
+#include "screen.h"
+#include "frame.h"
+#include "openbox.h"
+#include "event.h"
+#include "grab.h"
+#include "client.h"
+#include "action.h"
+#include "prop.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 <glib.h>
 
-typedef struct KeyboardData {
-    PyObject_HEAD
-    PyObject *keychain;
+typedef struct {
+    gboolean active;
     guint state;
-    guint keycode;
-    gboolean press;
-} KeyboardData;
+    ObClient *client;
+    ObAction *action;
+} ObInteractiveState;
 
-staticforward PyTypeObject KeyboardDataType;
+KeyBindingTree *keyboard_firstnode = NULL;
+static ObPopup *popup = NULL;
+static ObInteractiveState istate;
+static KeyBindingTree *curpos;
 
-/***************************************************************************
-   Type methods/struct
- ***************************************************************************/
-
-static PyObject *keybdata_new(PyObject *keychain, guint state,
-                             guint keycode, gboolean press)
-{
-    KeyboardData *data = PyObject_New(KeyboardData, &KeyboardDataType);
-    data->keychain = keychain;
-    Py_INCREF(keychain);
-    data->state = state;
-    data->keycode = keycode;
-    data->press = press;
-    return (PyObject*) data;
-}
-
-static void keybdata_dealloc(KeyboardData *self)
-{
-    Py_DECREF(self->keychain);
-    PyObject_Del((PyObject*)self);
-}
-
-static PyObject *keybdata_getattr(KeyboardData *self, char *name)
+static void grab_keys(gboolean grab)
 {
-    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;
+    KeyBindingTree *p;
+
+    ungrab_all_keys(RootWindow(ob_display, ob_screen));
+
+    if (grab) {
+        p = curpos ? curpos->first_child : keyboard_firstnode;
+        while (p) {
+            grab_key(p->key, p->state, RootWindow(ob_display, ob_screen),
+                     GrabModeAsync);
+            p = p->next_sibling;
+        }
+        if (curpos)
+            grab_key(config_keyboard_reset_keycode,
+                     config_keyboard_reset_state,
+                     RootWindow(ob_display, ob_screen), GrabModeAsync);
+    }
 }
 
-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 gboolean chain_timeout(gpointer data)
 {
-    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;
+    keyboard_reset_chains(0);
+    return FALSE; /* don't repeat */
 }
 
-static gboolean translate(char *str, guint *state, guint *keycode)
+static void set_curpos(KeyBindingTree *newpos)
 {
-    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;
+    if (curpos != newpos) {
+        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;
+
+        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);
+        }
+
+        popup_position(popup, NorthWestGravity, 10, 10);
+        /* 1 second delay for the popup to show */
+        popup_delay_show(popup, G_USEC_PER_SEC, 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()
 {
-    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, ObAction *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;
+    gboolean mods = TRUE;
 
-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;
+
+    if ((t = tree_find(tree, &conflict)) != NULL) {
+        /* already bound to something, use the existing tree */
+        tree_destroy(tree);
+        tree = NULL;
+    } else
+        t = tree;
+
+    if (conflict) {
+        g_message(_("Conflict with key binding in config file"));
+        tree_destroy(tree);
+        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);
+    /* find if every key in this chain has modifiers, and also find the
+       bottom node of the tree */
+    while (t->first_child) {
+        if (!t->state)
+            mods = FALSE;
+        t = t->first_child;
     }
 
-    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;
-           }
-       }
+    /* when there are no modifiers in the binding, then the action cannot
+       be interactive */
+    if (!mods && action->data.any.interactive) {
+        action->data.any.interactive = FALSE;
+        action->data.inter.final = TRUE;
     }
 
-    if (client != Py_None) { Py_DECREF(client); }
-}
+    /* 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);
 
-static void clearall()
-{
-    grab_keys(FALSE);
-    destroytree(firstnode);
-    firstnode = NULL;
-    grab_keys(TRUE);
+    return TRUE;
 }
 
-static gboolean grab_keyboard(gboolean grab)
+static void keyboard_interactive_end(guint state, gboolean cancel, Time time,
+                                     gboolean ungrab)
 {
-    gboolean ret = TRUE;
+    GSList *alist;
 
-    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);
-    }
-    return ret;
-}
+    g_assert(istate.active);
 
-/***************************************************************************
-   Define the type 'Keyboard'
+    /* ungrab first so they won't be NotifyWhileGrabbed */
+    if (ungrab)
+        ungrab_keyboard();
 
- ***************************************************************************/
+    /* set this before running the actions so they know the keyboard is not
+       grabbed */
+    istate.active = FALSE;
 
-#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; \
-    } \
+    alist = g_slist_append(NULL, istate.action);
+    action_run_interactive(alist, istate.client, state, time, cancel, TRUE);
+    g_slist_free(alist);
 }
 
-typedef struct Keyboard {
-    PyObject_HEAD
-} Keyboard;
+static void keyboard_interactive_end_client(ObClient *client, gpointer data)
+{
+    if (istate.active && istate.client == client)
+        istate.client = NULL;
+}
 
-staticforward PyTypeObject KeyboardType;
 
-static PyObject *keyb_bind(Keyboard *self, PyObject *args)
+void keyboard_interactive_cancel()
 {
-    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;
+    keyboard_interactive_end(0, TRUE, event_curtime, TRUE);
+}
 
-    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;
-    }
+gboolean keyboard_interactive_grab(guint state, ObClient *client,
+                                   ObAction *action)
+{
+    g_assert(action->data.any.interactive);
 
-    s = PyTuple_GET_SIZE(tuple);
-    if (s <= 0) {
-       PyErr_SetString(PyExc_ValueError, "expected a tuple of strings");
-       goto binderror;
+    if (!istate.active) {
+        if (!grab_keyboard())
+            return FALSE;
+    } else if (action->func != istate.action->func) {
+        keyboard_interactive_end(state, TRUE, action->data.any.time, FALSE);
     }
 
-    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)));
-    }
+    istate.active = TRUE;
+    istate.state = state;
+    istate.client = client;
+    istate.action = action;
 
-    if (!(tree = buildtree(keylist))) {
-       PyErr_SetString(PyExc_ValueError, "invalid binding");
-       goto binderror;
-    }
+    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;
+gboolean keyboard_process_interactive_grab(const XEvent *e, ObClient **client)
+{
+    gboolean handled = FALSE;
+    gboolean done = FALSE;
+    gboolean cancel = FALSE;
+
+    if (istate.active) {
+        if ((e->type == KeyRelease && !(istate.state & e->xkey.state))) {
+            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;
     }
 
-    /* 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 handled;
 }
 
-static PyObject *keyb_clearBinds(Keyboard *self, PyObject *args)
+void keyboard_event(ObClient *client, const XEvent *e)
 {
-    CHECK_KEYBOARD(self, "clearBinds");
-    if (!PyArg_ParseTuple(args, ":clearBinds"))
-       return NULL;
-    clearall();
-    Py_INCREF(Py_None);
-    return Py_None;
-}
+    KeyBindingTree *p;
 
-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;
+    g_assert(e->type == KeyPress);
+
+    if (e->xkey.keycode == config_keyboard_reset_keycode &&
+        e->xkey.state == config_keyboard_reset_state)
+    {
+        ob_main_loop_timeout_remove(ob_main_loop, chain_timeout);
+        keyboard_reset_chains(-1);
+        return;
     }
-    if (!grab_keyboard(TRUE)) {
-       PyErr_SetString(PyExc_RuntimeError, "failed to grab keyboard");
-       return NULL;
+
+    if (curpos == NULL)
+        p = keyboard_firstnode;
+    else
+        p = curpos->first_child;
+    while (p) {
+        if (p->key == e->xkey.keycode &&
+            p->state == e->xkey.state)
+        {
+            /* 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 */
+                ob_main_loop_timeout_remove(ob_main_loop, chain_timeout);
+                /* 3 second timeout for chains */
+                ob_main_loop_timeout_add(ob_main_loop, 3 * G_USEC_PER_SEC,
+                                         chain_timeout, NULL,
+                                         g_direct_equal, NULL);
+                set_curpos(p);
+            } else if (p->chroot)         /* an empty chroot */
+                set_curpos(p);
+            else {
+                keyboard_reset_chains(0);
+
+                /* If we don't have the keyboard grabbed, then ungrab it with
+                   XUngrabKeyboard, so that there is not a passive grab left
+                   on from the KeyPress. If the grab is left on, and focus
+                   moves during that time, it will be NotifyWhileGrabbed, and
+                   applications like to ignore those! */
+                if (!keyboard_interactively_grabbed())
+                    XUngrabKeyboard(ob_display, e->xkey.time);
+
+                action_run_key(p->actions, client, e->xkey.state,
+                               e->xkey.x_root, e->xkey.y_root,
+                               e->xkey.time);
+            }
+            break;
+        }
+        p = p->next_sibling;
     }
-    grab_func = func;
-    Py_INCREF(grab_func);
-    Py_INCREF(Py_None);
-    return Py_None;
 }
 
-static PyObject *keyb_ungrab(Keyboard *self, PyObject *args)
+gboolean keyboard_interactively_grabbed()
 {
-    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;
+    return istate.active;
 }
 
-#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(FALSE);
+
+    if (!reconfig)
+        client_add_destroy_notify(keyboard_interactive_end_client, NULL);
 }
 
-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;
+    if (!reconfig)
+        client_remove_destroy_notify(keyboard_interactive_end_client);
 
-    b = translate("C-G", &reset_state, &reset_key);
-    g_assert(b);
+    if (istate.active)
+        keyboard_interactive_cancel();
 
-    KeyboardType.ob_type = &PyType_Type;
-    KeyboardType.tp_methods = KeyboardMethods;
-    PyType_Ready(&KeyboardType);
-    PyType_Ready(&KeyboardDataType);
+    ob_main_loop_timeout_remove(ob_main_loop, chain_timeout);
 
-    /* get the input module/dict */
-    input = PyImport_ImportModule("input"); /* new */
-    g_assert(input != NULL);
-    inputdict = PyModule_GetDict(input); /* borrowed */
-    g_assert(inputdict != NULL);
+    keyboard_unbind_all();
+    set_curpos(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);
-}
-
-void keyboard_shutdown()
-{
-    if (grabbed || user_grabbed) {
-       grabbed = FALSE;
-       grab_keyboard(FALSE);
-    }
-    grab_keys(FALSE);
-    destroytree(firstnode);
-    firstnode = NULL;
+    popup_free(popup);
+    popup = NULL;
 }
 
This page took 0.042031 seconds and 4 git commands to generate.