Index: aim.c
===================================================================
--- aim.c	(revision 3472845ecdabe9cd1549dd2b2355ca745059ea36)
+++ aim.c	(revision dc1edbded39e57c67e8049c2960f0c235cd5afb5)
@@ -446,7 +446,6 @@
 }
 
-int owl_aim_process_events(void)
-{
-  aim_session_t *aimsess;
+int owl_aim_process_events(aim_session_t *aimsess)
+{
   aim_conn_t *waitingconn = NULL;
   struct timeval tv;
@@ -454,5 +453,4 @@
   struct owlfaim_priv *priv;
 
-  aimsess=owl_global_get_aimsess(&g);
   priv = aimsess->aux_data;
 
@@ -1795,8 +1793,113 @@
 }
 
-void owl_process_aim(void)
-{
-  if (owl_global_is_doaimevents(&g)) {
-    owl_aim_process_events();
-  }
-}
+typedef struct _owl_aim_event_source { /*noproto*/
+  GSource source;
+  aim_session_t *sess;
+  GPtrArray *fds;
+} owl_aim_event_source;
+
+static void truncate_pollfd_list(owl_aim_event_source *event_source, int len)
+{
+  GPollFD *fd;
+  int i;
+  if (len < event_source->fds->len)
+    owl_function_debugmsg("Truncating AIM PollFDs to %d, was %d", len, event_source->fds->len);
+  for (i = len; i < event_source->fds->len; i++) {
+    fd = event_source->fds->pdata[i];
+    g_source_remove_poll(&event_source->source, fd);
+    g_free(fd);
+  }
+  g_ptr_array_remove_range(event_source->fds, len, event_source->fds->len - len);
+}
+
+static gboolean owl_aim_event_source_prepare(GSource *source, int *timeout)
+{
+  owl_aim_event_source *event_source = (owl_aim_event_source*)source;
+  aim_conn_t *cur;
+  GPollFD *fd;
+  int i;
+
+  /* AIM HACK:
+   *
+   *  The problem - I'm not sure where to hook into the owl/faim
+   *  interface to keep track of when the AIM socket(s) open and
+   *  close. In particular, the bosconn thing throws me off. So,
+   *  rather than register particular dispatchers for AIM, I look up
+   *  the relevant FDs and add them to select's watch lists, then
+   *  check for them individually before moving on to the other
+   *  dispatchers. --asedeno
+   */
+  i = 0;
+  for (cur = event_source->sess->connlist; cur; cur = cur->next) {
+    if (cur->fd != -1) {
+      /* Add new GPollFDs as necessary. */
+      if (i == event_source->fds->len) {
+	fd = g_new0(GPollFD, 1);
+	g_ptr_array_add(event_source->fds, fd);
+	g_source_add_poll(source, fd);
+        owl_function_debugmsg("Allocated new AIM PollFD, len = %d", event_source->fds->len);
+      }
+      fd = event_source->fds->pdata[i];
+      fd->fd = cur->fd;
+      fd->events |= G_IO_IN | G_IO_HUP | G_IO_ERR;
+      if (cur->status & AIM_CONN_STATUS_INPROGRESS) {
+        /* Yes, we're checking writable sockets here. Without it, AIM
+           login is really slow. */
+	fd->events |= G_IO_OUT;
+      }
+      i++;
+    }
+  }
+  /* If the number of GPollFDs went down, clean up. */
+  truncate_pollfd_list(event_source, i);
+
+  *timeout = -1;
+  return FALSE;
+}
+
+static gboolean owl_aim_event_source_check(GSource *source)
+{
+  owl_aim_event_source *event_source = (owl_aim_event_source*)source;
+  int i;
+
+  for (i = 0; i < event_source->fds->len; i++) {
+    GPollFD *fd = event_source->fds->pdata[i];
+    if (fd->revents & fd->events)
+      return TRUE;
+  }
+  return FALSE;
+}
+
+static gboolean owl_aim_event_source_dispatch(GSource *source, GSourceFunc callback, gpointer user_data)
+{
+  owl_aim_event_source *event_source = (owl_aim_event_source*)source;
+  owl_aim_process_events(event_source->sess);
+  return TRUE;
+}
+
+static void owl_aim_event_source_finalize(GSource *source)
+{
+  owl_aim_event_source *event_source = (owl_aim_event_source*)source;
+  truncate_pollfd_list(event_source, 0);
+  g_ptr_array_free(event_source->fds, TRUE);
+}
+
+static GSourceFuncs aim_event_funcs = {
+  owl_aim_event_source_prepare,
+  owl_aim_event_source_check,
+  owl_aim_event_source_dispatch,
+  owl_aim_event_source_finalize,
+};
+
+GSource *owl_aim_event_source_new(aim_session_t *sess)
+{
+  GSource *source;
+  owl_aim_event_source *event_source;
+
+  source = g_source_new(&aim_event_funcs, sizeof(owl_aim_event_source));
+  event_source = (owl_aim_event_source *)source;
+  event_source->sess = sess;
+  /* TODO: When we depend on glib 2.22+, use g_ptr_array_new_with_free_func. */
+  event_source->fds = g_ptr_array_new();
+  return source;
+}
Index: global.c
===================================================================
--- global.c	(revision 47128d939b8cf3c9833095b626efc1efcee0744f)
+++ global.c	(revision dc1edbded39e57c67e8049c2960f0c235cd5afb5)
@@ -696,18 +696,24 @@
 }
 
