aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Djärv <[email protected]>2009-11-21 15:28:59 +0000
committerJan Djärv <[email protected]>2009-11-21 15:28:59 +0000
commit872870b29a846cc8e27d53d05147eb3e0beb7c50 (patch)
tree5bf7121650264015843c2111e98a0d26ededc358
parent62a6e103dd7b9d940565639d6a47c8bdee3f24ce (diff)
Use a select wrapper around the GLib event loop, thus taking into account GLib
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.
-rw-r--r--src/ChangeLog28
-rw-r--r--src/Makefile.in2
-rw-r--r--src/gtkutil.c131
-rw-r--r--src/process.c8
-rw-r--r--src/xgselect.c157
-rw-r--r--src/xgselect.h35
-rw-r--r--src/xsettings.c39
-rw-r--r--src/xterm.c3
8 files changed, 236 insertions, 167 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index 7f6891e071..27c2b7246a 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,31 @@
+2009-11-21 Jan Djärv <[email protected]>
+
+ * 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 <[email protected]>
* character.h (STRING_CHAR, STRING_CHAR_AND_LENGTH): Remove
diff --git a/src/Makefile.in b/src/Makefile.in
index 3d81cc1f2b..aceecacb5c 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -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
diff --git a/src/gtkutil.c b/src/gtkutil.c
index 4a55e51b8b..b1e238af55 100644
--- a/src/gtkutil.c
+++ b/src/gtkutil.c
@@ -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
diff --git a/src/process.c b/src/process.c
index 5c6875520e..90f2a9aa6b 100644
--- a/src/process.c
+++ b/src/process.c
@@ -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
index 0000000000..3c5a99f8ed
--- /dev/null
+++ b/src/xgselect.c
@@ -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
index 0000000000..537f3471fb
--- /dev/null
+++ b/src/xgselect.h
@@ -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 */
diff --git a/src/xsettings.c b/src/xsettings.c
index 8ce2474326..0dabc060b9 100644
--- a/src/xsettings.c
+++ b/src/xsettings.c
@@ -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 */
}
diff --git a/src/xterm.c b/src/xterm.c
index f18b8105c0..aefa9d7217 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -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 ();
}