Commit e90292a9 authored by Jan Djärv's avatar Jan Djärv

Bug #4574. Common code for file/font dialog. Handle timers with glib-timers.

* keyboard.h: Declare timer_check.

* keyboard.c (timer_check_2): New function that does what the old
timer_check did.
(timer_check): Call timer_check_2 until -1 or a non-zero time is
returned, i.e. don't return -1 with timers pending.

* process.c: Remove extern declaration of timer_check.

* xmenu.c (x_menu_wait_for_event): Remove code that did a timeout
even if timer_check returned -1.

* gtkutil.c (xg_dialog_response_cb): data is now a struct xg_dialog_data
(pop_down_dialog): Destroy widget (if any), cancel timer and unref
the event loop.
(xg_maybe_add_timer, xg_dialog_run): New functions (bug #4574).
(xg_get_file_name, xg_get_font_name): Call xg_dialog_run (bug #4574).
Destroy the dialog after xg_dialog_run.
parent 045b83c0
2009-11-10 Jan Djärv <jan.h.d@swipnet.se>
* keyboard.h: Declare timer_check.
* keyboard.c (timer_check_2): New function that does what the old
timer_check did.
(timer_check): Call timer_check_2 until -1 or a non-zero time is
returned, i.e. don't return -1 with timers pending.
* process.c: Remove extern declaration of timer_check.
* xmenu.c (x_menu_wait_for_event): Remove code that did a timeout
even if timer_check returned -1.
* gtkutil.c (xg_dialog_response_cb): data is now a struct xg_dialog_data
(pop_down_dialog): Destroy widget (if any), cancel timer and unref
the event loop.
(xg_maybe_add_timer, xg_dialog_run): New functions (bug #4574).
(xg_get_file_name, xg_get_font_name): Call xg_dialog_run (bug #4574).
Destroy the dialog after xg_dialog_run.
2009-11-10 Stefan Monnier <monnier@iro.umontreal.ca>
* menu.c (Fx_popup_menu) [HAVE_NS]: Remove unused vars.
......
......@@ -1224,46 +1224,29 @@ create_dialog (wv, select_cb, deactivate_cb)
return wdialog;
}
/***********************************************************************
File dialog functions
***********************************************************************/
/* Return non-zero if the old file selection dialog is being used.
Return zero if not. */
int
xg_uses_old_file_dialog ()
struct xg_dialog_data
{
#ifdef HAVE_GTK_FILE_BOTH
extern int x_gtk_use_old_file_dialog;
return x_gtk_use_old_file_dialog;
#else /* ! HAVE_GTK_FILE_BOTH */
#ifdef HAVE_GTK_FILE_SELECTION_NEW
return 1;
#else
return 0;
#endif
#endif /* ! HAVE_GTK_FILE_BOTH */
}
GMainLoop *loop;
int response;
GtkWidget *w;
guint timerid;
};
/* Function that is called when the file or font dialogs pop down.
W is the dialog widget, RESPONSE is the response code.
USER_DATA is what we passed in to g_signal_connect (pointer to int). */
USER_DATA is what we passed in to g_signal_connect. */
static void
xg_dialog_response_cb (w,
response,
user_data)
response,
user_data)
GtkDialog *w;
gint response;
gpointer user_data;
{
int *ptr = (int *) user_data;
*ptr = response;
struct xg_dialog_data *dd = (struct xg_dialog_data *)user_data;
dd->response = response;
g_main_loop_quit (dd->loop);
}
......@@ -1274,12 +1257,112 @@ pop_down_dialog (arg)
Lisp_Object arg;
{
struct Lisp_Save_Value *p = XSAVE_VALUE (arg);
struct xg_dialog_data *dd = (struct xg_dialog_data *) p->pointer;
BLOCK_INPUT;
gtk_widget_destroy (GTK_WIDGET (p->pointer));
if (dd->w) gtk_widget_destroy (dd->w);
if (dd->timerid != 0) g_source_remove (dd->timerid);
g_main_loop_quit (dd->loop);
g_main_loop_unref (dd->loop);
UNBLOCK_INPUT;
return Qnil;
}
/* If there are any emacs timers pending, add a timeout to main loop in DATA.
We pass in DATA as gpointer* so we can use this as a callback. */
static gboolean
xg_maybe_add_timer (data)
gpointer data;
{
struct xg_dialog_data *dd = (struct xg_dialog_data *) data;
EMACS_TIME next_time = timer_check (1);
long secs = EMACS_SECS (next_time);
long usecs = EMACS_USECS (next_time);
dd->timerid = 0;
if (secs >= 0 && usecs >= 0 && secs < ((guint)-1)/1000)
{
dd->timerid = g_timeout_add (secs * 1000 + usecs/1000,
xg_maybe_add_timer,
dd);
}
return FALSE;
}
/* Pops up a modal dialog W and waits for response.
We don't use gtk_dialog_run because we want to process emacs timers.
The dialog W is not destroyed when this function returns. */
static int
xg_dialog_run (f, w)
FRAME_PTR f;
GtkWidget *w;
{
int count = SPECPDL_INDEX ();
struct xg_dialog_data dd;
xg_set_screen (w, f);
gtk_window_set_transient_for (GTK_WINDOW (w),
GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)));
gtk_window_set_destroy_with_parent (GTK_WINDOW (w), TRUE);
gtk_window_set_modal (GTK_WINDOW (w), TRUE);
dd.loop = g_main_loop_new (NULL, FALSE);
dd.response = GTK_RESPONSE_CANCEL;
dd.w = w;
dd.timerid = 0;
g_signal_connect (G_OBJECT (w),
"response",
G_CALLBACK (xg_dialog_response_cb),
&dd);
/* Don't destroy the widget if closed by the window manager close button. */
g_signal_connect (G_OBJECT (w), "delete-event", G_CALLBACK (gtk_true), NULL);
gtk_widget_show (w);
record_unwind_protect (pop_down_dialog, make_save_value (&dd, 0));
(void) xg_maybe_add_timer (&dd);
g_main_loop_run (dd.loop);
dd.w = 0;
unbind_to (count, Qnil);
return dd.response;
}
/***********************************************************************
File dialog functions
***********************************************************************/
/* Return non-zero if the old file selection dialog is being used.
Return zero if not. */
int
xg_uses_old_file_dialog ()
{
#ifdef HAVE_GTK_FILE_BOTH
extern int x_gtk_use_old_file_dialog;
return x_gtk_use_old_file_dialog;
#else /* ! HAVE_GTK_FILE_BOTH */
#ifdef HAVE_GTK_FILE_SELECTION_NEW
return 1;
#else
return 0;
#endif
#endif /* ! HAVE_GTK_FILE_BOTH */
}
typedef char * (*xg_get_file_func) P_ ((GtkWidget *));
#ifdef HAVE_GTK_FILE_CHOOSER_DIALOG_NEW
......@@ -1537,7 +1620,6 @@ xg_get_file_name (f, prompt, default_filename, mustmatch_p, only_dir_p)
int mustmatch_p, only_dir_p;
{
GtkWidget *w = 0;
int count = SPECPDL_INDEX ();
char *fn = 0;
int filesel_done = 0;
xg_get_file_func func;
......@@ -1571,29 +1653,9 @@ xg_get_file_name (f, prompt, default_filename, mustmatch_p, only_dir_p)
#endif /* HAVE_GTK_FILE_BOTH */
xg_set_screen (w, f);
gtk_widget_set_name (w, "emacs-filedialog");
gtk_window_set_transient_for (GTK_WINDOW (w),
GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)));
gtk_window_set_destroy_with_parent (GTK_WINDOW (w), TRUE);
gtk_window_set_modal (GTK_WINDOW (w), TRUE);
g_signal_connect (G_OBJECT (w),
"response",
G_CALLBACK (xg_dialog_response_cb),
&filesel_done);
/* Don't destroy the widget if closed by the window manager close button. */
g_signal_connect (G_OBJECT (w), "delete-event", G_CALLBACK (gtk_true), NULL);
gtk_widget_show (w);
record_unwind_protect (pop_down_dialog, make_save_value (w, 0));
while (! filesel_done)
{
x_menu_wait_for_event (0);
gtk_main_iteration ();
}
filesel_done = xg_dialog_run (f, w);
#if defined (HAVE_GTK_AND_PTHREAD) && defined (__SIGRTMIN)
sigunblock (sigmask (__SIGRTMIN));
......@@ -1602,8 +1664,7 @@ xg_get_file_name (f, prompt, default_filename, mustmatch_p, only_dir_p)
if (filesel_done == GTK_RESPONSE_OK)
fn = (*func) (w);
unbind_to (count, Qnil);
gtk_widget_destroy (w);
return fn;
}
......@@ -1622,8 +1683,7 @@ xg_get_font_name (f, default_name)
FRAME_PTR f;
char *default_name;
{
GtkWidget *w = 0;
int count = SPECPDL_INDEX ();
GtkWidget *w;
char *fontname = NULL;
int done = 0;
......@@ -1637,27 +1697,9 @@ xg_get_font_name (f, default_name)
gtk_font_selection_dialog_set_font_name (GTK_FONT_SELECTION_DIALOG (w),
default_name);
xg_set_screen (w, f);
gtk_widget_set_name (w, "emacs-fontdialog");
gtk_window_set_transient_for (GTK_WINDOW (w),
GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)));
gtk_window_set_destroy_with_parent (GTK_WINDOW (w), TRUE);
gtk_window_set_modal (GTK_WINDOW (w), TRUE);
g_signal_connect (G_OBJECT (w), "response",
G_CALLBACK (xg_dialog_response_cb), &done);
/* Don't destroy the widget if closed by the window manager close button. */
g_signal_connect (G_OBJECT (w), "delete-event", G_CALLBACK (gtk_true), NULL);
gtk_widget_show (w);
record_unwind_protect (pop_down_dialog, make_save_value (w, 0));
while (!done)
{
x_menu_wait_for_event (0);
gtk_main_iteration ();
}
done = xg_dialog_run (f, w);
#if defined (HAVE_GTK_AND_PTHREAD) && defined (__SIGRTMIN)
sigunblock (sigmask (__SIGRTMIN));
......@@ -1665,10 +1707,9 @@ xg_get_font_name (f, default_name)
if (done == GTK_RESPONSE_OK)
fontname = gtk_font_selection_dialog_get_font_name
((GtkFontSelectionDialog *) w);
unbind_to (count, Qnil);
(GTK_FONT_SELECTION_DIALOG (w));
gtk_widget_destroy (w);
return fontname;
}
#endif /* HAVE_FREETYPE */
......
......@@ -4509,19 +4509,16 @@ extern Lisp_Object Qapply;
disregard elements that are not proper timers. Do not make a circular
timer list for the time being.
Returns the number of seconds to wait until the next timer fires. If a
timer is triggering now, return zero seconds.
If no timer is active, return -1 seconds.
Returns the time to wait until the next timer fires. If a
timer is triggering now, return zero.
If no timer is active, return -1.
If a timer is ripe, we run it, with quitting turned off.
In that case we return 0 to indicate that a new timer_check_2 call
should be done. */
DO_IT_NOW is now ignored. It used to mean that we should
run the timer directly instead of queueing a timer-event.
Now we always run timers directly. */
EMACS_TIME
timer_check (do_it_now)
int do_it_now;
static EMACS_TIME
timer_check_2 ()
{
EMACS_TIME nexttime;
EMACS_TIME now, idleness_now;
......@@ -4685,7 +4682,12 @@ timer_check (do_it_now)
/* Since we have handled the event,
we don't need to tell the caller to wake up and do it. */
/* But the caller must still wait for the next timer, so
return 0 to indicate that. */
}
EMACS_SET_SECS (nexttime, 0);
EMACS_SET_USECS (nexttime, 0);
}
else
/* When we encounter a timer that is still waiting,
......@@ -4702,6 +4704,35 @@ timer_check (do_it_now)
return nexttime;
}
/* Check whether a timer has fired. To prevent larger problems we simply
disregard elements that are not proper timers. Do not make a circular
timer list for the time being.
Returns the time to wait until the next timer fires.
If no timer is active, return -1.
As long as any timer is ripe, we run it.
DO_IT_NOW is now ignored. It used to mean that we should
run the timer directly instead of queueing a timer-event.
Now we always run timers directly. */
EMACS_TIME
timer_check (do_it_now)
int do_it_now;
{
EMACS_TIME nexttime;
do
{
nexttime = timer_check_2 ();
}
while (EMACS_SECS (nexttime) == 0 && EMACS_USECS (nexttime) == 0);
return nexttime;
}
DEFUN ("current-idle-time", Fcurrent_idle_time, Scurrent_idle_time, 0, 0, 0,
doc: /* Return the current length of Emacs idleness, or nil.
The value when Emacs is idle is a list of three integers. The first has
......
......@@ -488,6 +488,7 @@ extern void add_user_signal P_ ((int, const char *));
extern int tty_read_avail_input P_ ((struct terminal *, int,
struct input_event *));
extern EMACS_TIME timer_check P_ ((int));
/* arch-tag: 769cbade-1ba9-4950-b886-db265b061aa3
(do not change this comment) */
......@@ -296,7 +296,6 @@ static void create_pty P_ ((Lisp_Object));
static Lisp_Object get_process ();
static void exec_sentinel ();
extern EMACS_TIME timer_check ();
extern int timers_run;
/* Mask of bits indicating the descriptors that we wait for input on. */
......
......@@ -405,8 +405,6 @@ x_menu_set_in_use (in_use)
void
x_menu_wait_for_event (void *data)
{
extern EMACS_TIME timer_check P_ ((int));
/* Another way to do this is to register a timer callback, that can be
done in GTK and Xt. But we have to do it like this when using only X
anyway, and with callbacks we would have three variants for timer handling
......@@ -422,7 +420,7 @@ x_menu_wait_for_event (void *data)
#endif
)
{
EMACS_TIME next_time = timer_check (1);
EMACS_TIME next_time = timer_check (1), *ntp;
long secs = EMACS_SECS (next_time);
long usecs = EMACS_USECS (next_time);
SELECT_TYPE read_fds;
......@@ -437,15 +435,12 @@ x_menu_wait_for_event (void *data)
if (fd > n) n = fd;
}
if (secs < 0 || (secs == 0 && usecs == 0))
{
/* Sometimes timer_check returns -1 (no timers) even if there are
timers. So do a timeout anyway. */
EMACS_SET_SECS (next_time, 1);
EMACS_SET_USECS (next_time, 0);
}
if (secs < 0 && usecs < 0)
ntp = 0;
else
ntp = &next_time;
select (n + 1, &read_fds, (SELECT_TYPE *)0, (SELECT_TYPE *)0, &next_time);
select (n + 1, &read_fds, (SELECT_TYPE *)0, (SELECT_TYPE *)0, ntp);
}
}
#endif /* ! MSDOS */
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment