]> Dogcows Code - chaz/openbox/blobdiff - c/mbind.c
merge the C branch into HEAD
[chaz/openbox] / c / mbind.c
diff --git a/c/mbind.c b/c/mbind.c
new file mode 100644 (file)
index 0000000..f363be6
--- /dev/null
+++ b/c/mbind.c
@@ -0,0 +1,220 @@
+#include "mbind.h"
+#include "kbind.h"
+#include "frame.h"
+#include "openbox.h"
+#include "eventdata.h"
+#include "hooks.h"
+
+#include <glib.h>
+#ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+#endif
+
+/* GData of GSList*'s of PointerBinding*'s. */
+static GData *bound_contexts;
+
+static gboolean grabbed;
+
+struct mbind_foreach_grab_temp {
+    Client *client;
+    gboolean grab;
+};
+
+typedef struct {
+    guint state;
+    guint button;
+    char *name;
+} PointerBinding;
+
+static gboolean translate(char *str, guint *state, guint *button)
+{
+    char **parsed;
+    char *l;
+    int i;
+    gboolean ret = FALSE;
+
+    parsed = g_strsplit(str, "-", -1);
+    
+    /* first, find the button (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 = kbind_translate_modifier(parsed[i]);
+       if (!m) goto translation_fail;
+       *state |= m;
+    }
+
+    /* figure out the button */
+    *button = atoi(l);
+    if (!*button) {
+       g_warning("Invalid button '%s' in pointer binding.", l);
+       goto translation_fail;
+    }
+
+    ret = TRUE;
+
+translation_fail:
+    g_strfreev(parsed);
+    return ret;
+}
+
+void grab_button(Client *client, guint state, guint button, GQuark context,
+                gboolean grab)
+{
+    Window win;
+    int mode = GrabModeAsync;
+    unsigned int mask;
+
+    if (context == g_quark_try_string("frame")) {
+       win = client->frame->window;
+       mask = ButtonPressMask | ButtonMotionMask | ButtonReleaseMask;
+    } else if (context == g_quark_try_string("client")) {
+       win = client->frame->plate;
+       mode = GrabModeSync; /* this is handled in mbind_fire */
+       mask = ButtonPressMask; /* can't catch more than this with Sync mode
+                                  the release event is manufactured in
+                                  mbind_fire */
+    } else return;
+
+    if (grab)
+       XGrabButton(ob_display, button, state, win, FALSE, mask, mode,
+                   GrabModeAsync, None, None);
+    else
+       XUngrabButton(ob_display, button, state, win);
+}
+
+static void mbind_foreach_grab(GQuark key, gpointer data, gpointer user_data)
+{
+    struct mbind_foreach_grab_temp *d = user_data;
+    PointerBinding *b = ((GSList *)data)->data;
+    if (b != NULL)
+       grab_button(d->client, b->state, b->button, key, d->grab);
+}
+  
+void mbind_grab_all(Client *client, gboolean grab)
+{
+    struct mbind_foreach_grab_temp bt;
+    bt.client = client;
+    bt.grab = grab;
+    g_datalist_foreach(&bound_contexts, mbind_foreach_grab, &bt);
+}
+
+void grab_all_clients(gboolean grab)
+{
+    GSList *it;
+
+    for (it = client_list; it != NULL; it = it->next)
+       mbind_grab_all(it->data, grab);
+}
+
+void mbind_startup()
+{
+    grabbed = FALSE;
+    g_datalist_init(&bound_contexts);
+}
+
+void mbind_shutdown()
+{
+    if (grabbed)
+       mbind_grab_pointer(FALSE);
+    mbind_clearall();
+    g_datalist_clear(&bound_contexts);
+}
+
+gboolean mbind_add(char *name, GQuark context)
+{
+    guint state, button;
+    PointerBinding *b;
+    GSList *it;
+
+    if (!translate(name, &state, &button))
+       return FALSE;
+
+    for (it = g_datalist_id_get_data(&bound_contexts, context);
+        it != NULL; it = it->next){
+       b = it->data;
+       if (b->state == state && b->button == button)
+           return TRUE; /* already bound */
+    }
+
+    grab_all_clients(FALSE);
+
+    /* add the binding */
+    b = g_new(PointerBinding, 1);
+    b->state = state;
+    b->button = button;
+    b->name = g_strdup(name);
+    g_datalist_id_set_data(&bound_contexts, context, 
+        g_slist_append(g_datalist_id_get_data(&bound_contexts, context), b));
+    grab_all_clients(TRUE);
+
+    return TRUE;
+}
+
+static void mbind_foreach_clear(GQuark key, gpointer data, gpointer user_data)
+{
+    GSList *it;
+    user_data = user_data;
+    for (it = data; it != NULL; it = it->next) {
+        PointerBinding *b = it->data;
+        g_free(b->name);
+        g_free(b);
+    }
+    g_slist_free(data);
+}
+void mbind_clearall()
+{
+    grab_all_clients(FALSE);
+    g_datalist_foreach(&bound_contexts, mbind_foreach_clear, NULL);
+}
+
+void mbind_fire(guint state, guint button, GQuark context, EventType type,
+               Client *client, int xroot, int yroot)
+{
+    GSList *it;
+
+    if (grabbed) {
+           EventData *data;
+           data = eventdata_new_pointer(type, context, client, state, button,
+                                        NULL, xroot, yroot);
+           g_assert(data != NULL);
+           hooks_fire_pointer(data);
+           eventdata_free(data);
+           return;
+    }
+
+    for (it = g_datalist_id_get_data(&bound_contexts, context);
+        it != NULL; it = it->next){
+       PointerBinding *b = it->data;
+       if (b->state == state && b->button == button) {
+           EventData *data;
+           data = eventdata_new_pointer(type, context, client, state, button,
+                                        b->name, xroot, yroot);
+           g_assert(data != NULL);
+           hooks_fire(data);
+           eventdata_free(data);
+           break;
+       }
+    }
+}
+
+gboolean mbind_grab_pointer(gboolean grab)
+{
+    gboolean ret = TRUE;
+    if (grab)
+       ret = XGrabPointer(ob_display, ob_root, FALSE, (ButtonPressMask |
+                                                       ButtonReleaseMask |
+                                                       ButtonMotionMask |
+                                                       PointerMotionMask),
+                          GrabModeAsync, GrabModeAsync, None, None,
+                          CurrentTime) == GrabSuccess;
+    else
+       XUngrabPointer(ob_display, CurrentTime);
+    return ret;
+}
This page took 0.032612 seconds and 4 git commands to generate.