--- /dev/null
+#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;
+}