changeset 8273:f24172f53650

[gaim-migrate @ 8997] This is Scott Lamb's eventloop abstraction patch. If it breaks things, Scott Lamb will be glad to take the punishment. If it doesn't, it should make integration into other event loops easier. Well, no, not easier, harder actually, but it'll be done more appropriately and less hackily.. er, hacky. Is hackily a word? committer: Tailor Script <tailor@pidgin.im>
author Christian Hammond <chipx86@chipx86.com>
date Tue, 17 Feb 2004 02:17:48 +0000
parents 9af78e73f0b2
children 0d9559f3bd2e
files COPYRIGHT ChangeLog src/Makefile.am src/account.c src/blist.c src/connection.c src/conversation.c src/core.c src/core.h src/eventloop.c src/eventloop.h src/gaim-disclosure.c src/gtkeventloop.c src/gtkeventloop.h src/main.c src/pounce.c src/prefs.c src/protocols/icq/gaim_icq.c src/protocols/irc/msgs.c src/protocols/jabber/jabber.c src/protocols/msn/httpmethod.c src/protocols/msn/msnslp.c src/protocols/oscar/oscar.c src/protocols/trepia/trepia.c src/protocols/zephyr/zephyr.c src/proxy.c src/proxy.h src/server.c src/session.c src/status.c src/win32/win32dep.c
diffstat 31 files changed, 420 insertions(+), 206 deletions(-) [+]
line wrap: on
line diff
--- a/COPYRIGHT	Tue Feb 17 01:33:20 2004 +0000
+++ b/COPYRIGHT	Tue Feb 17 02:17:48 2004 +0000
@@ -59,6 +59,7 @@
 Akuke Kok
 Gary Kramlich
 Tero Kuusela
+Scott Lamb
 Dennis Lambe Jr.
 Ho-seok Lee
 Moses Lei
--- a/ChangeLog	Tue Feb 17 01:33:20 2004 +0000
+++ b/ChangeLog	Tue Feb 17 02:17:48 2004 +0000
@@ -16,6 +16,7 @@
 	  accessibility tools (Marc Mulcahy)
 	* Improved accessibility in conversation windows (Nathan Fredrickson)
 	* Keyboard access to context menus via Shift+F10 (Marc Mulcahy)
+	* Core/UI split event loop code. (Scott Lamb)
 
 	Bug Fixes:
 	* Various buffer overflow fixes (Stefan Esser)
--- a/src/Makefile.am	Tue Feb 17 01:33:20 2004 +0000
+++ b/src/Makefile.am	Tue Feb 17 02:17:48 2004 +0000
@@ -70,6 +70,8 @@
 	core.h \
 	debug.c \
 	debug.h \
+	eventloop.c \
+	eventloop.h \
 	ft.c \
 	ft.h \
 	imgstore.c \
@@ -145,6 +147,8 @@
 	gtkconv.h \
 	gtkdebug.c \
 	gtkdebug.h \
+	gtkeventloop.c \
+	gtkeventloop.h \
 	gtkft.c \
 	gtkft.h \
 	gtkimhtml.c \
--- a/src/account.c	Tue Feb 17 01:33:20 2004 +0000
+++ b/src/account.c	Tue Feb 17 02:17:48 2004 +0000
@@ -120,7 +120,7 @@
 schedule_accounts_save()
 {
 	if (!accounts_save_timer)
-		accounts_save_timer = g_timeout_add(5000, accounts_save_cb, NULL);
+		accounts_save_timer = gaim_timeout_add(5000, accounts_save_cb, NULL);
 }
 
 GaimAccount *
--- a/src/blist.c	Tue Feb 17 01:33:20 2004 +0000
+++ b/src/blist.c	Tue Feb 17 02:17:48 2004 +0000
@@ -297,7 +297,7 @@
 	if(do_something) {
 		if(buddy->timer > 0)
 			g_source_remove(buddy->timer);
-		buddy->timer = g_timeout_add(10000, (GSourceFunc)presence_update_timeout_cb, buddy);
+		buddy->timer = gaim_timeout_add(10000, (GSourceFunc)presence_update_timeout_cb, buddy);
 
 		gaim_contact_compute_priority_buddy(gaim_buddy_get_contact(buddy));
 		if (ops)
--- a/src/connection.c	Tue Feb 17 01:33:20 2004 +0000
+++ b/src/connection.c	Tue Feb 17 02:17:48 2004 +0000
@@ -482,7 +482,7 @@
 			ops->disconnected(gc);
 	}
 
-	gc->disconnect_timeout = g_timeout_add(0, gaim_connection_disconnect_cb,
+	gc->disconnect_timeout = gaim_timeout_add(0, gaim_connection_disconnect_cb,
 			gaim_connection_get_account(gc));
 }
 
