]> git.eshelyaron.com Git - emacs.git/commitdiff
Use a select wrapper around the GLib event loop, thus taking into account GLib
authorJan Djärv <jan.h.d@swipnet.se>
Sat, 21 Nov 2009 15:28:59 +0000 (15:28 +0000)
committerJan Djärv <jan.h.d@swipnet.se>
Sat, 21 Nov 2009 15:28:59 +0000 (15:28 +0000)
timeouts and event sources.  This simplifies Gtk+-code a lot, and is needed
for handling GConf death/restart.

* xterm.c: #include xgselect.h.
(x_initialize): Call xgselect_initialize.

* xsettings.c (something_changedCB): C++ comments => C comments.
(init_gconf): Do not deal with any GLib file descriptors, xg_select
does that now.

* gtkutil.c (xg_timer, xg_process_timeouts, xg_start_timer)
(xg_stop_timer, menu_grab_callback_cnt, menu_grab_callback)
(scroll_bar_button_cb): Remove.
(create_menus): C++ comments => C comments. Don't bind grab-notify
event.
(xg_create_scroll_bar): Don't bind button-press-event and
button-release-event.

* process.c: Include xgselect.h if defined (USE_GTK) ||
defined (HAVE_GCONF).
(wait_reading_process_output): Call xg_select for the same condition.

* xgselect.c (xg_select): New function to better integrate with
GLib/Gtk event handling.  Needed if GConf daemon dies/restarts.

* xgselect.h: New file, declare xg_select, xgselect_initialize.

* Makefile.in (XOBJ): Add xgselect.o.

src/ChangeLog
src/Makefile.in
src/gtkutil.c
src/process.c
src/xgselect.c [new file with mode: 0644]
src/xgselect.h [new file with mode: 0644]
src/xsettings.c
src/xterm.c

index 7f6891e0710969c9aea9c5c7b54cc27526644252..27c2b7246af0a438110dafaa726a9fc472716158 100644 (file)
@@ -1,3 +1,31 @@
+2009-11-21  Jan Djärv  <jan.h.d@swipnet.se>
+
+       * xterm.c: #include xgselect.h.
+       (x_initialize): Call xgselect_initialize.
+
+       * xsettings.c (something_changedCB): C++ comments => C comments.
+       (init_gconf): Do not deal with any GLib file descriptors, xg_select
+       does that now.
+
+       * gtkutil.c (xg_timer, xg_process_timeouts, xg_start_timer)
+       (xg_stop_timer, menu_grab_callback_cnt, menu_grab_callback)
+       (scroll_bar_button_cb): Remove.
+       (create_menus): C++ comments => C comments. Don't bind grab-notify
+       event.
+       (xg_create_scroll_bar): Don't bind button-press-event and
+       button-release-event.
+
+       * process.c: Include xgselect.h if defined (USE_GTK) ||
+       defined (HAVE_GCONF).
+       (wait_reading_process_output): Call xg_select for the same condition.
+
+       * xgselect.c (xg_select): New function to better integrate with
+       GLib/Gtk event handling.  Needed if GConf daemon dies/restarts.
+
+       * xgselect.h: New file, declare xg_select, xgselect_initialize.
+
+       * Makefile.in (XOBJ): Add xgselect.o.
+
 2009-11-21  Andreas Schwab  <schwab@linux-m68k.org>
 
        * character.h (STRING_CHAR, STRING_CHAR_AND_LENGTH): Remove
index 3d81cc1f2bc3ddf24e30b128d873080f70365fb9..aceecacb5c7137eaf428bc8f459435cec48557fa 100644 (file)
@@ -292,7 +292,7 @@ ALL_OBJC_CFLAGS=$(ALL_CFLAGS) @GNU_OBJC_CFLAGS@
 #ifdef HAVE_X_WINDOWS
 XMENU_OBJ = xmenu.o
 XOBJ= xterm.o xfns.o xselect.o xrdb.o fontset.o xsmfns.o fringe.o image.o \
-      xsettings.o
+      xsettings.o xgselect.o
 
 #ifdef HAVE_MENUS
 
index 4a55e51b8b23dd2087b05538ea605960027f5d1c..b1e238af55c7863e1a4701df298942e549850df4 100644 (file)
@@ -29,7 +29,6 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "blockinput.h"
 #include "syssignal.h"
 #include "window.h"
