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);