--- a/src/conversation.c	Tue Feb 17 01:33:20 2004 +0000
+++ b/src/conversation.c	Tue Feb 17 02:17:48 2004 +0000
@@ -1581,8 +1581,7 @@
 	conv = gaim_conv_im_get_conversation(im);
 	name = gaim_conversation_get_name(conv);
 
-	im->typing_timeout = g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE,
-		timeout * 1000, reset_typing, conv, NULL);
+	im->typing_timeout = gaim_timeout_add(timeout * 1000, reset_typing, conv);
 }
 
 void
@@ -1626,8 +1625,8 @@
 {
 	g_return_if_fail(im != NULL);
 
-	im->type_again_timeout = g_timeout_add(SEND_TYPED_TIMEOUT, send_typed,
-										   gaim_conv_im_get_conversation(im));
+	im->type_again_timeout = gaim_timeout_add(SEND_TYPED_TIMEOUT, send_typed,
+											  gaim_conv_im_get_conversation(im));
 }
 
 void
--- a/src/core.c	Tue Feb 17 01:33:20 2004 +0000
+++ b/src/core.c	Tue Feb 17 02:17:48 2004 +0000
@@ -159,25 +159,6 @@
 	return VERSION;
 }
 
-gboolean
-gaim_core_mainloop_events_pending(void)
-{
-	return g_main_context_pending(g_main_context_default());
-}
-
-void
-gaim_core_mainloop_iteration(void)
-{
-	g_main_context_iteration(g_main_context_default(), FALSE);
-}
-
-void
-gaim_core_mainloop_finish_events(void)
-{
-	while (gaim_core_mainloop_events_pending())
-		gaim_core_mainloop_iteration();
-}
-
 const char *
 gaim_core_get_ui(void)
 {
--- a/src/core.h	Tue Feb 17 01:33:20 2004 +0000
+++ b/src/core.h	Tue Feb 17 02:17:48 2004 +0000
@@ -60,10 +60,10 @@
 
 /**
  * Calls gaim_core_quit().  This can be used as the function 
- * passed to g_timeout_add() when you want to shutdown Gaim 
+ * passed to gaim_timeout_add() when you want to shutdown Gaim 
  * in a specified amount of time.  When shutting down Gaim 
  * from a plugin, you must use this with a timeout value of 0: 
- *   g_timeout_add(0, gaim_core_quitcb, NULL);
+ *   gaim_timeout_add(0, gaim_core_quitcb, NULL);
  * This is ensures that code from your plugin is not being 
  * executed when gaim_core_quit() is called.  Otherwise you 
  * would get a core dump after gaim_core_quit() executes and 
@@ -80,28 +80,6 @@
 const char *gaim_core_get_version(void);
 
 /**
- * Returns whether or not there are any mainloop events pending.
- *
- * @return TRUE if there are mainloop events pending. FALSE otherwise.
- */
-gboolean gaim_core_mainloop_events_pending(void);
-
-/**
- * Iterates once through the gaim mainloop.
- *
- * This is in actuality a wrapper around glib's mainloop iteration
- * function, but provides a nice, healthy level of abstraction.
- *
- * All UIs not using glib must call this in a timer.
- */
-void gaim_core_mainloop_iteration(void);
-
-/**
- * Iterates through all remaining events in the mainloop.
- */
-void gaim_core_mainloop_finish_events(void);
-
-/**
  * Returns the ID of the UI that is using the core.
  *
  * @return The ID of the UI that is currently using the core.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eventloop.c	Tue Feb 17 02:17:48 2004 +0000
@@ -0,0 +1,67 @@
+/**
+ * @file eventloop.c Gaim Event Loop API
+ * @ingroup core
+ *
+ * gaim
+ *
+ * Gaim is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include "eventloop.h"
+
+static GaimEventLoopUiOps *eventloop_ui_ops = NULL;
+
+guint
+gaim_timeout_add(guint interval, GSourceFunc function, gpointer data)
+{
+	GaimEventLoopUiOps *ops = gaim_eventloop_get_ui_ops();
+
+	return ops->timeout_add(interval, function, data);
+}
+
+gint
+gaim_input_add(int source, GaimInputCondition condition, GaimInputFunction func, gpointer user_data)
+{
+	GaimEventLoopUiOps *ops = gaim_eventloop_get_ui_ops();
+
+	return ops->input_add(source, condition, func, user_data);
+}
+
+void
+gaim_input_remove(gint tag)
+{
+	GaimEventLoopUiOps *ops = gaim_eventloop_get_ui_ops();
+
+	return ops->input_remove(tag);
+}
+
+void
+gaim_eventloop_set_ui_ops(GaimEventLoopUiOps *ops)
+{
+	eventloop_ui_ops = ops;
+}
+
+GaimEventLoopUiOps *
+gaim_eventloop_get_ui_ops(void)
+{
+	g_assert(eventloop_ui_ops != NULL);
+
+	return eventloop_ui_ops;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eventloop.h	Tue Feb 17 02:17:48 2004 +0000
@@ -0,0 +1,133 @@
+/**
+ * @file eventloop.h Gaim Event Loop API
+ * @ingroup core
+ *
+ * gaim
+ *
+ * Gaim is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef _GAIM_EVENTLOOP_H_
+#define _GAIM_EVENTLOOP_H_
+
+#include <glib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * An input condition.
+ */
+typedef enum
+{
+	GAIM_INPUT_READ  = 1 << 0,  /**< A read condition.  */
+	GAIM_INPUT_WRITE = 1 << 1   /**< A write condition. */
+
+} GaimInputCondition;
+
+typedef void (*GaimInputFunction)(gpointer, gint, GaimInputCondition);
+
+typedef struct _GaimEventLoopUiOps GaimEventLoopUiOps;
+
+struct _GaimEventLoopUiOps
+{
+	/**
+	 * Creates a callback timer.
+	 * @see g_timeout_add, gaim_timeout_add
+	 **/
+	guint (*timeout_add)(guint interval, GSourceFunc function, gpointer data);
+
+	/**
+	 * Adds an input handler.
+	 * @see gaim_input_add, g_io_add_watch_full
+	 */
+	gint (*input_add)(int source, GaimInputCondition cond,
+					  GaimInputFunction func, gpointer user_data);
+
+	/**
+	 * Removes an input handler.
+	 * @see gaim_input_remove, g_source_remove
+	 */
+	void (*input_remove)(gint handle);
+};
+
+/**************************************************************************/
+/** @name Event Loop API                                                  */
+/**************************************************************************/
+/*@{*/
+/**
+ * Creates a callback timer.
+ * The timer will repeat until the function returns <tt>FALSE</tt>. The
+ * first call will be at the end of the first interval.
+ * @param interval	The time between calls of the function, in
+ *					milliseconds.
+ * @param function	The function to call.
+ * @param data		data to pass to <tt>function</tt>.
+ **/
+guint gaim_timeout_add(guint interval, GSourceFunc function, gpointer data);
+
+/**
+ * Adds an input handler.
+ *
+ * @param source    The input source.
+ * @param cond      The condition type.
+ * @param func      The callback function for data.
+ * @param user_data User-specified data.
+ *
+ * @return The resulting handle.
+ * @see g_io_add_watch_full
+ */
+gint gaim_input_add(int source, GaimInputCondition cond,
+					GaimInputFunction func, gpointer user_data);
+
+/**
+ * Removes an input handler.
+ *
+ * @param handle The handle of the input handler.
+ */
+void gaim_input_remove(gint handle);
+
+/*@}*/
+
+
+/**************************************************************************/
+/** @name UI Registration Functions                                       */
+/**************************************************************************/
+/*@{*/
+/**
+ * Sets the UI operations structure to be used for accounts.
+ *
+ * @param ops The UI operations structure.
+ */
+void gaim_eventloop_set_ui_ops(GaimEventLoopUiOps *ops);
+
+/**
+ * Returns the UI operations structure used for accounts.
+ *
+ * @return The UI operations structure in use.
+ */
+GaimEventLoopUiOps *gaim_eventloop_get_ui_ops(void);
+
+/*@}*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GAIM_EVENTLOOP_H_ */
--- a/src/gaim-disclosure.c	Tue Feb 17 01:33:20 2004 +0000
+++ b/src/gaim-disclosure.c	Tue Feb 17 02:17:48 2004 +0000
@@ -192,7 +192,7 @@
 	}
 
 	disclosure->priv->direction = opening ? 1 : -1;
