]> code.delx.au - gnu-emacs/blobdiff - src/xgselect.c
Backport: Don't cache images in nsimage.m (Bug#18918).
[gnu-emacs] / src / xgselect.c
index 1d3f916c9f8284fdc88cf18c7ca7b36d343bd890..6b22f3d1376cb66cc21c10d6db034ff80851e7f6 100644 (file)
@@ -28,6 +28,18 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <stdbool.h>
 #include <timespec.h>
 #include "frame.h"
+#include "blockinput.h"
+
+/* `xg_select' is a `pselect' replacement.  Why do we need a separate function?
+   1. Timeouts.  Glib and Gtk rely on timer events.  If we did pselect
+      with a greater timeout then the one scheduled by Glib, we would
+      not allow Glib to process its timer events.  We want Glib to
+      work smoothly, so we need to reduce our timeout to match Glib.
+   2. Descriptors.  Glib may listen to more file descriptors than we do.
+      So we add Glib descriptors to our pselect pool, but we don't change
+      the value returned by the function.  The return value  matches only
+      the descriptors passed as arguments, making it compatible with
+      plain pselect.  */
 
 int
 xg_select (int fds_lim, fd_set *rfds, fd_set *wfds, fd_set *efds,
@@ -43,25 +55,28 @@ xg_select (int fds_lim, fd_set *rfds, fd_set *wfds, fd_set *efds,
   GPollFD *gfds = gfds_buf;
   int gfds_size = sizeof gfds_buf / sizeof *gfds_buf;
   int n_gfds, retval = 0, our_fds = 0, max_fds = fds_lim - 1;
-  int i, nfds, tmo_in_millisec;
+  bool context_acquired = false;
+  int i, nfds, tmo_in_millisec = -1;
   bool need_to_dispatch;
   USE_SAFE_ALLOCA;
 
-  /* Do not try to optimize with an initial check with g_main_context_pending
-     and a call to pselect if it returns false.  If Gdk has a timeout for 0.01
-     second, and Emacs has a timeout for 1 second, g_main_context_pending will
-     return false, but the timeout will be 1 second, thus missing the gdk
-     timeout with a lot.  */
-
   context = g_main_context_default ();
+  context_acquired = g_main_context_acquire (context);
+  /* FIXME: If we couldn't acquire the context, we just silently proceed
+     because this function handles more than just glib file descriptors.
+     Note that, as implemented, this failure is completely silent: there is
+     no feedback to the caller.  */
 
   if (rfds) all_rfds = *rfds;
   else FD_ZERO (&all_rfds);
   if (wfds) all_wfds = *wfds;
   else FD_ZERO (&all_wfds);
 
-  n_gfds = g_main_context_query (context, G_PRIORITY_LOW, &tmo_in_millisec,
-                                gfds, gfds_size);
+  n_gfds = (context_acquired
+           ? g_main_context_query (context, G_PRIORITY_LOW, &tmo_in_millisec,
+                                   gfds, gfds_size)
+           : -1);
+
   if (gfds_size < n_gfds)
     {
       SAFE_NALLOCA (gfds, sizeof *gfds, n_gfds);
@@ -136,11 +151,19 @@ xg_select (int fds_lim, fd_set *rfds, fd_set *wfds, fd_set *efds,
   if (need_to_dispatch)
     {
       int pselect_errno = errno;
+      /* Prevent g_main_dispatch recursion, that would occur without
+         block_input wrapper, because event handlers call
+         unblock_input.  Event loop recursion was causing Bug#15801.  */
+      block_input ();
       while (g_main_context_pending (context))
-       g_main_context_dispatch (context);
+        g_main_context_dispatch (context);
+      unblock_input ();
       errno = pselect_errno;
     }
 
+  if (context_acquired)
+    g_main_context_release (context);
+
   /* To not have to recalculate timeout, return like this.  */
   if ((our_fds > 0 || (nfds == 0 && tmop == &tmo)) && (retval == 0))
     {