improved .desktop parsing.
[dana/openbox.git] / obt / xevent.c
1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
2
3    obt/xevent.c for the Openbox window manager
4    Copyright (c) 2007        Dana Jansens
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    See the COPYING file for a copy of the GNU General Public License.
17 */
18
19 #include "obt/xevent.h"
20 #include "obt/mainloop.h"
21 #include "obt/util.h"
22
23 typedef struct _ObtXEventBinding ObtXEventBinding;
24
25 struct _ObtXEventHandler
26 {
27     gint ref;
28     ObtMainLoop *loop;
29
30     /* An array of hash tables where the key is the window, and the value is
31        the ObtXEventBinding */
32     GHashTable **bindings;
33     gint num_event_types; /* the length of the bindings array */
34 };
35
36 struct _ObtXEventBinding
37 {
38     Window win;
39     ObtXEventCallback func;
40     gpointer data;
41 };
42
43 static void xevent_handler(const XEvent *e, gpointer data);
44 static guint window_hash(Window *w) { return *w; }
45 static gboolean window_comp(Window *w1, Window *w2) { return *w1 == *w2; }
46 static void binding_free(gpointer b);
47
48 ObtXEventHandler* xevent_new(void)
49 {
50     ObtXEventHandler *h;
51
52     h = g_slice_new0(ObtXEventHandler);
53     h->ref = 1;
54
55     return h;
56 }
57
58 void xevent_ref(ObtXEventHandler *h)
59 {
60     ++h->ref;
61 }
62
63 void xevent_unref(ObtXEventHandler *h)
64 {
65     if (h && --h->ref == 0) {
66         gint i;
67
68         if (h->loop)
69             obt_main_loop_x_remove(h->loop, xevent_handler);
70         for (i = 0; i < h->num_event_types; ++i)
71             g_hash_table_destroy(h->bindings[i]);
72         g_free(h->bindings);
73
74         g_slice_free(ObtXEventHandler, h);
75     }
76 }
77
78 void xevent_register(ObtXEventHandler *h, ObtMainLoop *loop)
79 {
80     h->loop = loop;
81     obt_main_loop_x_add(loop, xevent_handler, h, NULL);
82 }
83
84 void xevent_set_handler(ObtXEventHandler *h, gint type, Window win,
85                         ObtXEventCallback func, gpointer data)
86 {
87     ObtXEventBinding *b;
88
89     g_assert(func);
90
91     /* make sure we have a spot for the event */
92     if (type + 1 < h->num_event_types) {
93         gint i;
94         h->bindings = g_renew(GHashTable*, h->bindings, type + 1);
95         for (i = h->num_event_types; i < type + 1; ++i)
96             h->bindings[i] = g_hash_table_new_full((GHashFunc)window_hash,
97                                                    (GEqualFunc)window_comp,
98                                                    NULL, binding_free);
99         h->num_event_types = type + 1;
100     }
101
102     b = g_slice_new(ObtXEventBinding);
103     b->win = win;
104     b->func = func;
105     b->data = data;
106     g_hash_table_replace(h->bindings[type], &b->win, b);
107 }
108
109 static void binding_free(gpointer b)
110 {
111     g_slice_free(ObtXEventBinding, b);
112 }
113
114 void xevent_remove_handler(ObtXEventHandler *h, gint type, Window win)
115 {
116     g_assert(type < h->num_event_types);
117     g_assert(win);
118
119     g_hash_table_remove(h->bindings[type], &win);
120 }
121
122 static void xevent_handler(const XEvent *e, gpointer data)
123 {
124     ObtXEventHandler *h;
125     ObtXEventBinding *b;
126
127     h = data;
128
129     if (e->type < h->num_event_types) {
130         const gint all = OBT_XEVENT_ALL_WINDOWS;
131         /* run the all_windows handler first */
132         b = g_hash_table_lookup(h->bindings[e->xany.type], &all);
133         if (b) b->func(e, b->data);
134         /* then run the per-window handler */
135         b = g_hash_table_lookup(h->bindings[e->xany.type], &e->xany.window);
136         if (b) b->func(e, b->data);
137     }
138     else
139         g_message("Unhandled X Event type %d", e->xany.type);
140 }