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