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