-	disclosure->priv->expand_id = g_timeout_add (50, expand_collapse_timeout, disclosure);
+	disclosure->priv->expand_id = gaim_timeout_add (50, expand_collapse_timeout, disclosure);
 }
 
 static void
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gtkeventloop.c	Tue Feb 17 02:17:48 2004 +0000
@@ -0,0 +1,114 @@
+/**
+ * @file gtk_eventloop.c Gaim Event Loop API (gtk implementation)
+ * @ingroup gtkui
+ *
+ * gaim
+ *
+ * Gaim is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <glib.h>
+#include "gtkeventloop.h"
+#include "eventloop.h"
+
+#define GAIM_GTK_READ_COND  (G_IO_IN | G_IO_HUP | G_IO_ERR)
+#define GAIM_GTK_WRITE_COND (G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL)
+
+typedef struct _GaimGtkIOClosure {
+	GaimInputFunction function;
+	guint result;
+	gpointer data;
+
+} GaimGtkIOClosure;
+
+static void gaim_gtk_io_destroy(gpointer data)
+{
+	g_free(data);
+}
+
+static gboolean gaim_gtk_io_invoke(GIOChannel *source, GIOCondition condition, gpointer data)
+{
+	GaimGtkIOClosure *closure = data;
+	GaimInputCondition gaim_cond = 0;
+
+	if (condition & GAIM_GTK_READ_COND)
+		gaim_cond |= GAIM_INPUT_READ;
+	if (condition & GAIM_GTK_WRITE_COND)
+		gaim_cond |= GAIM_INPUT_WRITE;
+
+#if 0
+	gaim_debug(GAIM_DEBUG_MISC, "gtk_eventloop",
+			   "CLOSURE: callback for %d, fd is %d\n",
+			   closure->result, g_io_channel_unix_get_fd(source));
+#endif
+
+	closure->function(closure->data, g_io_channel_unix_get_fd(source), gaim_cond);
+
+	return TRUE;
+}
+
+static gint gaim_gtk_input_add(gint source, GaimInputCondition condition, GaimInputFunction function,
+							   gpointer data)
+{
+	GaimGtkIOClosure *closure = g_new0(GaimGtkIOClosure, 1);
+	GIOChannel *channel;
+	GIOCondition cond = 0;
+
+	closure->function = function;
+	closure->data = data;
+
+	if (condition & GAIM_INPUT_READ)
+		cond |= GAIM_GTK_READ_COND;
+	if (condition & GAIM_INPUT_WRITE)
+		cond |= GAIM_GTK_WRITE_COND;
+
+	channel = g_io_channel_unix_new(source);
+	closure->result = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, cond,
+					      gaim_gtk_io_invoke, closure, gaim_gtk_io_destroy);
+
+#if 0
+	gaim_debug(GAIM_DEBUG_MISC, "gtk_eventloop",
+			   "CLOSURE: adding input watcher %d for fd %d\n",
+			   closure->result, source);
+#endif
+
+	g_io_channel_unref(channel);
+	return closure->result;
+}
+
+static void gaim_gtk_input_remove(gint tag)
+{
+	/* gaim_debug(GAIM_DEBUG_MISC, "proxy",
+	              "CLOSURE: removing input watcher %d\n", tag); */
+	if (tag > 0)
+		g_source_remove(tag);
+}
+
+static GaimEventLoopUiOps eventloop_ops =
+{
+	g_timeout_add,
+	gaim_gtk_input_add,
+	gaim_gtk_input_remove
+};
+
+GaimEventLoopUiOps *
+gaim_gtk_eventloop_get_ui_ops(void)
+{
+	return &eventloop_ops;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gtkeventloop.h	Tue Feb 17 02:17:48 2004 +0000
@@ -0,0 +1,34 @@
+/**
+ * @file gtkeventloop.h Gaim Event Loop API (gtk implementation)
+ * @ingroup gtkui
+ *
+ * gaim
+ *
+ * Gaim is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef _GAIM_GTKEVENTLOOP_H_
+#define _GAIM_GTKEVENTLOOP_H_
+#include "eventloop.h"
+
+/**
+ * Gets a static pointer to a gtk implementation of an eventloop.
+ */
+GaimEventLoopUiOps *gaim_gtk_eventloop_get_ui_ops(void);
+
+#endif /* _GAIM_GTKEVENTLOOP_H_ */
--- a/src/main.c	Tue Feb 17 01:33:20 2004 +0000
+++ b/src/main.c	Tue Feb 17 02:17:48 2004 +0000
@@ -27,6 +27,7 @@
 #include "conversation.h"
 #include "core.h"
 #include "debug.h"
+#include "eventloop.h"
 #include "ft.h"
 #include "log.h"
 #include "notify.h"
@@ -42,6 +43,7 @@
 #include "gtkconn.h"
 #include "gtkconv.h"
 #include "gtkdebug.h"
+#include "gtkeventloop.h"
 #include "gtkft.h"
 #include "gtknotify.h"
 #include "gtkplugin.h"
@@ -128,7 +130,7 @@
 			g_source_remove(snd_tmout);
 		}
 		gaim_gtk_sound_set_login_mute(TRUE);
