Mercurial > emacs
comparison src/gtkutil.c @ 105936:45191c90be7e
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.
author | Jan Djärv <jan.h.d@swipnet.se> |
---|---|
date | Tue, 10 Nov 2009 19:06:40 +0000 |
parents | 5910e0380daf |
children | ba3ffbd9c422 |
comparison
equal
deleted
inserted
replaced
105935:228c9c492970 | 105936:45191c90be7e |
---|---|
1222 } | 1222 } |
1223 | 1223 |
1224 return wdialog; | 1224 return wdialog; |
1225 } | 1225 } |
1226 | 1226 |
1227 struct xg_dialog_data | |
1228 { | |
1229 GMainLoop *loop; | |
1230 int response; | |
1231 GtkWidget *w; | |
1232 guint timerid; | |
1233 }; | |
1234 | |
1235 /* Function that is called when the file or font dialogs pop down. | |
1236 W is the dialog widget, RESPONSE is the response code. | |
1237 USER_DATA is what we passed in to g_signal_connect. */ | |
1238 | |
1239 static void | |
1240 xg_dialog_response_cb (w, | |
1241 response, | |
1242 user_data) | |
1243 GtkDialog *w; | |
1244 gint response; | |
1245 gpointer user_data; | |
1246 { | |
1247 struct xg_dialog_data *dd = (struct xg_dialog_data *)user_data; | |
1248 dd->response = response; | |
1249 g_main_loop_quit (dd->loop); | |
1250 } | |
1251 | |
1252 | |
1253 /* Destroy the dialog. This makes it pop down. */ | |
1254 | |
1255 static Lisp_Object | |
1256 pop_down_dialog (arg) | |
1257 Lisp_Object arg; | |
1258 { | |
1259 struct Lisp_Save_Value *p = XSAVE_VALUE (arg); | |
1260 struct xg_dialog_data *dd = (struct xg_dialog_data *) p->pointer; | |
1261 | |
1262 BLOCK_INPUT; | |
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 | |
1269 UNBLOCK_INPUT; | |
1270 | |
1271 return Qnil; | |
1272 } | |
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 | |
1277 static gboolean | |
1278 xg_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 | |
1302 static int | |
1303 xg_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 } | |
1227 | 1340 |
1228 | 1341 |
1229 /*********************************************************************** | 1342 /*********************************************************************** |
1230 File dialog functions | 1343 File dialog functions |
1231 ***********************************************************************/ | 1344 ***********************************************************************/ |
1247 #endif | 1360 #endif |
1248 | 1361 |
1249 #endif /* ! HAVE_GTK_FILE_BOTH */ | 1362 #endif /* ! HAVE_GTK_FILE_BOTH */ |
1250 } | 1363 } |
1251 | 1364 |
1252 | |
1253 /* Function that is called when the file or font dialogs pop down. | |
1254 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). */ | |
1256 | |
1257 static void | |
1258 xg_dialog_response_cb (w, | |
1259 response, | |
1260 user_data) | |
1261 GtkDialog *w; | |
1262 gint response; | |
1263 gpointer user_data; | |
1264 { | |
1265 int *ptr = (int *) user_data; | |
1266 *ptr = response; | |
1267 } | |
1268 | |
1269 | |
1270 /* Destroy the dialog. This makes it pop down. */ | |
1271 | |
1272 static Lisp_Object | |
1273 pop_down_dialog (arg) | |
1274 Lisp_Object arg; | |
1275 { | |
1276 struct Lisp_Save_Value *p = XSAVE_VALUE (arg); | |
1277 BLOCK_INPUT; | |
1278 gtk_widget_destroy (GTK_WIDGET (p->pointer)); | |
1279 UNBLOCK_INPUT; | |
1280 return Qnil; | |
1281 } | |
1282 | 1365 |
1283 typedef char * (*xg_get_file_func) P_ ((GtkWidget *)); | 1366 typedef 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 |
1286 | 1369 |
1535 char *prompt; | 1618 char *prompt; |
1536 char *default_filename; | 1619 char *default_filename; |
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; |
1544 | 1626 |
1545 #if defined (HAVE_GTK_AND_PTHREAD) && defined (__SIGRTMIN) | 1627 #if defined (HAVE_GTK_AND_PTHREAD) && defined (__SIGRTMIN) |
1569 mustmatch_p, only_dir_p, &func); | 1651 mustmatch_p, only_dir_p, &func); |
1570 #endif | 1652 #endif |
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), | 1657 |
1577 GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f))); | 1658 filesel_done = xg_dialog_run (f, w); |
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 | |
1589 gtk_widget_show (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)); |
1600 #endif | 1662 #endif |
1601 | 1663 |
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 |
1610 #ifdef HAVE_FREETYPE | 1671 #ifdef HAVE_FREETYPE |
1611 /* Pop up a GTK font selector and return the name of the font the user | 1672 /* Pop up a GTK font selector and return the name of the font the user |
1620 char * | 1681 char * |
1621 xg_get_font_name (f, default_name) | 1682 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 |
1630 #if defined (HAVE_GTK_AND_PTHREAD) && defined (__SIGRTMIN) | 1690 #if defined (HAVE_GTK_AND_PTHREAD) && defined (__SIGRTMIN) |
1631 sigblock (sigmask (__SIGRTMIN)); | 1691 sigblock (sigmask (__SIGRTMIN)); |
1635 if (!default_name) | 1695 if (!default_name) |
1636 default_name = "Monospace 10"; | 1696 default_name = "Monospace 10"; |
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), | 1701 |
1643 GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f))); | 1702 done = xg_dialog_run (f, w); |
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 | |
1655 record_unwind_protect (pop_down_dialog, make_save_value (w, 0)); | |
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)); |
1664 #endif | 1706 #endif |
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 | 1711 |
1670 unbind_to (count, Qnil); | 1712 gtk_widget_destroy (w); |
1671 | |
1672 return fontname; | 1713 return fontname; |
1673 } | 1714 } |
1674 #endif /* HAVE_FREETYPE */ | 1715 #endif /* HAVE_FREETYPE */ |
1675 | 1716 |
1676 | 1717 |