-#include "atimer.h"
 #include "gtkutil.h"
 #include "termhooks.h"
 #include "keyboard.h"
@@ -181,11 +180,6 @@ xg_display_close (Display *dpy)
 /***********************************************************************
                       Utility functions
  ***********************************************************************/
-/* The timer for scroll bar repetition and menu bar timeouts.
-   NULL if no timer is started.  */
-static struct atimer *xg_timer;
-
-
 /* The next two variables and functions are taken from lwlib.  */
 static widget_value *widget_value_free_list;
 static int malloc_cpt;
@@ -426,58 +420,6 @@ xg_set_cursor (w, cursor)
     gdk_window_set_cursor (GDK_WINDOW (children->data), cursor);
 }
 
-/*  Timer function called when a timeout occurs for xg_timer.
-    This function processes all GTK events in a recursive event loop.
-    This is done because GTK timer events are not seen by Emacs event
-    detection, Emacs only looks for X events.  When a scroll bar has the
-    pointer (detected by button press/release events below) an Emacs
-    timer is started, and this function can then check if the GTK timer
-    has expired by calling the GTK event loop.
-    Also, when a menu is active, it has a small timeout before it
-    pops down the sub menu under it.  */
-
-static void
-xg_process_timeouts (timer)
-     struct atimer *timer;
-{
-  BLOCK_INPUT;
-  /* Ideally we would like to just handle timer events, like the Xt version
-     of this does in xterm.c, but there is no such feature in GTK.  */
-  while (gtk_events_pending ())
-    gtk_main_iteration ();
-  UNBLOCK_INPUT;
-}
-
-/* Start the xg_timer with an interval of 0.1 seconds, if not already started.
-   xg_process_timeouts is called when the timer expires.  The timer
-   started is continuous, i.e. runs until xg_stop_timer is called.  */
-
-static void
-xg_start_timer ()
-{
-  if (! xg_timer)
-    {
-      EMACS_TIME interval;
-      EMACS_SET_SECS_USECS (interval, 0, 100000);
-      xg_timer = start_atimer (ATIMER_CONTINUOUS,
-                               interval,
-                               xg_process_timeouts,
-                               0);
-    }
-}
-
-/* Stop the xg_timer if started.  */
-
-static void
-xg_stop_timer ()
-{
-  if (xg_timer)
-    {
-      cancel_atimer (xg_timer);
-      xg_timer = 0;
-    }
-}
-
 /* Insert NODE into linked LIST.  */
 
 static void
@@ -1895,29 +1837,6 @@ menu_destroy_callback (w, client_data)
   unref_cl_data ((xg_menu_cb_data*) client_data);
 }
 
-/* Callback called when a menu does a grab or ungrab.  That means the
-   menu has been activated or deactivated.
-   Used to start a timer so the small timeout the menus in GTK uses before
-   popping down a menu is seen by Emacs (see xg_process_timeouts above).
-   W is the widget that does the grab (not used).
-   UNGRAB_P is TRUE if this is an ungrab, FALSE if it is a grab.
-   CLIENT_DATA is NULL (not used).  */
-
-/* Keep track of total number of grabs.  */
-static int menu_grab_callback_cnt;
-
-static void
-menu_grab_callback (GtkWidget *widget,
-                    gboolean ungrab_p,
-                    gpointer client_data)
-{
-  if (ungrab_p) menu_grab_callback_cnt--;
-  else menu_grab_callback_cnt++;
-
-  if (menu_grab_callback_cnt > 0 && ! xg_timer) xg_start_timer ();
-  else if (menu_grab_callback_cnt == 0 && xg_timer) xg_stop_timer ();
-}
-
 /* Make a GTK widget that contains both UTF8_LABEL and UTF8_KEY (both
    must be non-NULL) and can be inserted into a menu item.
 
@@ -2232,10 +2151,10 @@ create_menus (data, f, select_cb, deactivate_cb, highlight_cb,
       else
         {
           wmenu = gtk_menu_bar_new ();
-          // Set width of menu bar to a small value so it doesn't enlarge
-          // a small initial frame size.  The width will be set to the
-          // width of the frame later on when it is added to a container.
-          // height -1: Natural height.
+          /* Set width of menu bar to a small value so it doesn't enlarge
+             a small initial frame size.  The width will be set to the
+             width of the frame later on when it is added to a container.
+             height -1: Natural height.  */
           gtk_widget_set_size_request (wmenu, 1, -1);
         }
 