-		snd_tmout = g_timeout_add(10000, sound_timeout, NULL);
+		snd_tmout = gaim_timeout_add(10000, sound_timeout, NULL);
 	}
 }
 
@@ -814,6 +816,7 @@
         wgaim_init(hint);
 #endif
 	gaim_core_set_ui_ops(gaim_gtk_core_get_ui_ops());
+	gaim_eventloop_set_ui_ops(gaim_gtk_eventloop_get_ui_ops());
 
 	if (!gaim_core_init(GAIM_GTK_UI)) {
 		fprintf(stderr,
--- a/src/pounce.c	Tue Feb 17 01:33:20 2004 +0000
+++ b/src/pounce.c	Tue Feb 17 02:17:48 2004 +0000
@@ -112,7 +112,7 @@
 schedule_pounces_save(void)
 {
 	if (!pounces_save_timer)
-		pounces_save_timer = g_timeout_add(5000, pounces_save_cb, NULL);
+		pounces_save_timer = gaim_timeout_add(5000, pounces_save_cb, NULL);
 }
 
 GaimPounce *
--- a/src/prefs.c	Tue Feb 17 01:33:20 2004 +0000
+++ b/src/prefs.c	Tue Feb 17 02:17:48 2004 +0000
@@ -79,7 +79,7 @@
 
 static void schedule_prefs_save() {
 	if(!prefs_save_timer)
-		prefs_save_timer = g_timeout_add(5000, prefs_save_callback, NULL);
+		prefs_save_timer = gaim_timeout_add(5000, prefs_save_callback, NULL);
 }
 
 static void prefs_save_cb(const char *name, GaimPrefType type, gpointer val,
--- a/src/protocols/icq/gaim_icq.c	Tue Feb 17 01:33:20 2004 +0000
+++ b/src/protocols/icq/gaim_icq.c	Tue Feb 17 02:17:48 2004 +0000
@@ -146,7 +146,7 @@
 static void icq_set_timeout(long interval) {
 	debug_printf("icq_SetTimeout: %ld\n", interval);
 	if (interval > 0 && ack_timer == 0)
-		ack_timer = g_timeout_add(interval * 1000, icq_set_timeout_cb, NULL);
+		ack_timer = gaim_timeout_add(interval * 1000, icq_set_timeout_cb, NULL);
 	else if (ack_timer > 0) {
 		g_source_remove(ack_timer);
 		ack_timer = 0;
--- a/src/protocols/irc/msgs.c	Tue Feb 17 01:33:20 2004 +0000
+++ b/src/protocols/irc/msgs.c	Tue Feb 17 02:17:48 2004 +0000
@@ -387,7 +387,7 @@
 	gaim_connection_set_state(gc, GAIM_CONNECTED);
 
 	irc_blist_timeout(irc);
-	irc->timer = g_timeout_add(45000, (GSourceFunc)irc_blist_timeout, (gpointer)irc);
+	irc->timer = gaim_timeout_add(45000, (GSourceFunc)irc_blist_timeout, (gpointer)irc);
 }
 
 void irc_msg_nochan(struct irc_conn *irc, const char *name, const char *from, char **args)
--- a/src/protocols/jabber/jabber.c	Tue Feb 17 01:33:20 2004 +0000
+++ b/src/protocols/jabber/jabber.c	Tue Feb 17 02:17:48 2004 +0000
@@ -438,7 +438,7 @@
 static void
 jabber_connection_schedule_close(JabberStream *js)
 {
-	g_timeout_add(0, conn_close_cb, js);
+	gaim_timeout_add(0, conn_close_cb, js);
 }
 
 static void
--- a/src/protocols/msn/httpmethod.c	Tue Feb 17 01:33:20 2004 +0000
+++ b/src/protocols/msn/httpmethod.c	Tue Feb 17 02:17:48 2004 +0000
@@ -78,7 +78,7 @@
 	stop_timer(servconn);
 
 	gaim_debug(GAIM_DEBUG_INFO, "msn", "Starting timer\n");
-	servconn->http_data->timer = g_timeout_add(5000, http_poll, servconn);
+	servconn->http_data->timer = gaim_timeout_add(5000, http_poll, servconn);
 }
 
 size_t
--- a/src/protocols/msn/msnslp.c	Tue Feb 17 01:33:20 2004 +0000
+++ b/src/protocols/msn/msnslp.c	Tue Feb 17 02:17:48 2004 +0000
@@ -336,7 +336,7 @@
 			if (stat(gaim_account_get_buddy_icon(account), &st) == 0)
 				slpsession->remaining_size = st.st_size;
 
-			slpsession->send_timer = g_timeout_add(10, send_cb, slpsession);
+			slpsession->send_timer = gaim_timeout_add(10, send_cb, slpsession);
 		}
 		else
 			return send_error_500(slpsession, call_id, msg);
--- a/src/protocols/oscar/oscar.c	Tue Feb 17 01:33:20 2004 +0000
+++ b/src/protocols/oscar/oscar.c	Tue Feb 17 02:17:48 2004 +0000
@@ -1464,7 +1464,7 @@
 
 	if (od->icontimer)
 		g_source_remove(od->icontimer);
-	od->icontimer = g_timeout_add(100, gaim_icon_timerfunc, gc);
+	od->icontimer = gaim_timeout_add(100, gaim_icon_timerfunc, gc);
 
 	return 1;
 }
@@ -1883,7 +1883,7 @@
 				od->requesticon = g_slist_append(od->requesticon, g_strdup(gaim_normalize(gc->account, info->sn)));
 				if (od->icontimer)
 					g_source_remove(od->icontimer);
-				od->icontimer = g_timeout_add(500, gaim_icon_timerfunc, gc);
+				od->icontimer = gaim_timeout_add(500, gaim_icon_timerfunc, gc);
 			}
 		}
 		g_free(b16);
