diff options
author | Ryan Lortie <desrt@desrt.ca> | 2013-01-14 15:11:10 -0500 |
---|---|---|
committer | Ryan Lortie <desrt@desrt.ca> | 2013-01-15 14:08:02 -0500 |
commit | b68856a7c63289ae00394dafd354aa716477b8bc (patch) | |
tree | d1ea938a7cccd6550eb323c52fa643a54991bb67 | |
parent | 83e5d169d6f0fd3d0427bc3599df8e777b275d9f (diff) | |
download | glib-wip/win32-source-api.tar.gz |
win32: add HANDLE equivalents of new fd APIswip/win32-source-api
Add support for adding HANDLEs to a GSource and add API for creating a
new GSource from a single HANDLE.
-rw-r--r-- | glib/gmain.c | 133 | ||||
-rw-r--r-- | glib/gmain.h | 16 | ||||
-rw-r--r-- | glib/gwin32.c | 122 | ||||
-rw-r--r-- | glib/gwin32.h | 30 |
4 files changed, 294 insertions, 7 deletions
diff --git a/glib/gmain.c b/glib/gmain.c index 5807efde8..a1b5cc568 100644 --- a/glib/gmain.c +++ b/glib/gmain.c @@ -318,10 +318,6 @@ struct _GSourcePrivate GSource *parent_source; gint64 ready_time; - - /* This is currently only used on UNIX, but we always declare it (and - * let it remain empty on Windows) to avoid #ifdef all over the place. - */ GSList *fds; }; @@ -2411,7 +2407,134 @@ g_source_query_unix_fd (GSource *source, return poll_fd->revents; } -#endif /* G_OS_UNIX */ +#else /* G_OS_UNIX */ +/** + * g_source_add_win32_handle: + * @source: a #GSource + * @handle: the HANDLE to monitor + * @events: an event mask + * + * Monitors @handle for the signalled state. + * + * The tag returned by this function can be used to remove the handle + * using g_source_remove_win32_handle(). It is not necessary to remove + * the handle before destroying the source; it will be cleaned up + * automatically. + * + * This function is only available on Windows. + * + * Returns: an opaque tag + * + * Since: 2.36 + **/ +gpointer +g_source_add_handle (GSource *source, + HANDLE handle) +{ + GMainContext *context; + GPollFD *poll_fd; + + g_return_val_if_fail (source != NULL, NULL); + g_return_val_if_fail (!SOURCE_DESTROYED (source), NULL); + + poll_fd = g_new (GPollFD, 1); + poll_fd->fd = (gssize) handle; + poll_fd->events = G_IO_IN; + poll_fd->revents = 0; + + context = source->context; + + if (context) + LOCK_CONTEXT (context); + + source->priv->fds = g_slist_prepend (source->priv->fds, poll_fd); + + if (context) + { + if (!SOURCE_BLOCKED (source)) + g_main_context_add_poll_unlocked (context, source->priority, poll_fd); + UNLOCK_CONTEXT (context); + } + + return poll_fd; +} + +/** + * g_source_remove_win32_handle: + * @source: a #GSource + * @tag: the tag from g_source_add_win32_handle() + * + * Reverses the effect of a previous call to g_source_add_win32_handle(). + * + * You only need to call this if you want to remove a handle from being + * watched while keeping the same source around. In the normal case you + * will just want to destroy the source. + * + * This function is only available on Windows. + * + * Since: 2.36 + **/ +void +g_source_remove_win32_handle (GSource *source, + gpointer tag) +{ + GMainContext *context; + GPollFD *poll_fd; + + g_return_if_fail (source != NULL); + g_return_if_fail (g_slist_find (source->priv->fds, tag)); + + context = source->context; + poll_fd = tag; + + if (context) + LOCK_CONTEXT (context); + + source->priv->fds = g_slist_remove (source->priv->fds, poll_fd); + + if (context) + { + if (!SOURCE_BLOCKED (source)) + g_main_context_remove_poll_unlocked (context, poll_fd); + + UNLOCK_CONTEXT (context); + } + + g_free (poll_fd); +} + +/** + * g_source_query_win32_handle: + * @source: a #GSource + * @tag: the tag from g_source_add_win32_handle() + * + * Queries the events reported for the HANDLE corresponding to @tag on + * @source during the last poll. + * + * The return value of this function is only defined when the function + * is called from the check or dispatch functions for @source. + * + * This function is only available on Windows. + * + * Returns: %TRUE if the handle is signalled + * + * Since: 2.36 + **/ +gboolean +g_source_query_win32_handle (GSource *source, + gpointer tag) +{ + GPollFD *poll_fd; + + g_return_val_if_fail (source != NULL, 0); + g_return_val_if_fail (g_slist_find (source->priv->fds, tag), 0); + + poll_fd = tag; + + return (poll_fd->revents & G_IO_IN) != 0; +} + +#endif /* !G_OS_UNIX */ /** * g_get_current_time: diff --git a/glib/gmain.h b/glib/gmain.h index 47b4ecf1f..fe03ecaab 100644 --- a/glib/gmain.h +++ b/glib/gmain.h @@ -28,6 +28,10 @@ #include <glib/gslist.h> #include <glib/gthread.h> +#ifndef G_OS_UNIX +#include <windows.h> +#endif + G_BEGIN_DECLS typedef enum /*< flags >*/ @@ -485,7 +489,17 @@ void g_source_remove_unix_fd (GSource *source, GLIB_AVAILABLE_IN_2_36 GIOCondition g_source_query_unix_fd (GSource *source, gpointer tag); -#endif +#else /* G_OS_UNIX */ +GLIB_AVAILABLE_IN_2_36 +gpointer g_source_add_win32_handle (GSource *source, + HANDLE handle); +GLIB_AVAILABLE_IN_2_36 +void g_source_remove_win32_handle (GSource *source, + gpointer tag); +GLIB_AVAILABLE_IN_2_36 +gboolean g_source_query_win32_handle (GSource *source, + gpointer tag); +#endif /* !G_OS_UNIX */ /* Used to implement g_source_connect_closure and internally*/ GLIB_AVAILABLE_IN_ALL diff --git a/glib/gwin32.c b/glib/gwin32.c index 97eccd76e..e393c36ea 100644 --- a/glib/gwin32.c +++ b/glib/gwin32.c @@ -575,3 +575,125 @@ g_win32_locale_filename_from_utf8 (const gchar *utf8filename) } return retval; } + +typedef struct +{ + GSource source; + + HANGLE handle; +} GWin32HandleSource; + +static gboolean +g_win32_handle_source_dispatch (GSource *source, + GSourceFunc callback, + gpointer user_data) +{ + GWin32HandleSource *handle_source = (GWin32HandleSource *) source; + GWin32HandleSourceFunc func = (GWin32HandleSourceFunc) callback; + + if (!callback) + { + g_warning ("GWin32HandleSource dispatched without callback\n" + "You must call g_source_set_callback()."); + return FALSE; + } + + return (* func) (handle_source->handle, user_data); +} + + +/** + * g_win32_handle_source_new: + * @handle: a HANDLE + * + * Creates a #GSource to watch for @handle being signalled. + * + * Returns: the newly created #GSource + * + * Since: 2.36 + **/ +GSource * +g_win32_handle_source_new (HANDLE handle) +{ + static GSourceFuncs source_funcs = { + NULL, NULL, g_win32_handle_source_dispatch, NULL + }; + GWin32HandleSource *handle_source; + GSource *source; + + source = g_source_new (&source_funcs, sizeof (GWin32HandleSource)); + handle_source = (GWin32HandleSource *) source; + + handle_source->handle = handle; + + return source; +} + +/** + * g_win32_handle_add_full: + * @priority: the priority of the source + * @handle: a HANDLE + * @function: a #GWin32HandleSourceFunc + * @user_data: data to pass to @function + * @notify: function to call when the idle is removed, or %NULL + * + * Sets a function to be called when @handle becomes signalled. + * + * This is the same as g_win32_handle_add(), except that it allows you to + * specify a non-default priority and a provide a #GDestroyNotify for + * @user_data. + * + * Returns: the ID (greater than 0) of the event source + * + * Since: 2.36 + **/ +guint +g_win32_handle_add_full (gint priority, + HANDLE handle, + GWin32HandleSourceFunc function, + gpointer user_data, + GDestroyNotify notify) +{ + GSource *source; + guint id; + + g_return_val_if_fail (function != NULL, 0); + + source = g_win32_handle_source_new (handle); + + if (priority != G_PRIORITY_DEFAULT) + g_source_set_priority (source, priority); + + g_source_set_callback (source, (GSourceFunc) function, user_data, notify); + id = g_source_attach (source, NULL); + g_source_unref (source); + + return id; +} + +/** + * g_win32_handle_add: + * @handle: a HANDLE + * @function: a #GPollFDFunc + * @user_data: data to pass to @function + * + * Sets a function to be called when @handle becomes signalled. + * + * The function is expected to clear whatever event caused the handle to + * be signalled and return %TRUE in order to be notified when it happens + * again. If @function returns %FALSE then the watch will be cancelled. + * + * The return value of this function can be passed to g_source_remove() + * to cancel the watch at any time that it exists. + * + * Returns: the ID (greater than 0) of the event source + * + * Since: 2.36 + **/ +guint +g_win32_handle_add (HANDLE handle, + GWin32HandleSourceFunc function, + gpointer user_data) +{ + return g_win32_handle_add_full (G_PRIORITY_DEFAULT, handle, function, user_data, NULL); +} diff --git a/glib/gwin32.h b/glib/gwin32.h index ae87a45d4..e7f693b74 100644 --- a/glib/gwin32.h +++ b/glib/gwin32.h @@ -31,7 +31,7 @@ #error "Only <glib.h> can be included directly." #endif -#include <glib/gtypes.h> +#include <glib/gmain.h> #ifdef G_PLATFORM_WIN32 @@ -128,6 +128,34 @@ gchar *g_win32_get_package_installation_subdirectory_utf8 (const gchar *package, const gchar *dll_name, const gchar *subdir); +/** + * GWin32HandleSourceFunc: + * @handle: the HANDLE that triggered the event + * @user_data: user data passed to g_win32_handle_add() + * + * The type of functions to be called when a Windows HANDLE watch source + * triggers. + * + * Returns: %FALSE if the source should be removed + **/ +typedef gboolean (*GWin32HandleSourceFunc) (HANDLE handle, + gpointer user_data); + +GLIB_AVAILABLE_IN_2_36 +GSource *g_win32_handle_source_new (HANDLE handle); + +GLIB_AVAILABLE_IN_2_36 +guint g_win32_handle_add_full (gint priority, + HANDLE handle, + GWin32HandleSourceFunc function, + gpointer user_data, + GDestroyNotify notify); + +GLIB_AVAILABLE_IN_2_36 +guint g_win32_handle_add (HANDLE handle, + GWin32HandleSourceFunc function, + gpointer user_data); + #endif /* G_OS_WIN32 */ #endif /* __G_WIN32_H__ */ |