@@ -2251,9 +2170,6 @@ create_menus (data, f, select_cb, deactivate_cb, highlight_cb,
       if (deactivate_cb)
         g_signal_connect (G_OBJECT (wmenu),
                           "selection-done", deactivate_cb, 0);
-
-      g_signal_connect (G_OBJECT (wmenu),
-                        "grab-notify", G_CALLBACK (menu_grab_callback), 0);
     }
 
   if (! menu_bar_p && add_tearoff_p)
@@ -3177,34 +3093,6 @@ xg_gtk_scroll_destroy (widget, data)
   xg_remove_widget_from_map (id);
 }
 
-/* Callback for button press/release events.  Used to start timer so that
-   the scroll bar repetition timer in GTK gets handled.
-   Also, sets bar->dragging to Qnil when dragging (button release) is done.
-   WIDGET is the scroll bar widget the event is for (not used).
-   EVENT contains the event.
-   USER_DATA points to the struct scrollbar structure.
-
-   Returns FALSE to tell GTK that it shall continue propagate the event
-   to widgets.  */
-
-static gboolean
-scroll_bar_button_cb (widget, event, user_data)
-     GtkWidget *widget;
-     GdkEventButton *event;
-     gpointer user_data;
-{
-  if (event->type == GDK_BUTTON_PRESS && ! xg_timer)
-    xg_start_timer ();
-  else if (event->type == GDK_BUTTON_RELEASE)
-    {
-      struct scroll_bar *bar = (struct scroll_bar *) user_data;
-      if (xg_timer) xg_stop_timer ();
-      bar->dragging = Qnil;
-    }
-
-  return FALSE;
-}
-
 /* Create a scroll bar widget for frame F.  Store the scroll bar
    in BAR.
    SCROLL_CALLBACK is the callback to invoke when the value of the
@@ -3246,17 +3134,6 @@ xg_create_scroll_bar (f, bar, scroll_callback, scroll_bar_name)
                     G_CALLBACK (xg_gtk_scroll_destroy),
                     (gpointer) (EMACS_INT) scroll_id);
 
-  /* Connect to button press and button release to detect if any scroll bar
-     has the pointer.  */
-  g_signal_connect (G_OBJECT (wscroll),
-                    "button-press-event",
-                    G_CALLBACK (scroll_bar_button_cb),
-                    (gpointer) bar);
-  g_signal_connect (G_OBJECT (wscroll),
-                    "button-release-event",
-                    G_CALLBACK (scroll_bar_button_cb),
-                    (gpointer) bar);
-
   /* The scroll bar widget does not draw on a window of its own.  Instead
      it draws on the parent window, in this case the edit widget.  So
      whenever the edit widget is cleared, the scroll bar needs to redraw
index 5c6875520e6d9d0787b1eab877b631d07717a182..90f2a9aa6bb5232a4e85159de6749e77401cb238 100644 (file)
@@ -120,6 +120,10 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "composite.h"
 #include "atimer.h"
 
+#if defined (USE_GTK) || defined (HAVE_GCONF)
+#include "xgselect.h"
+#endif /* defined (USE_GTK) || defined (HAVE_GCONF) */
+
 Lisp_Object Qprocessp;
 Lisp_Object Qrun, Qstop, Qsignal;
 Lisp_Object Qopen, Qclosed, Qconnect, Qfailed, Qlisten;
@@ -4922,7 +4926,9 @@ wait_reading_process_output (time_limit, microsecs, read_kbd, do_display,
              process_output_skip = 0;
            }
 #endif
-#ifdef HAVE_NS
+#if defined (USE_GTK) || defined (HAVE_GCONF)
+          nfds = xg_select
+#elif defined (HAVE_NS)
          nfds = ns_select
 #else
          nfds = select