@@ -3497,7 +3497,7 @@
 
 	if (od->icontimer)
 		g_source_remove(od->icontimer);
-	od->icontimer = g_timeout_add(500, gaim_icon_timerfunc, gc);
+	od->icontimer = gaim_timeout_add(500, gaim_icon_timerfunc, gc);
 
 	return 1;
 }
@@ -3545,7 +3545,7 @@
 
 	if (od->icontimer)
 		g_source_remove(od->icontimer);
-	od->icontimer = g_timeout_add(250, gaim_icon_timerfunc, gc);
+	od->icontimer = gaim_timeout_add(250, gaim_icon_timerfunc, gc);
 
 	return 1;
 }
@@ -4862,7 +4862,7 @@
 	if (reason == 0x0005) {
 		gaim_notify_error(gc, NULL, _("Unable To Retrieve Buddy List"),
 						  _("Gaim was temporarily unable to retrieve your buddy list from the AIM servers.  Your buddy list is not lost, and will probably become available in a few hours."));
-		od->getblisttimer = g_timeout_add(300000, gaim_ssi_rerequestdata, od->sess);
+		od->getblisttimer = gaim_timeout_add(300000, gaim_ssi_rerequestdata, od->sess);
 	}
 
 	/* Activate SSI */
@@ -5844,8 +5844,6 @@
 		gaim_input_remove(dim->watcher);   /* Otherwise, the callback will callback */
 		dim->watcher = 0;
 	}
