[glib/wip/win32-source-api] win32: add HANDLE equivalents of new fd APIs



commit b68856a7c63289ae00394dafd354aa716477b8bc
Author: Ryan Lortie <desrt desrt ca>
Date:   Mon Jan 14 15:11:10 2013 -0500

    win32: add HANDLE equivalents of new fd APIs
    
    Add support for adding HANDLEs to a GSource and add API for creating a
    new GSource from a single HANDLE.

 glib/gmain.c  |  133 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 glib/gmain.h  |   16 ++++++-
 glib/gwin32.c |  122 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 glib/gwin32.h |   30 ++++++++++++-
 4 files changed, 294 insertions(+), 7 deletions(-)
---
diff --git a/glib/gmain.c b/glib/gmain.c
index 5807efd..a1b5cc5 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 47b4ecf..fe03eca 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 97eccd7..e393c36 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 ae87a45..e7f693b 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__ */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]