1 /* Function for handling the GLib event loop.
  2    Copyright (C) 2009, 2010
  3      Free Software Foundation, Inc.
  4 
  5 This file is part of GNU Emacs.
  6 
  7 GNU Emacs is free software: you can redistribute it and/or modify
  8 it under the terms of the GNU General Public License as published by
  9 the Free Software Foundation, either version 3 of the License, or
 10 (at your option) any later version.
 11 
 12 GNU Emacs is distributed in the hope that it will be useful,
 13 but WITHOUT ANY WARRANTY; without even the implied warranty of
 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 15 GNU General Public License for more details.
 16 
 17 You should have received a copy of the GNU General Public License
 18 along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 19 
 20 #include "config.h"
 21 
 22 #if defined (USE_GTK) || defined (HAVE_GCONF)
 23 #include <glib.h>
 24 #include <errno.h>
 25 #include <setjmp.h>
 26 #include "xgselect.h"
 27 
 28 static GPollFD *gfds;
 29 static int gfds_size;
 30 
 31 int
 32 xg_select (max_fds, rfds, wfds, efds, timeout)
 33      int max_fds;
 34      SELECT_TYPE *rfds;
 35      SELECT_TYPE *wfds;
 36      SELECT_TYPE *efds;
 37      EMACS_TIME *timeout;
 38 {
 39   SELECT_TYPE all_rfds, all_wfds;
 40   EMACS_TIME tmo, *tmop = timeout;
 41 
 42   GMainContext *context = g_main_context_default ();
 43   int have_wfds = wfds != NULL;
 44   int n_gfds = 0, our_tmo = 0, retval = 0, our_fds = 0;
 45   int prio, i, nfds, tmo_in_millisec;
 46 
 47   if (rfds) memcpy (&all_rfds, rfds, sizeof (all_rfds));
 48   else FD_ZERO (&all_rfds);
 49   if (wfds) memcpy (&all_wfds, wfds, sizeof (all_rfds));
 50   else FD_ZERO (&all_wfds);
 51 
 52   /* Update event sources in GLib. */
 53   g_main_context_pending (context);
 54 
 55   do {
 56     if (n_gfds > gfds_size) 
 57       {
 58         while (n_gfds > gfds_size) 
 59           gfds_size *= 2;
 60         xfree (gfds);
 61         gfds = xmalloc (sizeof (*gfds) * gfds_size);
 62       }
 63 
 64     n_gfds = g_main_context_query (context,
 65                                    G_PRIORITY_LOW,
 66                                    &tmo_in_millisec,
 67                                    gfds,
 68                                    gfds_size);
 69   } while (n_gfds > gfds_size);
 70 
 71   for (i = 0; i < n_gfds; ++i) 
 72     {
 73       if (gfds[i].events & G_IO_IN)
 74         {
 75           FD_SET (gfds[i].fd, &all_rfds);
 76           if (gfds[i].fd > max_fds) max_fds = gfds[i].fd;
 77         }
 78       if (gfds[i].events & G_IO_OUT)
 79         {
 80           FD_SET (gfds[i].fd, &all_wfds);
 81           if (gfds[i].fd > max_fds) max_fds = gfds[i].fd;
 82           have_wfds = 1;
 83         }
 84     }
 85 
 86   if (tmo_in_millisec >= 0)
 87     {
 88       EMACS_SET_SECS_USECS (tmo, tmo_in_millisec/1000,
 89                             1000 * (tmo_in_millisec % 1000));
 90       if (!timeout) our_tmo = 1;
 91       else
 92         {
 93           EMACS_TIME difference;
 94           
 95           EMACS_SUB_TIME (difference, tmo, *timeout);
 96           if (EMACS_TIME_NEG_P (difference)) our_tmo = 1;
 97         }
 98 
 99       if (our_tmo) tmop = &tmo;
100     }
101 
102   nfds = select (max_fds+1, &all_rfds, have_wfds ? &all_wfds : NULL,
103                  efds, tmop);
104 
105   if (nfds < 0)
106     retval = nfds;
107   else if (nfds > 0) 
108     {
109       for (i = 0; i < max_fds+1; ++i)
110         {
111           if (FD_ISSET (i, &all_rfds))
112             {
113               if (rfds && FD_ISSET (i, rfds)) ++retval;
114               else ++our_fds;
115             }
116           if (have_wfds && FD_ISSET (i, &all_wfds))
117             {
118               if (wfds && FD_ISSET (i, wfds)) ++retval;
119               else ++our_fds;
120             }
121           if (efds && FD_ISSET (i, efds))
122             ++retval;
123         }
124     }
125 
126   if (our_fds > 0 || (nfds == 0 && our_tmo))
127     {
128       
129       /* If Gtk+ is in use eventually gtk_main_iteration will be called,
130          unless retval is zero.  */
131 #ifdef USE_GTK
132       if (retval == 0)
133 #endif
134         while (g_main_context_pending (context))
135           g_main_context_dispatch (context);
136 
137       /* To not have to recalculate timeout, return like this.  */
138       if (retval == 0) 
139         {
140           retval = -1;
141           errno = EINTR;
142         }
143     }
144 
145   return retval;
146 }
147 #endif /* defined (USE_GTK) || defined (HAVE_GCONF) */
148 
149 void
150 xgselect_initialize ()
151 {
152 #if defined (USE_GTK) || defined (HAVE_GCONF)
153   gfds_size = 128;
154   gfds = xmalloc (sizeof (*gfds)*gfds_size);
155 #endif /* defined (USE_GTK) || defined (HAVE_GCONF) */
156 }
157 
158 /* arch-tag: c5873ee3-d1f6-44f9-9f3b-b14f70fd0e6a
159    (do not change this comment) */