-	/* XXX is this really necessary? */
-	gaim_core_mainloop_finish_events();
 
 	c = gaim_find_conversation_with_account(sn, gaim_connection_get_account(gc));
 	if (c != NULL)
--- a/src/protocols/trepia/trepia.c	Tue Feb 17 01:33:20 2004 +0000
+++ b/src/protocols/trepia/trepia.c	Tue Feb 17 02:17:48 2004 +0000
@@ -911,6 +911,11 @@
 					serv_got_update(session->gc, username, 1, 0, 0, 0, 0);
 				}
 
+				/*
+				 * XXX
+				 * This does nothing when using a non-gtk event loop.
+				 * What is it supposed to accomplish anyway?
+				 */
 				ctx = g_main_context_default();
 
 				while (g_main_context_pending(ctx))
--- a/src/protocols/zephyr/zephyr.c	Tue Feb 17 01:33:20 2004 +0000
+++ b/src/protocols/zephyr/zephyr.c	Tue Feb 17 02:17:48 2004 +0000
@@ -685,8 +685,8 @@
 	process_anyone();
 	process_zsubs();
 
-	nottimer = g_timeout_add(100, check_notify, NULL);
-	loctimer = g_timeout_add(20000, check_loc, NULL);
+	nottimer = gaim_timeout_add(100, check_notify, NULL);
+	loctimer = gaim_timeout_add(20000, check_loc, NULL);
 }
 
 static void write_zsubs()
--- a/src/proxy.c	Tue Feb 17 01:33:20 2004 +0000
+++ b/src/proxy.c	Tue Feb 17 02:17:48 2004 +0000
@@ -36,9 +36,6 @@
 #include "proxy.h"
 #include "util.h"
 
-#define GAIM_READ_COND  (G_IO_IN | G_IO_HUP | G_IO_ERR)
-#define GAIM_WRITE_COND (G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL)
-
 static GaimProxyInfo *global_proxy_info = NULL;
 
 static int opt_debug = 0;
@@ -53,13 +50,6 @@
 	GaimAccount *account;
 };
 
-typedef struct _GaimIOClosure {
-	GaimInputFunction function;
-	guint result;
-	gpointer data;
-
-} GaimIOClosure;
-
 const char* socks5errors[] = {
 	"succeeded\n",
 	"general SOCKS server failure\n",
@@ -194,69 +184,6 @@
 /**************************************************************************
  * Proxy API
  **************************************************************************/
-static void gaim_io_destroy(gpointer data)
-{
-	g_free(data);
-}
-
-static gboolean gaim_io_invoke(GIOChannel *source, GIOCondition condition, gpointer data)
-{
-	GaimIOClosure *closure = data;
-	GaimInputCondition gaim_cond = 0;
-
-	if (condition & GAIM_READ_COND)
-		gaim_cond |= GAIM_INPUT_READ;
-	if (condition & GAIM_WRITE_COND)
-		gaim_cond |= GAIM_INPUT_WRITE;
-
-#if 0
-	gaim_debug(GAIM_DEBUG_MISC, "proxy",
-			   "CLOSURE: callback for %d, fd is %d\n",
-			   closure->result, g_io_channel_unix_get_fd(source));
-#endif
-
-	closure->function(closure->data, g_io_channel_unix_get_fd(source), gaim_cond);
-
-	return TRUE;
-}
-
-gint gaim_input_add(gint source, GaimInputCondition condition, GaimInputFunction function, gpointer data)
-{
-	GaimIOClosure *closure = g_new0(GaimIOClosure, 1);
-	GIOChannel *channel;
-	GIOCondition cond = 0;
-
-	closure->function = function;
-	closure->data = data;
-
-	if (condition & GAIM_INPUT_READ)
-		cond |= GAIM_READ_COND;
-	if (condition & GAIM_INPUT_WRITE)
-		cond |= GAIM_WRITE_COND;
-
-	channel = g_io_channel_unix_new(source);
-	closure->result = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, cond,
-					      gaim_io_invoke, closure, gaim_io_destroy);
-
-#if 0
-	gaim_debug(GAIM_DEBUG_MISC, "proxy",
-			   "CLOSURE: adding input watcher %d for fd %d\n",
-			   closure->result, source);
-#endif
-
-	g_io_channel_unref(channel);
-	return closure->result;
-}
-
-void gaim_input_remove(gint tag)
-{
-	/* gaim_debug(GAIM_DEBUG_MISC, "proxy",
-	              "CLOSURE: removing input watcher %d\n", tag); */
-	if (tag > 0)
-		g_source_remove(tag);
-}
-
-
 typedef void (*dns_callback_t)(GSList *hosts, gpointer data,
 		const char *error_message);
 
