comparison src/gtkutil.c @ 106186:9b6f45dd8386

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.
author Jan Djärv <jan.h.d@swipnet.se>
date Sat, 21 Nov 2009 15:28:59 +0000
parents 0ea716305b13
children 471e6932ea09
comparison
equal deleted inserted replaced
106185:f2cea199b0c4 106186:9b6f45dd8386
27 #include "lisp.h" 27 #include "lisp.h"
28 #include "xterm.h" 28 #include "xterm.h"
29 #include "blockinput.h" 29 #include "blockinput.h"
30 #include "syssignal.h" 30 #include "syssignal.h"
31 #include "window.h" 31 #include "window.h"
32 #include "atimer.h"
33 #include "gtkutil.h" 32 #include "gtkutil.h"
34 #include "termhooks.h" 33 #include "termhooks.h"
35 #include "keyboard.h" 34 #include "keyboard.h"
36 #include "charset.h" 35 #include "charset.h"
37 #include "coding.h" 36 #include "coding.h"
179 178
180 179
181 /*********************************************************************** 180 /***********************************************************************
182 Utility functions 181 Utility functions
183 ***********************************************************************/ 182 ***********************************************************************/
184 /* The timer for scroll bar repetition and menu bar timeouts.
185 NULL if no timer is started. */
186 static struct atimer *xg_timer;
187
188
189 /* The next two variables and functions are taken from lwlib. */ 183 /* The next two variables and functions are taken from lwlib. */
190 static widget_value *widget_value_free_list; 184 static widget_value *widget_value_free_list;
191 static int malloc_cpt; 185 static int malloc_cpt;
192 186
193 /* Allocate a widget_value structure, either by taking one from the 187 /* Allocate a widget_value structure, either by taking one from the
422 on widgets in GTK. So we must set the cursor for all GDK windows. 416 on widgets in GTK. So we must set the cursor for all GDK windows.
423 Ditto for menus. */ 417 Ditto for menus. */
424 418
425 for ( ; children; children = g_list_next (children)) 419 for ( ; children; children = g_list_next (children))
426 gdk_window_set_cursor (GDK_WINDOW (children->data), cursor); 420 gdk_window_set_cursor (GDK_WINDOW (children->data), cursor);
427 }
428
429 /* Timer function called when a timeout occurs for xg_timer.
430 This function processes all GTK events in a recursive event loop.
431 This is done because GTK timer events are not seen by Emacs event
432 detection, Emacs only looks for X events. When a scroll bar has the
433 pointer (detected by button press/release events below) an Emacs
434 timer is started, and this function can then check if the GTK timer
435 has expired by calling the GTK event loop.
436 Also, when a menu is active, it has a small timeout before it
437 pops down the sub menu under it. */
438
439 static void
440 xg_process_timeouts (timer)
441 struct atimer *timer;
442 {
443 BLOCK_INPUT;
444 /* Ideally we would like to just handle timer events, like the Xt version
445 of this does in xterm.c, but there is no such feature in GTK. */
446 while (gtk_events_pending ())
447 gtk_main_iteration ();
448 UNBLOCK_INPUT;
449 }
450
451 /* Start the xg_timer with an interval of 0.1 seconds, if not already started.
452 xg_process_timeouts is called when the timer expires. The timer
453 started is continuous, i.e. runs until xg_stop_timer is called. */
454
455 static void
456 xg_start_timer ()
457 {
458 if (! xg_timer)
459 {
460 EMACS_TIME interval;
461 EMACS_SET_SECS_USECS (interval, 0, 100000);
462 xg_timer = start_atimer (ATIMER_CONTINUOUS,
463 interval,
464 xg_process_timeouts,
465 0);
466 }
467 }
468
469 /* Stop the xg_timer if started. */
470
471 static void
472 xg_stop_timer ()
473 {
474 if (xg_timer)
475 {
476 cancel_atimer (xg_timer);
477 xg_timer = 0;
478 }
479 } 421 }
480 422
481 /* Insert NODE into linked LIST. */ 423 /* Insert NODE into linked LIST. */
482 424
483 static void 425 static void
1893 gpointer client_data; 1835 gpointer client_data;
1894 { 1836 {
1895 unref_cl_data ((xg_menu_cb_data*) client_data); 1837 unref_cl_data ((xg_menu_cb_data*) client_data);
1896 } 1838 }
1897 1839
1898 /* Callback called when a menu does a grab or ungrab. That means the
1899 menu has been activated or deactivated.
1900 Used to start a timer so the small timeout the menus in GTK uses before
1901 popping down a menu is seen by Emacs (see xg_process_timeouts above).
1902 W is the widget that does the grab (not used).
1903 UNGRAB_P is TRUE if this is an ungrab, FALSE if it is a grab.
1904 CLIENT_DATA is NULL (not used). */
1905
1906 /* Keep track of total number of grabs. */
1907 static int menu_grab_callback_cnt;
1908
1909 static void
1910 menu_grab_callback (GtkWidget *widget,
1911 gboolean ungrab_p,
1912 gpointer client_data)
1913 {
1914 if (ungrab_p) menu_grab_callback_cnt--;
1915 else menu_grab_callback_cnt++;
1916
1917 if (menu_grab_callback_cnt > 0 && ! xg_timer) xg_start_timer ();
1918 else if (menu_grab_callback_cnt == 0 && xg_timer) xg_stop_timer ();
1919 }
1920
1921 /* Make a GTK widget that contains both UTF8_LABEL and UTF8_KEY (both 1840 /* Make a GTK widget that contains both UTF8_LABEL and UTF8_KEY (both
1922 must be non-NULL) and can be inserted into a menu item. 1841 must be non-NULL) and can be inserted into a menu item.
1923 1842
1924 Returns the GtkHBox. */ 1843 Returns the GtkHBox. */
1925 1844
2230 NULL); 2149 NULL);
2231 } 2150 }
2232 else 2151 else
2233 { 2152 {
2234 wmenu = gtk_menu_bar_new (); 2153 wmenu = gtk_menu_bar_new ();
2235 // Set width of menu bar to a small value so it doesn't enlarge 2154 /* Set width of menu bar to a small value so it doesn't enlarge
2236 // a small initial frame size. The width will be set to the 2155 a small initial frame size. The width will be set to the
2237 // width of the frame later on when it is added to a container. 2156 width of the frame later on when it is added to a container.
2238 // height -1: Natural height. 2157 height -1: Natural height. */
2239 gtk_widget_set_size_request (wmenu, 1, -1); 2158 gtk_widget_set_size_request (wmenu, 1, -1);
2240 } 2159 }
2241 2160
2242 /* Put cl_data on the top menu for easier access. */ 2161 /* Put cl_data on the top menu for easier access. */
2243 cl_data = make_cl_data (cl_data, f, highlight_cb); 2162 cl_data = make_cl_data (cl_data, f, highlight_cb);
2249 gtk_widget_set_name (wmenu, name); 2168 gtk_widget_set_name (wmenu, name);
2250 2169
2251 if (deactivate_cb) 2170 if (deactivate_cb)
2252 g_signal_connect (G_OBJECT (wmenu), 2171 g_signal_connect (G_OBJECT (wmenu),
2253 "selection-done", deactivate_cb, 0); 2172 "selection-done", deactivate_cb, 0);
2254
2255 g_signal_connect (G_OBJECT (wmenu),
2256 "grab-notify", G_CALLBACK (menu_grab_callback), 0);
2257 } 2173 }
2258 2174
2259 if (! menu_bar_p && add_tearoff_p) 2175 if (! menu_bar_p && add_tearoff_p)
2260 { 2176 {
2261 GtkWidget *tearoff = gtk_tearoff_menu_item_new (); 2177 GtkWidget *tearoff = gtk_tearoff_menu_item_new ();
3175 p = g_object_get_data (G_OBJECT (widget), XG_LAST_SB_DATA); 3091 p = g_object_get_data (G_OBJECT (widget), XG_LAST_SB_DATA);
3176 xfree (p); 3092 xfree (p);
3177 xg_remove_widget_from_map (id); 3093 xg_remove_widget_from_map (id);
3178 } 3094 }
3179 3095
3180 /* Callback for button press/release events. Used to start timer so that
3181 the scroll bar repetition timer in GTK gets handled.
3182 Also, sets bar->dragging to Qnil when dragging (button release) is done.
3183 WIDGET is the scroll bar widget the event is for (not used).
3184 EVENT contains the event.
3185 USER_DATA points to the struct scrollbar structure.
3186
3187 Returns FALSE to tell GTK that it shall continue propagate the event
3188 to widgets. */
3189
3190 static gboolean
3191 scroll_bar_button_cb (widget, event, user_data)
3192 GtkWidget *widget;
3193 GdkEventButton *event;
3194 gpointer user_data;
3195 {
3196 if (event->type == GDK_BUTTON_PRESS && ! xg_timer)
3197 xg_start_timer ();
3198 else if (event->type == GDK_BUTTON_RELEASE)
3199 {
3200 struct scroll_bar *bar = (struct scroll_bar *) user_data;
3201 if (xg_timer) xg_stop_timer ();
3202 bar->dragging = Qnil;
3203 }
3204
3205 return FALSE;
3206 }
3207
3208 /* Create a scroll bar widget for frame F. Store the scroll bar 3096 /* Create a scroll bar widget for frame F. Store the scroll bar
3209 in BAR. 3097 in BAR.
3210 SCROLL_CALLBACK is the callback to invoke when the value of the 3098 SCROLL_CALLBACK is the callback to invoke when the value of the
3211 bar changes. 3099 bar changes.
3212 SCROLL_BAR_NAME is the name we use for the scroll bar. Can be used 3100 SCROLL_BAR_NAME is the name we use for the scroll bar. Can be used
3243 /* The EMACS_INT cast avoids a warning. */ 3131 /* The EMACS_INT cast avoids a warning. */
3244 g_signal_connect (G_OBJECT (wscroll), 3132 g_signal_connect (G_OBJECT (wscroll),
3245 "destroy", 3133 "destroy",
3246 G_CALLBACK (xg_gtk_scroll_destroy), 3134 G_CALLBACK (xg_gtk_scroll_destroy),
3247 (gpointer) (EMACS_INT) scroll_id); 3135 (gpointer) (EMACS_INT) scroll_id);
3248
3249 /* Connect to button press and button release to detect if any scroll bar
3250 has the pointer. */
3251 g_signal_connect (G_OBJECT (wscroll),
3252 "button-press-event",
3253 G_CALLBACK (scroll_bar_button_cb),
3254 (gpointer) bar);
3255 g_signal_connect (G_OBJECT (wscroll),
3256 "button-release-event",
3257 G_CALLBACK (scroll_bar_button_cb),
3258 (gpointer) bar);
3259 3136
3260 /* The scroll bar widget does not draw on a window of its own. Instead 3137 /* The scroll bar widget does not draw on a window of its own. Instead
3261 it draws on the parent window, in this case the edit widget. So 3138 it draws on the parent window, in this case the edit widget. So
3262 whenever the edit widget is cleared, the scroll bar needs to redraw 3139 whenever the edit widget is cleared, the scroll bar needs to redraw
3263 also, which causes flicker. Put an event box between the edit widget 3140 also, which causes flicker. Put an event box between the edit widget