aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJan Djärv2009-11-10 19:06:40 +0000
committerJan Djärv2009-11-10 19:06:40 +0000
commite90292a90cdb9a3b4d28b21db39f5f44ad3de805 (patch)
tree2bf6f977a64392335dd3365c845b6d589bfc6726 /src
parent045b83c00aabaaaa5d4e363f848a1826f8f27338 (diff)
downloademacs-e90292a90cdb9a3b4d28b21db39f5f44ad3de805.tar.gz
emacs-e90292a90cdb9a3b4d28b21db39f5f44ad3de805.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog21
-rw-r--r--src/gtkutil.c197
-rw-r--r--src/keyboard.c51
-rw-r--r--src/keyboard.h1
-rw-r--r--src/process.c1
-rw-r--r--src/xmenu.c17
6 files changed, 188 insertions, 100 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index ae1a234679d..3b85404ba20 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,24 @@
12009-11-10 Jan Djärv <jan.h.d@swipnet.se>
2
3 * keyboard.h: Declare timer_check.
4
5 * keyboard.c (timer_check_2): New function that does what the old
6 timer_check did.
7 (timer_check): Call timer_check_2 until -1 or a non-zero time is
8 returned, i.e. don't return -1 with timers pending.
9
10 * process.c: Remove extern declaration of timer_check.
11
12 * xmenu.c (x_menu_wait_for_event): Remove code that did a timeout
13 even if timer_check returned -1.
14
15 * gtkutil.c (xg_dialog_response_cb): data is now a struct xg_dialog_data
16 (pop_down_dialog): Destroy widget (if any), cancel timer and unref
17 the event loop.
18 (xg_maybe_add_timer, xg_dialog_run): New functions (bug #4574).
19 (xg_get_file_name, xg_get_font_name): Call xg_dialog_run (bug #4574).
20 Destroy the dialog after xg_dialog_run.
21
12009-11-10 Stefan Monnier <monnier@iro.umontreal.ca> 222009-11-10 Stefan Monnier <monnier@iro.umontreal.ca>
2 23
3 * menu.c (Fx_popup_menu) [HAVE_NS]: Remove unused vars. 24 * menu.c (Fx_popup_menu) [HAVE_NS]: Remove unused vars.
diff --git a/src/gtkutil.c b/src/gtkutil.c
index 543b868448d..ba9d95e0325 100644
--- a/src/gtkutil.c
+++ b/src/gtkutil.c
@@ -1224,46 +1224,29 @@ create_dialog (wv, select_cb, deactivate_cb)
1224 return wdialog; 1224 return wdialog;
1225} 1225}
1226 1226
1227 1227struct xg_dialog_data
1228
1229/***********************************************************************
1230 File dialog functions
1231 ***********************************************************************/
1232/* Return non-zero if the old file selection dialog is being used.
1233 Return zero if not. */
1234
1235int
1236xg_uses_old_file_dialog ()
1237{ 1228{
1238#ifdef HAVE_GTK_FILE_BOTH 1229 GMainLoop *loop;
1239 extern int x_gtk_use_old_file_dialog; 1230 int response;
1240 return x_gtk_use_old_file_dialog; 1231 GtkWidget *w;
1241#else /* ! HAVE_GTK_FILE_BOTH */ 1232 guint timerid;
1242 1233};
1243#ifdef HAVE_GTK_FILE_SELECTION_NEW
1244 return 1;
1245#else
1246 return 0;
1247#endif
1248
1249#endif /* ! HAVE_GTK_FILE_BOTH */
1250}
1251
1252 1234
1253/* Function that is called when the file or font dialogs pop down. 1235/* Function that is called when the file or font dialogs pop down.
1254 W is the dialog widget, RESPONSE is the response code. 1236 W is the dialog widget, RESPONSE is the response code.
1255 USER_DATA is what we passed in to g_signal_connect (pointer to int). */ 1237 USER_DATA is what we passed in to g_signal_connect. */
1256 1238
1257static void 1239static void
1258xg_dialog_response_cb (w, 1240xg_dialog_response_cb (w,
1259 response, 1241 response,
1260 user_data) 1242 user_data)
1261 GtkDialog *w; 1243 GtkDialog *w;
1262 gint response; 1244 gint response;
1263 gpointer user_data; 1245 gpointer user_data;
1264{ 1246{
1265 int *ptr = (int *) user_data; 1247 struct xg_dialog_data *dd = (struct xg_dialog_data *)user_data;
1266 *ptr = response; 1248 dd->response = response;
1249 g_main_loop_quit (dd->loop);
1267} 1250}
1268 1251
1269 1252
@@ -1274,12 +1257,112 @@ pop_down_dialog (arg)
1274 Lisp_Object arg; 1257 Lisp_Object arg;
1275{ 1258{
1276 struct Lisp_Save_Value *p = XSAVE_VALUE (arg); 1259 struct Lisp_Save_Value *p = XSAVE_VALUE (arg);
1260 struct xg_dialog_data *dd = (struct xg_dialog_data *) p->pointer;
1261
1277 BLOCK_INPUT; 1262 BLOCK_INPUT;
1278 gtk_widget_destroy (GTK_WIDGET (p->pointer)); 1263 if (dd->w) gtk_widget_destroy (dd->w);
1264 if (dd->timerid != 0) g_source_remove (dd->timerid);
1265
1266 g_main_loop_quit (dd->loop);
1267 g_main_loop_unref (dd->loop);
1268
1279 UNBLOCK_INPUT; 1269 UNBLOCK_INPUT;
1270
1280 return Qnil; 1271 return Qnil;
1281} 1272}
1282 1273
1274/* If there are any emacs timers pending, add a timeout to main loop in DATA.
1275 We pass in DATA as gpointer* so we can use this as a callback. */
1276
1277static gboolean
1278xg_maybe_add_timer (data)
1279 gpointer data;
1280{
1281 struct xg_dialog_data *dd = (struct xg_dialog_data *) data;
1282 EMACS_TIME next_time = timer_check (1);
1283 long secs = EMACS_SECS (next_time);
1284 long usecs = EMACS_USECS (next_time);
1285
1286 dd->timerid = 0;
1287
1288 if (secs >= 0 && usecs >= 0 && secs < ((guint)-1)/1000)
1289 {
1290 dd->timerid = g_timeout_add (secs * 1000 + usecs/1000,
1291 xg_maybe_add_timer,
1292 dd);
1293 }
1294 return FALSE;
1295}
1296
1297
1298/* Pops up a modal dialog W and waits for response.
1299 We don't use gtk_dialog_run because we want to process emacs timers.
1300 The dialog W is not destroyed when this function returns. */
1301
1302static int
1303xg_dialog_run (f, w)
1304 FRAME_PTR f;
1305 GtkWidget *w;
1306
1307{
1308 int count = SPECPDL_INDEX ();
1309 struct xg_dialog_data dd;
1310
1311 xg_set_screen (w, f);
1312 gtk_window_set_transient_for (GTK_WINDOW (w),
1313 GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)));
1314 gtk_window_set_destroy_with_parent (GTK_WINDOW (w), TRUE);
1315 gtk_window_set_modal (GTK_WINDOW (w), TRUE);
1316
1317 dd.loop = g_main_loop_new (NULL, FALSE);
1318 dd.response = GTK_RESPONSE_CANCEL;
1319 dd.w = w;
1320 dd.timerid = 0;
1321
1322 g_signal_connect (G_OBJECT (w),
1323 "response",
1324 G_CALLBACK (xg_dialog_response_cb),
1325 &dd);
1326 /* Don't destroy the widget if closed by the window manager close button. */
1327 g_signal_connect (G_OBJECT (w), "delete-event", G_CALLBACK (gtk_true), NULL);
1328 gtk_widget_show (w);
1329
1330 record_unwind_protect (pop_down_dialog, make_save_value (&dd, 0));
1331
1332 (void) xg_maybe_add_timer (&dd);
1333 g_main_loop_run (dd.loop);
1334
1335 dd.w = 0;
1336 unbind_to (count, Qnil);
1337
1338 return dd.response;
1339}
1340
1341
1342/***********************************************************************
1343 File dialog functions
1344 ***********************************************************************/
1345/* Return non-zero if the old file selection dialog is being used.
1346 Return zero if not. */
1347
1348int
1349xg_uses_old_file_dialog ()
1350{
1351#ifdef HAVE_GTK_FILE_BOTH
1352 extern int x_gtk_use_old_file_dialog;
1353 return x_gtk_use_old_file_dialog;
1354#else /* ! HAVE_GTK_FILE_BOTH */
1355
1356#ifdef HAVE_GTK_FILE_SELECTION_NEW
1357 return 1;
1358#else
1359 return 0;
1360#endif
1361
1362#endif /* ! HAVE_GTK_FILE_BOTH */
1363}
1364
1365
1283typedef char * (*xg_get_file_func) P_ ((GtkWidget *)); 1366typedef char * (*xg_get_file_func) P_ ((GtkWidget *));
1284 1367
1285#ifdef HAVE_GTK_FILE_CHOOSER_DIALOG_NEW 1368#ifdef HAVE_GTK_FILE_CHOOSER_DIALOG_NEW
@@ -1537,7 +1620,6 @@ xg_get_file_name (f, prompt, default_filename, mustmatch_p, only_dir_p)
1537 int mustmatch_p, only_dir_p; 1620 int mustmatch_p, only_dir_p;
1538{ 1621{
1539 GtkWidget *w = 0; 1622 GtkWidget *w = 0;
1540 int count = SPECPDL_INDEX ();
1541 char *fn = 0; 1623 char *fn = 0;
1542 int filesel_done = 0; 1624 int filesel_done = 0;
1543 xg_get_file_func func; 1625 xg_get_file_func func;
@@ -1571,29 +1653,9 @@ xg_get_file_name (f, prompt, default_filename, mustmatch_p, only_dir_p)
1571 1653
1572#endif /* HAVE_GTK_FILE_BOTH */ 1654#endif /* HAVE_GTK_FILE_BOTH */
1573 1655
1574 xg_set_screen (w, f);
1575 gtk_widget_set_name (w, "emacs-filedialog"); 1656 gtk_widget_set_name (w, "emacs-filedialog");
1576 gtk_window_set_transient_for (GTK_WINDOW (w),
1577 GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)));
1578 gtk_window_set_destroy_with_parent (GTK_WINDOW (w), TRUE);
1579 gtk_window_set_modal (GTK_WINDOW (w), TRUE);
1580
1581 g_signal_connect (G_OBJECT (w),
1582 "response",
1583 G_CALLBACK (xg_dialog_response_cb),
1584 &filesel_done);
1585
1586 /* Don't destroy the widget if closed by the window manager close button. */
1587 g_signal_connect (G_OBJECT (w), "delete-event", G_CALLBACK (gtk_true), NULL);
1588 1657
1589 gtk_widget_show (w); 1658 filesel_done = xg_dialog_run (f, w);
1590
1591 record_unwind_protect (pop_down_dialog, make_save_value (w, 0));
1592 while (! filesel_done)
1593 {
1594 x_menu_wait_for_event (0);
1595 gtk_main_iteration ();
1596 }
1597 1659
1598#if defined (HAVE_GTK_AND_PTHREAD) && defined (__SIGRTMIN) 1660#if defined (HAVE_GTK_AND_PTHREAD) && defined (__SIGRTMIN)
1599 sigunblock (sigmask (__SIGRTMIN)); 1661 sigunblock (sigmask (__SIGRTMIN));
@@ -1602,8 +1664,7 @@ xg_get_file_name (f, prompt, default_filename, mustmatch_p, only_dir_p)
1602 if (filesel_done == GTK_RESPONSE_OK) 1664 if (filesel_done == GTK_RESPONSE_OK)
1603 fn = (*func) (w); 1665 fn = (*func) (w);
1604 1666
1605 unbind_to (count, Qnil); 1667 gtk_widget_destroy (w);
1606
1607 return fn; 1668 return fn;
1608} 1669}
1609 1670
@@ -1622,8 +1683,7 @@ xg_get_font_name (f, default_name)
1622 FRAME_PTR f; 1683 FRAME_PTR f;
1623 char *default_name; 1684 char *default_name;
1624{ 1685{
1625 GtkWidget *w = 0; 1686 GtkWidget *w;
1626 int count = SPECPDL_INDEX ();
1627 char *fontname = NULL; 1687 char *fontname = NULL;
1628 int done = 0; 1688 int done = 0;
1629 1689
@@ -1637,27 +1697,9 @@ xg_get_font_name (f, default_name)
1637 gtk_font_selection_dialog_set_font_name (GTK_FONT_SELECTION_DIALOG (w), 1697 gtk_font_selection_dialog_set_font_name (GTK_FONT_SELECTION_DIALOG (w),
1638 default_name); 1698 default_name);
1639 1699
1640 xg_set_screen (w, f);
1641 gtk_widget_set_name (w, "emacs-fontdialog"); 1700 gtk_widget_set_name (w, "emacs-fontdialog");
1642 gtk_window_set_transient_for (GTK_WINDOW (w),
1643 GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)));
1644 gtk_window_set_destroy_with_parent (GTK_WINDOW (w), TRUE);
1645 gtk_window_set_modal (GTK_WINDOW (w), TRUE);
1646
1647 g_signal_connect (G_OBJECT (w), "response",
1648 G_CALLBACK (xg_dialog_response_cb), &done);
1649
1650 /* Don't destroy the widget if closed by the window manager close button. */
1651 g_signal_connect (G_OBJECT (w), "delete-event", G_CALLBACK (gtk_true), NULL);
1652
1653 gtk_widget_show (w);
1654 1701
1655 record_unwind_protect (pop_down_dialog, make_save_value (w, 0)); 1702 done = xg_dialog_run (f, w);
1656 while (!done)
1657 {
1658 x_menu_wait_for_event (0);
1659 gtk_main_iteration ();
1660 }
1661 1703
1662#if defined (HAVE_GTK_AND_PTHREAD) && defined (__SIGRTMIN) 1704#if defined (HAVE_GTK_AND_PTHREAD) && defined (__SIGRTMIN)
1663 sigunblock (sigmask (__SIGRTMIN)); 1705 sigunblock (sigmask (__SIGRTMIN));
@@ -1665,10 +1707,9 @@ xg_get_font_name (f, default_name)
1665 1707
1666 if (done == GTK_RESPONSE_OK) 1708 if (done == GTK_RESPONSE_OK)
1667 fontname = gtk_font_selection_dialog_get_font_name 1709 fontname = gtk_font_selection_dialog_get_font_name
1668 ((GtkFontSelectionDialog *) w); 1710 (GTK_FONT_SELECTION_DIALOG (w));
1669
1670 unbind_to (count, Qnil);
1671 1711
1712 gtk_widget_destroy (w);
1672 return fontname; 1713 return fontname;
1673} 1714}
1674#endif /* HAVE_FREETYPE */ 1715#endif /* HAVE_FREETYPE */
diff --git a/src/keyboard.c b/src/keyboard.c
index 4157d1ebfb3..872bd81ed40 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -4509,19 +4509,16 @@ extern Lisp_Object Qapply;
4509 disregard elements that are not proper timers. Do not make a circular 4509 disregard elements that are not proper timers. Do not make a circular
4510 timer list for the time being. 4510 timer list for the time being.
4511 4511
4512 Returns the number of seconds to wait until the next timer fires. If a 4512 Returns the time to wait until the next timer fires. If a
4513 timer is triggering now, return zero seconds. 4513 timer is triggering now, return zero.
4514 If no timer is active, return -1 seconds. 4514 If no timer is active, return -1.
4515 4515
4516 If a timer is ripe, we run it, with quitting turned off. 4516 If a timer is ripe, we run it, with quitting turned off.
4517 In that case we return 0 to indicate that a new timer_check_2 call
4518 should be done. */
4517 4519
4518 DO_IT_NOW is now ignored. It used to mean that we should 4520static EMACS_TIME
4519 run the timer directly instead of queueing a timer-event. 4521timer_check_2 ()
4520 Now we always run timers directly. */
4521
4522EMACS_TIME
4523timer_check (do_it_now)
4524 int do_it_now;
4525{ 4522{
4526 EMACS_TIME nexttime; 4523 EMACS_TIME nexttime;
4527 EMACS_TIME now, idleness_now; 4524 EMACS_TIME now, idleness_now;
@@ -4685,7 +4682,12 @@ timer_check (do_it_now)
4685 4682
4686 /* Since we have handled the event, 4683 /* Since we have handled the event,
4687 we don't need to tell the caller to wake up and do it. */ 4684 we don't need to tell the caller to wake up and do it. */
4685 /* But the caller must still wait for the next timer, so
4686 return 0 to indicate that. */
4688 } 4687 }
4688
4689 EMACS_SET_SECS (nexttime, 0);
4690 EMACS_SET_USECS (nexttime, 0);
4689 } 4691 }
4690 else 4692 else
4691 /* When we encounter a timer that is still waiting, 4693 /* When we encounter a timer that is still waiting,
@@ -4702,6 +4704,35 @@ timer_check (do_it_now)
4702 return nexttime; 4704 return nexttime;
4703} 4705}
4704 4706
4707
4708/* Check whether a timer has fired. To prevent larger problems we simply
4709 disregard elements that are not proper timers. Do not make a circular
4710 timer list for the time being.
4711
4712 Returns the time to wait until the next timer fires.
4713 If no timer is active, return -1.
4714
4715 As long as any timer is ripe, we run it.
4716
4717 DO_IT_NOW is now ignored. It used to mean that we should
4718 run the timer directly instead of queueing a timer-event.
4719 Now we always run timers directly. */
4720
4721EMACS_TIME
4722timer_check (do_it_now)
4723 int do_it_now;
4724{
4725 EMACS_TIME nexttime;
4726
4727 do
4728 {
4729 nexttime = timer_check_2 ();
4730 }
4731 while (EMACS_SECS (nexttime) == 0 && EMACS_USECS (nexttime) == 0);
4732
4733 return nexttime;
4734}
4735
4705DEFUN ("current-idle-time", Fcurrent_idle_time, Scurrent_idle_time, 0, 0, 0, 4736DEFUN ("current-idle-time", Fcurrent_idle_time, Scurrent_idle_time, 0, 0, 0,
4706 doc: /* Return the current length of Emacs idleness, or nil. 4737 doc: /* Return the current length of Emacs idleness, or nil.
4707The value when Emacs is idle is a list of three integers. The first has 4738The value when Emacs is idle is a list of three integers. The first has
diff --git a/src/keyboard.h b/src/keyboard.h
index 5b32595fa63..b23cc13c64d 100644
--- a/src/keyboard.h
+++ b/src/keyboard.h
@@ -488,6 +488,7 @@ extern void add_user_signal P_ ((int, const char *));
488 488
489extern int tty_read_avail_input P_ ((struct terminal *, int, 489extern int tty_read_avail_input P_ ((struct terminal *, int,
490 struct input_event *)); 490 struct input_event *));
491extern EMACS_TIME timer_check P_ ((int));
491 492
492/* arch-tag: 769cbade-1ba9-4950-b886-db265b061aa3 493/* arch-tag: 769cbade-1ba9-4950-b886-db265b061aa3
493 (do not change this comment) */ 494 (do not change this comment) */
diff --git a/src/process.c b/src/process.c
index 08495d2d8bd..fd94731a413 100644
--- a/src/process.c
+++ b/src/process.c
@@ -296,7 +296,6 @@ static void create_pty P_ ((Lisp_Object));
296static Lisp_Object get_process (); 296static Lisp_Object get_process ();
297static void exec_sentinel (); 297static void exec_sentinel ();
298 298
299extern EMACS_TIME timer_check ();
300extern int timers_run; 299extern int timers_run;
301 300
302/* Mask of bits indicating the descriptors that we wait for input on. */ 301/* Mask of bits indicating the descriptors that we wait for input on. */
diff --git a/src/xmenu.c b/src/xmenu.c
index 15e609199b5..172be93a58c 100644
--- a/src/xmenu.c
+++ b/src/xmenu.c
@@ -405,8 +405,6 @@ x_menu_set_in_use (in_use)
405void 405void
406x_menu_wait_for_event (void *data) 406x_menu_wait_for_event (void *data)
407{ 407{
408 extern EMACS_TIME timer_check P_ ((int));
409
410 /* Another way to do this is to register a timer callback, that can be 408 /* Another way to do this is to register a timer callback, that can be
411 done in GTK and Xt. But we have to do it like this when using only X 409 done in GTK and Xt. But we have to do it like this when using only X
412 anyway, and with callbacks we would have three variants for timer handling 410 anyway, and with callbacks we would have three variants for timer handling
@@ -422,7 +420,7 @@ x_menu_wait_for_event (void *data)
422#endif 420#endif
423 ) 421 )
424 { 422 {
425 EMACS_TIME next_time = timer_check (1); 423 EMACS_TIME next_time = timer_check (1), *ntp;
426 long secs = EMACS_SECS (next_time); 424 long secs = EMACS_SECS (next_time);
427 long usecs = EMACS_USECS (next_time); 425 long usecs = EMACS_USECS (next_time);
428 SELECT_TYPE read_fds; 426 SELECT_TYPE read_fds;
@@ -437,15 +435,12 @@ x_menu_wait_for_event (void *data)
437 if (fd > n) n = fd; 435 if (fd > n) n = fd;
438 } 436 }
439 437
440 if (secs < 0 || (secs == 0 && usecs == 0)) 438 if (secs < 0 && usecs < 0)
441 { 439 ntp = 0;
442 /* Sometimes timer_check returns -1 (no timers) even if there are 440 else
443 timers. So do a timeout anyway. */ 441 ntp = &next_time;
444 EMACS_SET_SECS (next_time, 1);
445 EMACS_SET_USECS (next_time, 0);
446 }
447 442
448 select (n + 1, &read_fds, (SELECT_TYPE *)0, (SELECT_TYPE *)0, &next_time); 443 select (n + 1, &read_fds, (SELECT_TYPE *)0, (SELECT_TYPE *)0, ntp);
449 } 444 }
450} 445}
451#endif /* ! MSDOS */ 446#endif /* ! MSDOS */