@@ -727,7 +654,7 @@
 	req->addrlen = sizeof(sin);
 	req->data = data;
 	req->callback = callback;
-	g_timeout_add(10, host_resolved, req);
+	gaim_timeout_add(10, host_resolved, req);
 	return 0;
 }
 
@@ -738,16 +665,28 @@
 {
 	struct PHB *phb = data;
 	unsigned int len;
-	int error=0;
+	int error=0, ret;
 
 	gaim_debug(GAIM_DEBUG_INFO, "proxy", "Connected.\n");
 
 	len = sizeof(error);
 
-	if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
-/*	if (ret < 0 || error != 0) { */
-		/* The fourth parameter above isn't really "error", is it? */
-		/* if(ret==0) errno = error; */
+	/*
+	 * getsockopt after a non-blocking connect returns -1 if something is
+	 * really messed up (bad descriptor, usually). Otherwise, it returns 0 and
+	 * error holds what connect would have returned if it blocked until now.
+	 * Thus, error == 0 is success, error == EINPROGRESS means "try again",
+	 * and anything else is a real error.
+	 *
+	 * (error == EINPROGRESS can happen after a select because the kernel can
+	 * be overly optimistic sometimes. select is just a hint that you might be
+	 * able to do something.)
+	 */
+	ret = getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len);
+	if (ret == 0 && error == EINPROGRESS)
+		return; // we'll be called again later
+	if (ret < 0 || error != 0) {
+		if(ret==0) errno = error;
 		close(source);
 		gaim_input_remove(phb->inpa);
 
@@ -835,7 +774,7 @@
 		}
 		fcntl(fd, F_SETFL, 0);
 		phb->port = fd;	/* bleh */
-		g_timeout_add(50, clean_connect, phb);	/* we do this because we never
+		gaim_timeout_add(50, clean_connect, phb);	/* we do this because we never
 							   want to call our callback
 							   before we return. */
 	}
--- a/src/proxy.h	Tue Feb 17 01:33:20 2004 +0000
+++ b/src/proxy.h	Tue Feb 17 02:17:48 2004 +0000
@@ -26,6 +26,7 @@
 #define _GAIM_PROXY_H_
 
 #include <glib.h>
+#include "eventloop.h"
 
 /**
  * A type of proxy connection.
@@ -42,16 +43,6 @@
 } GaimProxyType;
 
 /**
- * An input condition.
- */
-typedef enum
-{
-	GAIM_INPUT_READ  = 1 << 0,  /**< A read condition.  */
-	GAIM_INPUT_WRITE = 1 << 1   /**< A write condition. */
-
-} GaimInputCondition;
-
-/**
  * Information on proxy settings.
  */
 typedef struct
@@ -65,8 +56,6 @@
 
 } GaimProxyInfo;
 
-typedef void (*GaimInputFunction)(gpointer, gint, GaimInputCondition);
-
 
 #include "account.h"
 
@@ -205,26 +194,6 @@
 void gaim_proxy_init(void);
 
 /**
- * Adds an input handler.
- *
- * @param source    The input source.
- * @param cond      The condition type.
- * @param func      The callback function for data.
- * @param user_data User-specified data.
- *
- * @return The resulting handle.
- */
-gint gaim_input_add(int source, GaimInputCondition cond,
-					GaimInputFunction func, gpointer user_data);
-
-/**
- * Removes an input handler.
- *
- * @param handle The handle of the input handler.
- */
-void gaim_input_remove(gint handle);
-
-/**
  * Makes a connection to the specified host and port.
  *
  * @param account The account making the connection.
--- a/src/server.c	Tue Feb 17 01:33:20 2004 +0000
+++ b/src/server.c	Tue Feb 17 02:17:48 2004 +0000
@@ -87,7 +87,7 @@
 {
 	if (on && !gc->keep_alive) {
 		gaim_debug(GAIM_DEBUG_INFO, "server", "allowing NOP\n");
-		gc->keep_alive = g_timeout_add(60000, send_keepalive, gc);
+		gc->keep_alive = gaim_timeout_add(60000, send_keepalive, gc);
 	} else if (!on && gc->keep_alive > 0) {
 		gaim_debug(GAIM_DEBUG_INFO, "server", "removing NOP\n");
 		g_source_remove(gc->keep_alive);
@@ -154,7 +154,7 @@
 	if (gc->idle_timer > 0)
 		g_source_remove(gc->idle_timer);
 
-	gc->idle_timer = g_timeout_add(20000, check_idle, gc);
+	gc->idle_timer = gaim_timeout_add(20000, check_idle, gc);
 	serv_touch_idle(gc);
 
 	/* Move this hack into toc.c */