diff --git a/src/xgselect.c b/src/xgselect.c
new file mode 100644 (file)
index 0000000..3c5a99f
--- /dev/null
@@ -0,0 +1,157 @@
+/* Function for handling the GLib event loop.
+   Copyright (C) 2009
+     Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs 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 3 of the License, or
+(at your option) any later version.
+
+GNU Emacs 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+
+#if defined (USE_GTK) || defined (HAVE_GCONF)
+#include <glib.h>
+#include <errno.h>
+#include <setjmp.h>
+#include "xgselect.h"
+
+static GPollFD *gfds;
+static int gfds_size;
+
+int
+xg_select (max_fds, rfds, wfds, efds, timeout)
+     int max_fds;
+     SELECT_TYPE *rfds;
+     SELECT_TYPE *wfds;
+     SELECT_TYPE *efds;
+     EMACS_TIME *timeout;
+{
+  SELECT_TYPE all_rfds, all_wfds;
+  EMACS_TIME tmo, *tmop = timeout;
+
+  GMainContext *context = g_main_context_default ();
+  int have_wfds = wfds != NULL;
+  int n_gfds = 0, our_tmo = 0, retval = 0, our_fds = 0;
+  int prio, i, nfds, tmo_in_millisec;
+
+  if (rfds) memcpy (&all_rfds, rfds, sizeof (all_rfds));
+  else FD_ZERO (&all_rfds);
+  if (wfds) memcpy (&all_wfds, wfds, sizeof (all_rfds));
+  else FD_ZERO (&all_wfds);
+
+  /* Update event sources in GLib. */
+  g_main_context_pending (context);
+
+  do {
+    if (n_gfds > gfds_size) 
+      {
+        while (n_gfds > gfds_size) 
+          gfds_size *= 2;
+        xfree (gfds);
+        gfds = xmalloc (sizeof (*gfds) * gfds_size);
+      }
+
+    n_gfds = g_main_context_query (context,
+                                   G_PRIORITY_LOW,
+                                   &tmo_in_millisec,
+                                   gfds,
+                                   gfds_size);
+  } while (n_gfds > gfds_size);
+
+  for (i = 0; i < n_gfds; ++i) 
+    {
+      if (gfds[i].events & G_IO_IN)
+        {
+          FD_SET (gfds[i].fd, &all_rfds);
+          if (gfds[i].fd > max_fds) max_fds = gfds[i].fd;
+        }
+      if (gfds[i].events & G_IO_OUT)
+        {
+          FD_SET (gfds[i].fd, &all_wfds);
+          if (gfds[i].fd > max_fds) max_fds = gfds[i].fd;
+          have_wfds = 1;
+        }
+    }
+
+  if (tmo_in_millisec >= 0)
+    {
+      EMACS_SET_SECS_USECS (tmo, tmo_in_millisec/1000,
+                            1000 * (tmo_in_millisec % 1000));
+      if (!timeout) our_tmo = 1;
+      else
+        {
+          EMACS_TIME difference;
+          
+          EMACS_SUB_TIME (difference, tmo, *timeout);
+          if (EMACS_TIME_NEG_P (difference)) our_tmo = 1;
+        }
+
+      if (our_tmo) tmop = &tmo;
+    }
+
+  nfds = select (max_fds+1, &all_rfds, have_wfds ? &all_wfds : NULL,
+                 efds, tmop);
+
+  if (nfds < 0)
+    retval = nfds;
+  else if (nfds > 0) 
+    {
+      for (i = 0; i < max_fds+1; ++i)
+        {
+          if (FD_ISSET (i, &all_rfds))
+            {
+              if (rfds && FD_ISSET (i, rfds)) ++retval;
+              else ++our_fds;
+            }
+          if (have_wfds && FD_ISSET (i, &all_wfds))
+            {
+              if (wfds && FD_ISSET (i, wfds)) ++retval;
+              else ++our_fds;
+            }
+          if (efds && FD_ISSET (i, efds))
+            ++retval;
+        }
+    }
+
+  if (our_fds > 0 || (nfds == 0 && our_tmo))
+    {
+      
+      /* If Gtk+ is in use eventually gtk_main_iteration will be called,
+         unless retval is zero.  */
+#ifdef USE_GTK
+      if (retval == 0)
+#endif
+        while (g_main_context_pending (context))
+          g_main_context_dispatch (context);
+
+      /* To not have to recalculate timeout, return like this.  */
+      if (retval == 0) 
+        {
+          retval = -1;
+          errno = EINTR;
+        }
+    }
+
+  return retval;
+}
+#endif /* defined (USE_GTK) || defined (HAVE_GCONF) */
+
+void
+xgselect_initialize ()
+{
+#if defined (USE_GTK) || defined (HAVE_GCONF)
+  gfds_size = 128;
+  gfds = xmalloc (sizeof (*gfds)*gfds_size);
+#endif /* defined (USE_GTK) || defined (HAVE_GCONF) */
+}
+
diff --git a/src/xgselect.h b/src/xgselect.h
new file mode 100644 (file)
index 0000000..537f347
--- /dev/null
@@ -0,0 +1,35 @@
+/* Header for xg_select.
+   Copyright (C) 2009
+     Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs 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 3 of the License, or
+(at your option) any later version.
+
+GNU Emacs 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef XGSELECT_H
+#define XGSELECT_H
+
+#include "lisp.h"
+#include "systime.h"
+#include "sysselect.h"
+
+extern int xg_select P_ ((int max_fds,
+                          SELECT_TYPE *rfds,
+                          SELECT_TYPE *wfds,
+                          SELECT_TYPE *efds,
+                          EMACS_TIME *timeout));
+
+extern void xgselect_initialize P_ ((void));
+
+#endif /* XGSELECT_H */
index 8ce247432603411a027e132980318d7122fe9ba9..0dabc060b9a1c4252b81ee206d950c0735e6e85f 100644 (file)
@@ -82,7 +82,7 @@ something_changedCB (client, cnxn_id, entry, user_data)
       const char *value = gconf_value_get_string (v);
       int i;
       if (current_mono_font != NULL && strcmp (value, current_mono_font) == 0)