-int owl_global_is_doaimevents(const owl_global *g)
-{
-  if (g->aim_doprocessing) return(1);
-  return(0);
+bool owl_global_is_doaimevents(const owl_global *g)
+{
+  return g->aim_event_source != NULL;
 }
 
 void owl_global_set_doaimevents(owl_global *g)
 {
-  g->aim_doprocessing=1;
+  if (g->aim_event_source)
+    return;
+  g->aim_event_source = owl_aim_event_source_new(owl_global_get_aimsess(g));
+  g_source_attach(g->aim_event_source, NULL);
 }
 
 void owl_global_set_no_doaimevents(owl_global *g)
 {
-  g->aim_doprocessing=0;
+  if (!g->aim_event_source)
+    return;
+  g_source_destroy(g->aim_event_source);
+  g_source_unref(g->aim_event_source);
+  g->aim_event_source = NULL;
 }
 
Index: owl.h
===================================================================
--- owl.h	(revision 47128d939b8cf3c9833095b626efc1efcee0744f)
+++ owl.h	(revision dc1edbded39e57c67e8049c2960f0c235cd5afb5)
@@ -610,5 +610,5 @@
   aim_conn_t bosconn;
   int aim_loggedin;         /* true if currently logged into AIM */
-  int aim_doprocessing;     /* true if we should process AIM events (like pending login) */
+  GSource *aim_event_source; /* where we get our AIM events from */
   char *aim_screenname;     /* currently logged in AIM screen name */
   char *aim_screenname_for_filters;     /* currently logged in AIM screen name */
Index: select.c
===================================================================
--- select.c	(revision 257b9c4167ca2e12d88c2e3296cee64846a2a8cd)
+++ select.c	(revision dc1edbded39e57c67e8049c2960f0c235cd5afb5)
@@ -296,28 +296,4 @@
 }
 
-int owl_select_aim_hack(fd_set *rfds, fd_set *wfds)
-{
-  aim_conn_t *cur;
-  aim_session_t *sess;
-  int max_fd;
-
-  max_fd = 0;
-  sess = owl_global_get_aimsess(&g);
-  for (cur = sess->connlist; cur; cur = cur->next) {
-    if (cur->fd != -1) {
-      FD_SET(cur->fd, rfds);
-      if (cur->status & AIM_CONN_STATUS_INPROGRESS) {
-        /* Yes, we're checking writable sockets here. Without it, AIM
-           login is really slow. */
-        FD_SET(cur->fd, wfds);
-      }
-      
-      if (cur->fd > max_fd)
-        max_fd = cur->fd;
-    }
-  }
-  return max_fd;
-}
-
 void owl_process_input_char(owl_input j)
 {
@@ -331,92 +307,4 @@
 }
 
-#if 0
-/* FIXME: Reimplement the AIM hack and handle AIM events. */
-void owl_select(void)
-{
-  int i, max_fd, max_fd2, aim_done, ret;
-  fd_set r;
-  fd_set w;
-  fd_set e;
-  fd_set aim_rfds, aim_wfds;
-  struct timespec timeout;
-  sigset_t mask;
-
-  owl_select_process_timers(&timeout);
-
-  owl_select_mask_signals(&mask);
-
-  if(owl_global_is_interrupted(&g)) {
-    owl_select_handle_intr(&mask);
-    return;
-  }
-  FD_ZERO(&r);
-  FD_ZERO(&w);
-  FD_ZERO(&e);
-
-  max_fd = owl_select_prepare_io_dispatch_fd_sets(&r, &w, &e);
-
-  /* AIM HACK: 
-   *
-   *  The problem - I'm not sure where to hook into the owl/faim
-   *  interface to keep track of when the AIM socket(s) open and
-   *  close. In particular, the bosconn thing throws me off. So,
-   *  rather than register particular dispatchers for AIM, I look up
-   *  the relevant FDs and add them to select's watch lists, then
-   *  check for them individually before moving on to the other
-   *  dispatchers. --asedeno
-   */
-  aim_done = 1;
-  FD_ZERO(&aim_rfds);
-  FD_ZERO(&aim_wfds);
-  if (owl_global_is_doaimevents(&g)) {
-    aim_done = 0;
-    max_fd2 = owl_select_aim_hack(&aim_rfds, &aim_wfds);
-    if (max_fd < max_fd2) max_fd = max_fd2;
-    for(i = 0; i <= max_fd2; i++) {
-      if (FD_ISSET(i, &aim_rfds)) {
-        FD_SET(i, &r);
-        FD_SET(i, &e);
-      }
-      if (FD_ISSET(i, &aim_wfds)) {
-        FD_SET(i, &w);
-        FD_SET(i, &e);
-      }
-    }
-  }
-  /* END AIM HACK */
-
-  if (owl_select_do_pre_select_actions()) {
-    timeout.tv_sec = 0;
-    timeout.tv_nsec = 0;
-  }
-
-  ret = pselect(max_fd+1, &r, &w, &e, &timeout, &mask);
-
-  if(ret < 0 && errno == EINTR) {
-    if(owl_global_is_interrupted(&g)) {
-      owl_select_handle_intr(NULL);
-    }
-    sigprocmask(SIG_SETMASK, &mask, NULL);
-    return;
-  }
-
-  sigprocmask(SIG_SETMASK, &mask, NULL);
-
-  if(ret > 0) {
-    /* AIM HACK: process all AIM events at once. */
-    for(i = 0; !aim_done && i <= max_fd; i++) {
-      if (FD_ISSET(i, &r) || FD_ISSET(i, &w) || FD_ISSET(i, &e)) {
-        if (FD_ISSET(i, &aim_rfds) || FD_ISSET(i, &aim_wfds)) {
-          owl_process_aim();
-          aim_done = 1;
-        }
-      }
-    }
-    owl_select_io_dispatch(&r, &w, &e, max_fd);
-  }
-}
-#endif
-
 void owl_select_init(void)
 {