@@ -219,7 +219,7 @@
 
 	/* because we're modifying or creating a lar, schedule the
 	 * function to expire them as the pref dictates */
-	g_timeout_add((gaim_prefs_get_int("/core/away/auto_response/sec_before_resend") + 1) * 1000,
+	gaim_timeout_add((gaim_prefs_get_int("/core/away/auto_response/sec_before_resend") + 1) * 1000,
 			expire_last_auto_responses, NULL);
 
 	tmp = last_auto_responses;
--- a/src/session.c	Tue Feb 17 01:33:20 2004 +0000
+++ b/src/session.c	Tue Feb 17 02:17:48 2004 +0000
@@ -24,6 +24,7 @@
 
 #include "core.h"
 #include "debug.h"
+#include "eventloop.h"
 
 extern char *opt_rcfile_arg;
 
@@ -45,8 +46,8 @@
 
 /* ICE belt'n'braces stuff */
 
-static gboolean ice_process_messages(GIOChannel *channel, GIOCondition condition,
-	      gpointer data) {
+static void ice_process_messages(gpointer data, gint fd,
+								 GaimInputCondition condition) {
 	IceConn connection = (IceConn)data;
 	IceProcessMessagesStatus status;
 
@@ -64,41 +65,28 @@
 		gaim_debug(GAIM_DEBUG_INFO, NULL, "done.\n");
 
 		/* cancel the handler */
-		return FALSE;
+		gaim_input_remove(IceConnectionNumber(connection));
 	}
-
-	/* live to see another day */
-	return TRUE;
 }
 
 static void ice_connection_watch(IceConn connection, IcePointer client_data,
 	      Bool opening, IcePointer *watch_data) {
-	guint input_id;
-
 	if (opening) {
-		GIOChannel *channel;
-
 		gaim_debug(GAIM_DEBUG_INFO, "Session Management",
 				   "Handling new ICE connection... ");
 
 		/* ensure ICE connection is not passed to child processes */
 		fcntl(IceConnectionNumber(connection), F_SETFD, FD_CLOEXEC);
 
-		/* get glib to watch the connection for us */
-		channel = g_io_channel_unix_new(IceConnectionNumber(connection));
-		input_id = g_io_add_watch(channel, G_IO_IN | G_IO_ERR,
-			     ice_process_messages, connection);
-		g_io_channel_unref(channel);
-
-		/* store the input ID as a pointer for when it closes */
-		*watch_data = (IcePointer)GUINT_TO_POINTER(input_id);
+		/* watch the connection */
+		gaim_input_add(IceConnectionNumber(connection), GAIM_INPUT_READ,
+					   ice_process_messages, connection);
 	} else {
 		gaim_debug(GAIM_DEBUG_INFO, "Session Management",
 				   "Handling closed ICE connection... ");
 
-		/* get the input ID back and stop watching it */
-		input_id = GPOINTER_TO_UINT((gpointer) *watch_data);
-		g_source_remove(input_id);
+		/* stop watching it */
+		gaim_input_remove(IceConnectionNumber(connection));
 	}
 
 	gaim_debug(GAIM_DEBUG_INFO, NULL, "done.\n");
--- a/src/status.c	Tue Feb 17 01:33:20 2004 +0000
+++ b/src/status.c	Tue Feb 17 02:17:48 2004 +0000
@@ -103,7 +103,7 @@
 schedule_status_save()
 {
 	if (!status_save_timer)
-		status_save_timer = g_timeout_add(5000, status_save_cb, NULL);
+		status_save_timer = gaim_timeout_add(5000, status_save_cb, NULL);
 }
 
 static void
--- a/src/win32/win32dep.c	Tue Feb 17 01:33:20 2004 +0000
+++ b/src/win32/win32dep.c	Tue Feb 17 02:17:48 2004 +0000
@@ -448,7 +448,7 @@
 		WGAIM_FLASH_INFO *finfo = g_new0(WGAIM_FLASH_INFO, 1);
 
 		/* Start Flashing window */
-		finfo->t_handle = g_timeout_add(1000, 
+		finfo->t_handle = gaim_timeout_add(1000, 
 						flash_window_cb, 
 						GDK_WINDOW_HWND(window->window));
 		finfo->sig_handler = g_signal_connect(G_OBJECT(window),