-        return; // No change.
+        return; /* No change. */
 
       xfree (current_mono_font);
       current_mono_font = xstrdup (value);
@@ -501,24 +501,6 @@ init_gconf ()
 #if defined (HAVE_GCONF) && defined (HAVE_XFT)
   int i;
   char *s;
-  /* Should be enough, this is called at startup */
-#define N_FDS 1024
-  int fd_before[N_FDS], fd_before1[N_FDS];
-  int dummy, n_fds;
-  GPollFD gfds[N_FDS];
-
-  /* To find out which filedecriptors GConf uses, check before and after.
-     If we do not do this, GConf changes will only happen when Emacs gets
-     an X event.  */
-  memset (fd_before, 0, sizeof (fd_before));
-  n_fds = g_main_context_query (g_main_context_default (),
-                                G_PRIORITY_LOW,
-                                &dummy,
-                                gfds,
-                                N_FDS);
-  for (i = 0; i < n_fds; ++i)
-    if (gfds[i].fd < N_FDS && gfds[i].fd > 0 && gfds[i].events > 0)
-      fd_before[gfds[i].fd] = 1;
 
   g_type_init ();
   gconf_client = gconf_client_get_default ();
@@ -537,25 +519,6 @@ init_gconf ()
                            SYSTEM_MONO_FONT,
                            something_changedCB,
                            NULL, NULL, NULL);
-  n_fds = g_main_context_query (g_main_context_default (),
-                                G_PRIORITY_LOW,
-                                &dummy,
-                                gfds,
-                                N_FDS);
-
-  for (i = 0; i < n_fds; ++i)
-    if (gfds[i].fd < N_FDS && gfds[i].fd > 0 && gfds[i].events > 0
-        && !fd_before[gfds[i].fd])
-      {
-#ifdef F_SETOWN
-        fcntl (i, F_SETOWN, getpid ());
-#endif /* ! defined (F_SETOWN) */
-
-#ifdef SIGIO
-        if (interrupt_input)
-          init_sigio (i);
-#endif /* ! defined (SIGIO) */
-      }
 #endif /* HAVE_GCONF && HAVE_XFT */
 }
 
index f18b8105c025590294367acd48e36f84b44a3bf5..aefa9d7217b5e202b30059de61fc07723f2335df 100644 (file)
@@ -87,6 +87,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "font.h"
 #include "fontset.h"
 #include "xsettings.h"
+#include "xgselect.h"
 #include "sysselect.h"
 
 #ifdef USE_X_TOOLKIT
@@ -10850,6 +10851,8 @@ x_initialize ()
   XSetIOErrorHandler (x_io_error_quitter);
 
   signal (SIGPIPE, x_connection_signal);
+
+  xgselect_initialize ();
 }