diff options
Diffstat (limited to 'c/mbind.c')
| -rw-r--r-- | c/mbind.c | 220 |
1 files changed, 220 insertions, 0 deletions
diff --git a/c/mbind.c b/c/mbind.c new file mode 100644 index 00000000..f363be68 --- /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; +} |
