1
/*********************************************************
2
* Copyright (C) 2009 VMware, Inc. All rights reserved.
4
* This program is free software; you can redistribute it and/or modify it
5
* under the terms of the GNU Lesser General Public License as published
6
* by the Free Software Foundation version 2.1 and no later version.
8
* This program is distributed in the hope that it will be useful, but
9
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10
* or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
11
* License for more details.
13
* You should have received a copy of the GNU Lesser General Public License
14
* along with this program; if not, write to the Free Software Foundation, Inc.,
15
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
17
*********************************************************/
22
* Provides code relating the Glib main loop and Xlib/X11 event sources.
36
* File scope prototypes.
40
static void ConnectionWatch(Display *display, XPointer client_data, int fd,
41
int opening, XPointer *watch_data);
42
static gboolean TeardownHashRemove(gpointer key, gpointer value,
44
static gboolean USourcePrepare(GSource *source, gint *timeout);
45
static gboolean USourceCheck(GSource *source);
46
static gboolean USourceDispatch(GSource *source, GSourceFunc callback,
51
* Library scope functions.
56
******************************************************************************
57
* UnityX11EstablishSource -- */ /**
59
* @brief Creates Glib event source for X11 events. Attaches to the Glib event
62
* @param[in] up Our Unity platform context.
64
******************************************************************************
68
UnityX11EventEstablishSource(UnityPlatform *up) // IN
70
static GSourceFuncs unitySourceFuncs = {0};
71
unitySourceFuncs.prepare = USourcePrepare;
72
unitySourceFuncs.check = USourceCheck;
73
unitySourceFuncs.dispatch = USourceDispatch;
75
UnityGSource *uSource;
80
uSource = (UnityGSource *)g_source_new(&unitySourceFuncs, sizeof *uSource);
82
uSource->fdTable = g_hash_table_new(g_direct_hash, g_direct_equal);
84
up->glibSource = uSource;
86
/* Hook our main X11 connection into our event source. */
87
ConnectionWatch(up->display, (XPointer)up, ConnectionNumber(up->display), TRUE,
90
/* If Xlib opens an internal connection, bind it to the source, too. */
91
XAddConnectionWatch(up->display, &ConnectionWatch, (XPointer)up);
93
/* Attach the source to the event loop. */
94
g_source_set_callback((GSource*)uSource, UnityX11HandleEvents, up, NULL);
95
g_source_attach((GSource*)uSource, NULL);
97
/* Transfer ownership to the event loop. */
98
g_source_unref((GSource*)uSource);
103
******************************************************************************
104
* UnityX11TeardownSource -- */ /**
106
* @brief Detach Unity from our Glib event loop.
108
* @param[in] up Our Unity platform context.
110
******************************************************************************
114
UnityX11EventTeardownSource(UnityPlatform *up) // IN
116
UnityGSource *uSource = up->glibSource;
121
/* Detach Xlib internal connection notification from the Glib event loop. */
122
XRemoveConnectionWatch(up->display, &ConnectionWatch, (XPointer)up);
124
/* Detach all Xlib file descriptors from our Glib event source. */
125
g_hash_table_foreach_remove(uSource->fdTable, TeardownHashRemove, uSource);
126
g_hash_table_unref(uSource->fdTable);
127
uSource->fdTable = NULL;
129
/* Destroy the Glib event source. */
130
g_source_destroy((GSource*)uSource);
131
up->glibSource = NULL;
136
* File scope functions.
141
******************************************************************************
142
* ConnectionWatch -- */ /**
144
* @brief Binds Xlib internal connections to Glib event sources.
146
* When Xlib or its extensions create new X11 connections, they're bound to
147
* a @a Display as <em>"internal connections"</em>. When Xlib processes the
148
* incoming event queue, it pulls requests from @em all of these connections,
149
* not just the main event connection. As such, we should monitor all of
152
* @param[in] display X11 display context.
153
* @param[in] client_data Our UnityPlatform context.
154
* @param[in] fd Relevant file descriptor.
155
* @param[in] opening TRUE when @a fd is opened, FALSE when @a fd is closed.
156
* @param[in] watch_data Unused.
158
* @sa XAddConnectionWatch
160
******************************************************************************
164
ConnectionWatch(Display *display, // IN
165
XPointer client_data, // IN
168
XPointer *watch_data) // UNUSED
171
UnityGSource *uSource;
173
up = (UnityPlatform *)client_data;
175
ASSERT(up); // Make sure we're correctly registered.
176
ASSERT(up->isRunning); // This cb should be stripped before we exit Unity.
177
ASSERT(up->glibSource); // This function is useless w/o an established source.
178
ASSERT(display == up->display);
180
uSource = up->glibSource;
184
* Add new a new file descriptor to the poll array.
186
GPollFD *newFd = g_new0(GPollFD, 1);
188
ASSERT(g_hash_table_lookup(uSource->fdTable, GINT_TO_POINTER(fd)) == NULL);
191
newFd->events = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
193
g_hash_table_insert(uSource->fdTable, GINT_TO_POINTER(fd), newFd);
194
g_source_add_poll((GSource*)uSource, newFd);
197
* Remove a file descriptor from the poll array.
199
GPollFD *oldFd = (GPollFD*)g_hash_table_lookup(uSource->fdTable, GINT_TO_POINTER(fd));
202
g_source_remove_poll((GSource *)uSource, oldFd);
203
g_hash_table_remove(uSource->fdTable, GINT_TO_POINTER(fd));
211
******************************************************************************
212
* TeardownHashRemove -- */ /**
214
* @brief Assists TeardownSource with destroying its GPollFD hash table.
216
* @param[in] key GINT_TO_POINTER-converted file descriptor.
217
* @param[in] value Corresponding GPollFD *.
218
* @param[in] user_data Our UnityGSource.
220
* @see g_hash_table_foreach_remove
222
******************************************************************************
226
TeardownHashRemove(gpointer key, // IN
227
gpointer value, // IN
228
gpointer user_data) // IN
230
GPollFD *oldFd = (GPollFD*)value;
231
UnityGSource *uSource = (UnityGSource*)user_data;
236
g_source_remove_poll((GSource *)uSource, oldFd);
244
******************************************************************************
245
* USourcePrepare -- */ /**
247
* @brief See GSourceFuncs::prepare.
249
* @param[in] source Points to our UnityGSource.
250
* @param[out] timeout May specify a maximum timeout value for poll(2).
252
* @retval TRUE Source is ready.
253
* @retval FALSE Source not yet ready.
255
******************************************************************************
259
USourcePrepare(GSource *source, // IN
260
gint *timeout) // OUT
262
UnityGSource *uSource = (UnityGSource *)source;
265
* "It sets the returned timeout to -1 to indicate that it doesn't mind how
266
* long the poll() call blocks."
267
* - http://library.gnome.org/devel/glib/unstable/glib-The-Main-Event-Loop.html#GSourceFuncs
271
return XQLength(uSource->up->display) > 0;
276
******************************************************************************
277
* USourceCheck -- */ /**
279
* @brief See GSourceFuncs::check.
281
* @param[in] source Points to our UnityGSource.
283
* @retval TRUE Source is ready.
284
* @retval FALSE Source not yet ready.
286
* @todo Should exit Unity upon file descriptor error.
288
******************************************************************************
292
USourceCheck(GSource *source) // IN
294
UnityGSource *uSource = (UnityGSource *)source;
295
gboolean haveData = FALSE;
298
* XXX Could/should test for FD errors here.
300
if (XQLength(uSource->up->display)) {
306
pollFds = g_hash_table_get_values(uSource->fdTable);
308
for (listIter = pollFds; listIter; listIter = listIter->next) {
309
GPollFD *pollFd = (GPollFD*)listIter->data;
311
if (pollFd->revents & G_IO_IN) {
317
g_list_free(pollFds);
325
******************************************************************************
326
* USourceDispatch -- */ /**
328
* @brief See GSourceFuncs::dispatch.
330
* @param[in] source Points to our UnityGSource.
331
* @param[in] callback Points to the user's callback.
332
* @param[in] cbData Points to user's callback data.
334
* @retval TRUE Glib should continue monitoring the source.
335
* @retval FALSE Glib should stop monitoring the source.
337
******************************************************************************
341
USourceDispatch(GSource *source, // IN
342
GSourceFunc callback, // IN
343
gpointer cbData) // IN
346
* Remind callers to attach a callback.
351
return callback(cbData);