tProvide glib event loop equivalents for Windows - vaccinewars - be a doctor and try to vaccinate the world
 (HTM) git clone git://src.adamsgaard.dk/vaccinewars
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 54b9e74c81e0dc4bb786f7de94d96bda1569e101
 (DIR) parent 9041057b524e7631a4095a3ad36f12bd0c337e81
 (HTM) Author: Ben Webb <ben@salilab.org>
       Date:   Wed, 11 Nov 2020 15:25:04 -0800
       
       Provide glib event loop equivalents for Windows
       
       We use the glib event loop to handle metaserver socket events
       on Unix (g_timeout_add, g_io_add_watch, g_source_remove).
       These functions don't do anything on Windows because we use
       tthe Windows event loop instead. Provide dp_* equivalents
       which, on Windows, tie into the Windows event loop instead.
       This should make metaserver connections work again on Windows
       from the GUI client and server. Closes #48.
       
       Diffstat:
         M src/gtkport/gtkport.c               |     116 ++++++++++++++++++++++++++++++
         M src/gtkport/gtkport.h               |       6 ++++++
         M src/gui_client/newgamedia.c         |       2 +-
         M src/network.c                       |      10 +++++-----
         M src/network.h                       |       9 +++++++++
         M src/serverside.c                    |       2 +-
       
       6 files changed, 138 insertions(+), 7 deletions(-)
       ---
 (DIR) diff --git a/src/gtkport/gtkport.c b/src/gtkport/gtkport.c
       t@@ -254,6 +254,21 @@ struct _GtkTimeout {
          guint id;
        };
        
       +struct _OurSource {
       +  guint id;     /* Unique identifier */
       +
       +  /* Used for timeouts (dp_g_timeout_add()) */
       +  GSourceFunc timeout_function;
       +
       +  /* Used for IO channels (dp_g_io_watch()) */
       +  GIOChannel *io_channel;
       +  GIOFunc io_function;
       +  int socket;
       +
       +  gpointer data;    /* Data passed to callback function */
       +};
       +typedef struct _OurSource OurSource;
       +
        typedef struct _GtkItemFactoryChild GtkItemFactoryChild;
        
        struct _GtkItemFactoryChild {
       t@@ -638,6 +653,7 @@ HFONT defFont;
        static HFONT urlFont;
        static GSList *WindowList = NULL;
        static GSList *GdkInputs = NULL;
       +static GSList *OurSources = NULL;
        static GSList *GtkTimeouts = NULL;
        static HWND TopLevel = NULL;
        
       t@@ -663,6 +679,7 @@ static void DispatchSocketEvent(SOCKET sock, long event)
        {
          GSList *list;
          GdkInput *input;
       +  OurSource *s;
        
          for (list = GdkInputs; list; list = g_slist_next(list)) {
            input = (GdkInput *)(list->data);
       t@@ -675,11 +692,23 @@ static void DispatchSocketEvent(SOCKET sock, long event)
              break;
            }
          }
       +  for (list = OurSources; list; list = g_slist_next(list)) {
       +    s = (OurSource *)(list->data);
       +    if (s->socket == sock) {
       +      (*s->io_function) (s->io_channel,
       +                          (event & (FD_READ | FD_CLOSE | FD_ACCEPT) ?
       +                           G_IO_IN : 0) |
       +                          (event & (FD_WRITE | FD_CONNECT) ?
       +                           G_IO_OUT : 0), s->data);
       +      break;
       +    }
       +  }
        }
        
        static void DispatchTimeoutEvent(UINT id)
        {
          GSList *list;
       +  OurSource *s;
          GtkTimeout *timeout;
        
          for (list = GtkTimeouts; list; list = g_slist_next(list)) {
       t@@ -693,6 +722,17 @@ static void DispatchTimeoutEvent(UINT id)
              break;
            }
          }
       +  for (list = OurSources; list; list = g_slist_next(list)) {
       +    s = (OurSource *)list->data;
       +    if (s->id == id) {
       +      if (s->timeout_function) {
       +        if (!(*s->timeout_function) (s->data)) {
       +          dp_g_source_remove(s->id);
       +        }
       +      }
       +      break;
       +    }
       +  }
        }
        
        static HWND gtk_get_window_hwnd(GtkWidget *widget)
       t@@ -5315,6 +5355,82 @@ gint GtkMessageBox(GtkWidget *parent, const gchar *Text,
          return retval;
        }
        
       +
       +/* Add a new source and return a unique ID */
       +static guint add_our_source(OurSource *source)
       +{
       +  GSList *list;
       +  guint id = 1;
       +
       +  /* Get an unused ID */
       +  list = OurSources;
       +  while (list) {
       +    OurSource *s = (OurSource *)list->data;
       +    if (s->id == id) {
       +      id++;
       +      list = OurSources;  /* Back to the start */
       +    } else {
       +      list = g_slist_next(list);
       +    }
       +  }
       +
       +  source->id = id;
       +  OurSources = g_slist_append(OurSources, source);
       +  return source->id;
       +}
       +
       +/* Like g_timeout_add(), but uses the Windows event loop */
       +guint dp_g_timeout_add(guint interval, GSourceFunc function, gpointer data)
       +{
       +  guint id;
       +  OurSource *source = g_new0(OurSource, 1);
       +  source->timeout_function = function;
       +  source->data = data;
       +  id = add_our_source(source);
       +  if (SetTimer(TopLevel, id, interval, NULL) == 0) {
       +    g_warning("Failed to create timer!");
       +  }
       +  return id;
       +}
       +
       +/* Like g_io_add_watch(), but uses the Windows event loop */
       +guint dp_g_io_add_watch(GIOChannel *channel, GIOCondition condition,
       +                        GIOFunc func, gpointer user_data)
       +{
       +  OurSource *source = g_new0(OurSource, 1);
       +  source->io_channel = channel;
       +  source->io_function = func;
       +  source->socket = g_io_channel_unix_get_fd(channel);
       +  source->data = user_data;
       +  WSAAsyncSelect(source->socket, TopLevel, MYWM_SOCKETDATA,
       +                 (condition & G_IO_IN ? FD_READ | FD_CLOSE | FD_ACCEPT : 0)
       +                 | (condition & G_IO_OUT ? FD_WRITE | FD_CONNECT : 0));
       +  return add_our_source(source);
       +}
       +
       +/* Like g_source_remove(), but uses the Windows event loop */
       +gboolean dp_g_source_remove(guint tag)
       +{
       +  GSList *list;
       +  OurSource *s;
       +  for (list = OurSources; list; list = g_slist_next(list)) {
       +    s = (OurSource *)list->data;
       +    if (s->id == tag) {
       +      if (s->timeout_function) {
       +        if (KillTimer(TopLevel, s->id) == 0) {
       +          g_warning("Failed to kill timer!");
       +        }
       +      } else {
       +        WSAAsyncSelect(s->socket, TopLevel, 0, 0);
       +      }
       +      OurSources = g_slist_remove(OurSources, s);
       +      g_free(s);
       +      break;
       +    }
       +  }
       +  return TRUE;
       +}
       +
        guint gtk_timeout_add(guint32 interval, GtkFunction function,
                              gpointer data)
        {
 (DIR) diff --git a/src/gtkport/gtkport.h b/src/gtkport/gtkport.h
       t@@ -620,6 +620,12 @@ GtkWidget *gtk_spin_button_new(GtkAdjustment *adjustment,
        void gdk_input_remove(gint tag);
        gint gdk_input_add(gint source, GdkInputCondition condition,
                           GdkInputFunction function, gpointer data);
       +
       +guint dp_g_io_add_watch(GIOChannel *channel, GIOCondition condition,
       +                        GIOFunc func, gpointer user_data);
       +guint dp_g_timeout_add(guint interval, GSourceFunc function, gpointer data);
       +gboolean dp_g_source_remove(guint tag);
       +
        GtkWidget *gtk_hseparator_new();
        GtkWidget *gtk_vseparator_new();
        void gtk_object_set_data(GtkObject *object, const gchar *key,
 (DIR) diff --git a/src/gui_client/newgamedia.c b/src/gui_client/newgamedia.c
       t@@ -108,7 +108,7 @@ static gboolean glib_socket(GIOChannel *ch, GIOCondition condition,
            return TRUE;
          } else {
            if (g->timer_event) {
       -      g_source_remove(g->timer_event);
       +      dp_g_source_remove(g->timer_event);
              g->timer_event = 0;
            }
            if (!err)
 (DIR) diff --git a/src/network.c b/src/network.c
       t@@ -1288,13 +1288,13 @@ static int timer_function(CURLM *multi, long timeout_ms, void *userp)
          CurlConnection *g = userp;
        
          if (g->timer_event) {
       -    g_source_remove(g->timer_event);
       +    dp_g_source_remove(g->timer_event);
            g->timer_event = 0;
          }
        
          /* -1 means we should just delete our timer. */
          if (timeout_ms >= 0) {
       -    g->timer_event = g_timeout_add(timeout_ms, g->timer_cb, g);
       +    g->timer_event = dp_g_timeout_add(timeout_ms, g->timer_cb, g);
          }
          return 0;
        }
       t@@ -1306,7 +1306,7 @@ static void remsock(SockData *f)
            return;
          }
          if (f->ev) {
       -    g_source_remove(f->ev);
       +    dp_g_source_remove(f->ev);
          }
          g_free(f);
        }
       t@@ -1320,9 +1320,9 @@ static void setsock(SockData *f, curl_socket_t s, CURL *e, int act,
            ((act & CURL_POLL_OUT) ? G_IO_OUT : 0);
        
          if (f->ev) {
       -    g_source_remove(f->ev);
       +    dp_g_source_remove(f->ev);
          }
       -  f->ev = g_io_add_watch(f->ch, kind, g->socket_cb, g);
       +  f->ev = dp_g_io_add_watch(f->ch, kind, g->socket_cb, g);
        }
        
        /* Initialize a new SockData structure */
 (DIR) diff --git a/src/network.h b/src/network.h
       t@@ -62,6 +62,15 @@
        #define SOCKET_ERROR -1
        #endif
        
       +#ifdef CYGWIN
       +/* Need GUI main loop to handle timers/events */
       +#include "gtkport/gtkport.h"
       +#else
       +#define dp_g_source_remove g_source_remove
       +#define dp_g_io_add_watch g_io_add_watch
       +#define dp_g_timeout_add g_timeout_add
       +#endif
       +
        typedef struct _CurlConnection {
          CURLM *multi;
          CURL *h;
 (DIR) diff --git a/src/serverside.c b/src/serverside.c
       t@@ -1144,7 +1144,7 @@ static gboolean glib_socket(GIOChannel *ch, GIOCondition condition,
            return TRUE;
          } else {
            if (g->timer_event) {
       -      g_source_remove(g->timer_event);
       +      dp_g_source_remove(g->timer_event);
              g->timer_event = 0;
            }
            LogMetaReply(g);