openbox/obt/xevent.c
2010-02-16 16:32:38 -05:00

140 lines
3.7 KiB
C

/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
obt/xevent.c for the Openbox window manager
Copyright (c) 2007 Dana Jansens
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.
See the COPYING file for a copy of the GNU General Public License.
*/
#include "obt/xevent.h"
#include "obt/mainloop.h"
#include "obt/util.h"
typedef struct _ObtXEventBinding ObtXEventBinding;
struct _ObtXEventHandler
{
gint ref;
ObtMainLoop *loop;
/* An array of hash tables where the key is the window, and the value is
the ObtXEventBinding */
GHashTable **bindings;
gint num_event_types; /* the length of the bindings array */
};
struct _ObtXEventBinding
{
Window win;
ObtXEventCallback func;
gpointer data;
};
static void xevent_handler(const XEvent *e, gpointer data);
static guint window_hash(Window *w) { return *w; }
static gboolean window_comp(Window *w1, Window *w2) { return *w1 == *w2; }
static void binding_free(gpointer b);
ObtXEventHandler* xevent_new(void)
{
ObtXEventHandler *h;
h = g_slice_new0(ObtXEventHandler);
h->ref = 1;
return h;
}
void xevent_ref(ObtXEventHandler *h)
{
++h->ref;
}
void xevent_unref(ObtXEventHandler *h)
{
if (h && --h->ref == 0) {
gint i;
if (h->loop)
obt_main_loop_x_remove(h->loop, xevent_handler);
for (i = 0; i < h->num_event_types; ++i)
g_hash_table_destroy(h->bindings[i]);
g_free(h->bindings);
g_slice_free(ObtXEventHandler, h);
}
}
void xevent_register(ObtXEventHandler *h, ObtMainLoop *loop)
{
h->loop = loop;
obt_main_loop_x_add(loop, xevent_handler, h, NULL);
}
void xevent_set_handler(ObtXEventHandler *h, gint type, Window win,
ObtXEventCallback func, gpointer data)
{
ObtXEventBinding *b;
g_assert(func);
/* make sure we have a spot for the event */
if (type + 1 < h->num_event_types) {
gint i;
h->bindings = g_renew(GHashTable*, h->bindings, type + 1);
for (i = h->num_event_types; i < type + 1; ++i)
h->bindings[i] = g_hash_table_new_full((GHashFunc)window_hash,
(GEqualFunc)window_comp,
NULL, binding_free);
h->num_event_types = type + 1;
}
b = g_slice_new(ObtXEventBinding);
b->win = win;
b->func = func;
b->data = data;
g_hash_table_replace(h->bindings[type], &b->win, b);
}
static void binding_free(gpointer b)
{
g_slice_free(ObtXEventBinding, b);
}
void xevent_remove_handler(ObtXEventHandler *h, gint type, Window win)
{
g_assert(type < h->num_event_types);
g_assert(win);
g_hash_table_remove(h->bindings[type], &win);
}
static void xevent_handler(const XEvent *e, gpointer data)
{
ObtXEventHandler *h;
ObtXEventBinding *b;
h = data;
if (e->type < h->num_event_types) {
const gint all = OBT_XEVENT_ALL_WINDOWS;
/* run the all_windows handler first */
b = g_hash_table_lookup(h->bindings[e->xany.type], &all);
if (b) b->func(e, b->data);
/* then run the per-window handler */
b = g_hash_table_lookup(h->bindings[e->xany.type], &e->xany.window);
if (b) b->func(e, b->data);
}
else
g_message("Unhandled X Event type %d", e->xany.type);
}