Remove debug code.
[emacs.git] / src / gtkutil.c
blob2c5d31e571aa5d80a7c44e1e0de609b3c5c58ded
1 /* Functions for creating and updating GTK widgets.
2 Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009
3 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
20 #include <config.h>
22 #ifdef USE_GTK
23 #include <string.h>
24 #include <signal.h>
25 #include <stdio.h>
26 #include "lisp.h"
27 #include "xterm.h"
28 #include "blockinput.h"
29 #include "syssignal.h"
30 #include "window.h"
31 #include "atimer.h"
32 #include "gtkutil.h"
33 #include "termhooks.h"
34 #include "keyboard.h"
35 #include "charset.h"
36 #include "coding.h"
37 #include <gdk/gdkkeysyms.h>
39 #ifdef HAVE_XFT
40 #include <X11/Xft/Xft.h>
41 #endif
43 #define FRAME_TOTAL_PIXEL_HEIGHT(f) \
44 (FRAME_PIXEL_HEIGHT (f) + FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f))
46 /* Avoid "differ in sign" warnings */
47 #define SSDATA(x) ((char *) SDATA (x))
50 /***********************************************************************
51 Display handling functions
52 ***********************************************************************/
54 #ifdef HAVE_GTK_MULTIDISPLAY
56 /* Keep track of the default display, or NULL if there is none. Emacs
57 may close all its displays. */
59 static GdkDisplay *gdpy_def;
61 /* Return the GdkDisplay that corresponds to the X display DPY. */
63 static GdkDisplay *
64 xg_get_gdk_display (dpy)
65 Display *dpy;
67 return gdk_x11_lookup_xdisplay (dpy);
70 /* When the GTK widget W is to be created on a display for F that
71 is not the default display, set the display for W.
72 W can be a GtkMenu or a GtkWindow widget. */
74 static void
75 xg_set_screen (w, f)
76 GtkWidget *w;
77 FRAME_PTR f;
79 if (FRAME_X_DISPLAY (f) != GDK_DISPLAY ())
81 GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (FRAME_X_DISPLAY (f));
82 GdkScreen *gscreen = gdk_display_get_default_screen (gdpy);
84 if (GTK_IS_MENU (w))
85 gtk_menu_set_screen (GTK_MENU (w), gscreen);
86 else
87 gtk_window_set_screen (GTK_WINDOW (w), gscreen);
92 #else /* not HAVE_GTK_MULTIDISPLAY */
94 /* Make some defines so we can use the GTK 2.2 functions when
95 compiling with GTK 2.0. */
97 #define xg_set_screen(w, f)
98 #define gdk_xid_table_lookup_for_display(dpy, w) gdk_xid_table_lookup (w)
99 #define gdk_pixmap_foreign_new_for_display(dpy, p) gdk_pixmap_foreign_new (p)
100 #define gdk_cursor_new_for_display(dpy, c) gdk_cursor_new (c)
101 #define gdk_x11_lookup_xdisplay(dpy) 0
102 #define GdkDisplay void
104 #endif /* not HAVE_GTK_MULTIDISPLAY */
106 /* Open a display named by DISPLAY_NAME. The display is returned in *DPY.
107 *DPY is set to NULL if the display can't be opened.
109 Returns non-zero if display could be opened, zero if display could not
110 be opened, and less than zero if the GTK version doesn't support
111 multipe displays. */
114 xg_display_open (display_name, dpy)
115 char *display_name;
116 Display **dpy;
118 #ifdef HAVE_GTK_MULTIDISPLAY
119 GdkDisplay *gdpy;
121 gdpy = gdk_display_open (display_name);
122 if (!gdpy_def && gdpy)
124 gdpy_def = gdpy;
125 gdk_display_manager_set_default_display (gdk_display_manager_get (),
126 gdpy);
129 *dpy = gdpy ? GDK_DISPLAY_XDISPLAY (gdpy) : NULL;
130 return gdpy != NULL;
132 #else /* not HAVE_GTK_MULTIDISPLAY */
134 return -1;
135 #endif /* not HAVE_GTK_MULTIDISPLAY */
139 /* Close display DPY. */
141 void
142 xg_display_close (Display *dpy)
144 #ifdef HAVE_GTK_MULTIDISPLAY
145 GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (dpy);
147 /* If this is the default display, try to change it before closing.
148 If there is no other display to use, gdpy_def is set to NULL, and
149 the next call to xg_display_open resets the default display. */
150 if (gdk_display_get_default () == gdpy)
152 struct x_display_info *dpyinfo;
153 GdkDisplay *gdpy_new = NULL;
155 /* Find another display. */
156 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
157 if (dpyinfo->display != dpy)
159 gdpy_new = gdk_x11_lookup_xdisplay (dpyinfo->display);
160 gdk_display_manager_set_default_display (gdk_display_manager_get (),
161 gdpy_new);
162 break;
164 gdpy_def = gdpy_new;
167 #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 10
168 /* GTK 2.2-2.8 has a bug that makes gdk_display_close crash (bug
169 http://bugzilla.gnome.org/show_bug.cgi?id=85715). This way we
170 can continue running, but there will be memory leaks. */
171 g_object_run_dispose (G_OBJECT (gdpy));
172 #else
173 /* This seems to be fixed in GTK 2.10. */
174 gdk_display_close (gdpy);
175 #endif
176 #endif /* HAVE_GTK_MULTIDISPLAY */
180 /***********************************************************************
181 Utility functions
182 ***********************************************************************/
183 /* The timer for scroll bar repetition and menu bar timeouts.
184 NULL if no timer is started. */
185 static struct atimer *xg_timer;
188 /* The next two variables and functions are taken from lwlib. */
189 static widget_value *widget_value_free_list;
190 static int malloc_cpt;
192 /* Allocate a widget_value structure, either by taking one from the
193 widget_value_free_list or by malloc:ing a new one.
195 Return a pointer to the allocated structure. */
197 widget_value *
198 malloc_widget_value ()
200 widget_value *wv;
201 if (widget_value_free_list)
203 wv = widget_value_free_list;
204 widget_value_free_list = wv->free_list;
205 wv->free_list = 0;
207 else
209 wv = (widget_value *) xmalloc (sizeof (widget_value));
210 malloc_cpt++;
212 memset (wv, 0, sizeof (widget_value));
213 return wv;
216 /* This is analogous to free. It frees only what was allocated
217 by malloc_widget_value, and no substructures. */
219 void
220 free_widget_value (wv)
221 widget_value *wv;
223 if (wv->free_list)
224 abort ();
226 if (malloc_cpt > 25)
228 /* When the number of already allocated cells is too big,
229 We free it. */
230 xfree (wv);
231 malloc_cpt--;
233 else
235 wv->free_list = widget_value_free_list;
236 widget_value_free_list = wv;
241 /* Create and return the cursor to be used for popup menus and
242 scroll bars on display DPY. */
244 GdkCursor *
245 xg_create_default_cursor (dpy)
246 Display *dpy;
248 GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (dpy);
249 return gdk_cursor_new_for_display (gdpy, GDK_LEFT_PTR);
252 /* Apply GMASK to GPIX and return a GdkPixbuf with an alpha channel. */
254 static GdkPixbuf *
255 xg_get_pixbuf_from_pix_and_mask (gpix, gmask, cmap)
256 GdkPixmap *gpix;
257 GdkPixmap *gmask;
258 GdkColormap *cmap;
260 int x, y, width, height, rowstride, mask_rowstride;
261 GdkPixbuf *icon_buf, *tmp_buf;
262 guchar *pixels;
263 guchar *mask_pixels;
265 gdk_drawable_get_size (gpix, &width, &height);
266 tmp_buf = gdk_pixbuf_get_from_drawable (NULL, gpix, cmap,
267 0, 0, 0, 0, width, height);
268 icon_buf = gdk_pixbuf_add_alpha (tmp_buf, FALSE, 0, 0, 0);
269 g_object_unref (G_OBJECT (tmp_buf));
271 if (gmask)
273 GdkPixbuf *mask_buf = gdk_pixbuf_get_from_drawable (NULL,
274 gmask,
275 NULL,
276 0, 0, 0, 0,
277 width, height);
278 guchar *pixels = gdk_pixbuf_get_pixels (icon_buf);
279 guchar *mask_pixels = gdk_pixbuf_get_pixels (mask_buf);
280 int rowstride = gdk_pixbuf_get_rowstride (icon_buf);
281 int mask_rowstride = gdk_pixbuf_get_rowstride (mask_buf);
282 int y;
284 for (y = 0; y < height; ++y)
286 guchar *iconptr, *maskptr;
287 int x;
289 iconptr = pixels + y * rowstride;
290 maskptr = mask_pixels + y * mask_rowstride;
292 for (x = 0; x < width; ++x)
294 /* In a bitmap, RGB is either 255/255/255 or 0/0/0. Checking
295 just R is sufficient. */
296 if (maskptr[0] == 0)
297 iconptr[3] = 0; /* 0, 1, 2 is R, G, B. 3 is alpha. */
299 iconptr += rowstride/width;
300 maskptr += mask_rowstride/width;
304 g_object_unref (G_OBJECT (mask_buf));
307 return icon_buf;
310 static Lisp_Object
311 file_for_image (image)
312 Lisp_Object image;
314 Lisp_Object specified_file = Qnil;
315 Lisp_Object tail;
316 extern Lisp_Object QCfile;
318 for (tail = XCDR (image);
319 NILP (specified_file) && CONSP (tail) && CONSP (XCDR (tail));
320 tail = XCDR (XCDR (tail)))
321 if (EQ (XCAR (tail), QCfile))
322 specified_file = XCAR (XCDR (tail));
324 return specified_file;
327 /* For the image defined in IMG, make and return a GtkImage. For displays with
328 8 planes or less we must make a GdkPixbuf and apply the mask manually.
329 Otherwise the highlightning and dimming the tool bar code in GTK does
330 will look bad. For display with more than 8 planes we just use the
331 pixmap and mask directly. For monochrome displays, GTK doesn't seem
332 able to use external pixmaps, it looks bad whatever we do.
333 The image is defined on the display where frame F is.
334 WIDGET is used to find the GdkColormap to use for the GdkPixbuf.
335 If OLD_WIDGET is NULL, a new widget is constructed and returned.
336 If OLD_WIDGET is not NULL, that widget is modified. */
338 static GtkWidget *
339 xg_get_image_for_pixmap (f, img, widget, old_widget)
340 FRAME_PTR f;
341 struct image *img;
342 GtkWidget *widget;
343 GtkImage *old_widget;
345 GdkPixmap *gpix;
346 GdkPixmap *gmask;
347 GdkDisplay *gdpy;
348 GdkColormap *cmap;
349 GdkPixbuf *icon_buf;
351 /* If we have a file, let GTK do all the image handling.
352 This seems to be the only way to make insensitive and activated icons
353 look good in all cases. */
354 Lisp_Object specified_file = file_for_image (img->spec);
355 Lisp_Object file;
357 /* We already loaded the image once before calling this
358 function, so this only fails if the image file has been removed.
359 In that case, use the pixmap already loaded. */
361 if (STRINGP (specified_file)
362 && STRINGP (file = x_find_image_file (specified_file)))
364 if (! old_widget)
365 old_widget = GTK_IMAGE (gtk_image_new_from_file (SSDATA (file)));
366 else
367 gtk_image_set_from_file (old_widget, SSDATA (file));
369 return GTK_WIDGET (old_widget);
372 /* No file, do the image handling ourselves. This will look very bad
373 on a monochrome display, and sometimes bad on all displays with
374 certain themes. */
376 gdpy = gdk_x11_lookup_xdisplay (FRAME_X_DISPLAY (f));
377 gpix = gdk_pixmap_foreign_new_for_display (gdpy, img->pixmap);
378 gmask = img->mask ? gdk_pixmap_foreign_new_for_display (gdpy, img->mask) : 0;
380 /* This is a workaround to make icons look good on pseudo color
381 displays. Apparently GTK expects the images to have an alpha
382 channel. If they don't, insensitive and activated icons will
383 look bad. This workaround does not work on monochrome displays,
384 and is strictly not needed on true color/static color displays (i.e.
385 16 bits and higher). But we do it anyway so we get a pixbuf that is
386 not associated with the img->pixmap. The img->pixmap may be removed
387 by clearing the image cache and then the tool bar redraw fails, since
388 Gtk+ assumes the pixmap is always there. */
389 cmap = gtk_widget_get_colormap (widget);
390 icon_buf = xg_get_pixbuf_from_pix_and_mask (gpix, gmask, cmap);
392 if (! old_widget)
393 old_widget = GTK_IMAGE (gtk_image_new_from_pixbuf (icon_buf));
394 else
395 gtk_image_set_from_pixbuf (old_widget, icon_buf);
397 g_object_unref (G_OBJECT (icon_buf));
399 g_object_unref (G_OBJECT (gpix));
400 if (gmask) g_object_unref (G_OBJECT (gmask));
402 return GTK_WIDGET (old_widget);
406 /* Set CURSOR on W and all widgets W contain. We must do like this
407 for scroll bars and menu because they create widgets internally,
408 and it is those widgets that are visible. */
410 static void
411 xg_set_cursor (w, cursor)
412 GtkWidget *w;
413 GdkCursor *cursor;
415 GList *children = gdk_window_peek_children (w->window);
417 gdk_window_set_cursor (w->window, cursor);
419 /* The scroll bar widget has more than one GDK window (had to look at
420 the source to figure this out), and there is no way to set cursor
421 on widgets in GTK. So we must set the cursor for all GDK windows.
422 Ditto for menus. */
424 for ( ; children; children = g_list_next (children))
425 gdk_window_set_cursor (GDK_WINDOW (children->data), cursor);
428 /* Timer function called when a timeout occurs for xg_timer.
429 This function processes all GTK events in a recursive event loop.
430 This is done because GTK timer events are not seen by Emacs event
431 detection, Emacs only looks for X events. When a scroll bar has the
432 pointer (detected by button press/release events below) an Emacs
433 timer is started, and this function can then check if the GTK timer
434 has expired by calling the GTK event loop.
435 Also, when a menu is active, it has a small timeout before it
436 pops down the sub menu under it. */
438 static void
439 xg_process_timeouts (timer)
440 struct atimer *timer;
442 BLOCK_INPUT;
443 /* Ideally we would like to just handle timer events, like the Xt version
444 of this does in xterm.c, but there is no such feature in GTK. */
445 while (gtk_events_pending ())
446 gtk_main_iteration ();
447 UNBLOCK_INPUT;
450 /* Start the xg_timer with an interval of 0.1 seconds, if not already started.
451 xg_process_timeouts is called when the timer expires. The timer
452 started is continuous, i.e. runs until xg_stop_timer is called. */
454 static void
455 xg_start_timer ()
457 if (! xg_timer)
459 EMACS_TIME interval;
460 EMACS_SET_SECS_USECS (interval, 0, 100000);
461 xg_timer = start_atimer (ATIMER_CONTINUOUS,
462 interval,
463 xg_process_timeouts,
468 /* Stop the xg_timer if started. */
470 static void
471 xg_stop_timer ()
473 if (xg_timer)
475 cancel_atimer (xg_timer);
476 xg_timer = 0;
480 /* Insert NODE into linked LIST. */
482 static void
483 xg_list_insert (xg_list_node *list, xg_list_node *node)
485 xg_list_node *list_start = list->next;
487 if (list_start) list_start->prev = node;
488 node->next = list_start;
489 node->prev = 0;
490 list->next = node;
493 /* Remove NODE from linked LIST. */
495 static void
496 xg_list_remove (xg_list_node *list, xg_list_node *node)
498 xg_list_node *list_start = list->next;
499 if (node == list_start)
501 list->next = node->next;
502 if (list->next) list->next->prev = 0;
504 else
506 node->prev->next = node->next;
507 if (node->next) node->next->prev = node->prev;
511 /* Allocate and return a utf8 version of STR. If STR is already
512 utf8 or NULL, just return STR.
513 If not, a new string is allocated and the caller must free the result
514 with g_free. */
516 static char *
517 get_utf8_string (str)
518 char *str;
520 char *utf8_str = str;
522 if (!str) return NULL;
524 /* If not UTF-8, try current locale. */
525 if (!g_utf8_validate (str, -1, NULL))
526 utf8_str = g_locale_to_utf8 (str, -1, 0, 0, 0);
528 if (!utf8_str)
530 /* Probably some control characters in str. Escape them. */
531 size_t nr_bad = 0;
532 gsize bytes_read;
533 gsize bytes_written;
534 unsigned char *p = (unsigned char *)str;
535 char *cp, *up;
536 GError *error = NULL;
538 while (! (cp = g_locale_to_utf8 ((char *)p, -1, &bytes_read,
539 &bytes_written, &error))
540 && error->code == G_CONVERT_ERROR_ILLEGAL_SEQUENCE)
542 ++nr_bad;
543 p += bytes_written+1;
544 g_error_free (error);
545 error = NULL;
548 if (error)
550 g_error_free (error);
551 error = NULL;
553 if (cp) g_free (cp);
555 up = utf8_str = xmalloc (strlen (str) + nr_bad * 4 + 1);
556 p = (unsigned char *)str;
558 while (! (cp = g_locale_to_utf8 ((char *)p, -1, &bytes_read,
559 &bytes_written, &error))
560 && error->code == G_CONVERT_ERROR_ILLEGAL_SEQUENCE)
562 strncpy (up, (char *)p, bytes_written);
563 sprintf (up + bytes_written, "\\%03o", p[bytes_written]);
564 up[bytes_written+4] = '\0';
565 up += bytes_written+4;
566 p += bytes_written+1;
567 g_error_free (error);
568 error = NULL;
571 if (cp)
573 strcat (utf8_str, cp);
574 g_free (cp);
576 if (error)
578 g_error_free (error);
579 error = NULL;
582 return utf8_str;
587 /***********************************************************************
588 General functions for creating widgets, resizing, events, e.t.c.
589 ***********************************************************************/
591 /* Make a geometry string and pass that to GTK. It seems this is the
592 only way to get geometry position right if the user explicitly
593 asked for a position when starting Emacs.
594 F is the frame we shall set geometry for. */
596 static void
597 xg_set_geometry (f)
598 FRAME_PTR f;
600 if (f->size_hint_flags & USPosition)
602 int left = f->left_pos;
603 int xneg = f->size_hint_flags & XNegative;
604 int top = f->top_pos;
605 int yneg = f->size_hint_flags & YNegative;
606 char geom_str[32];
608 if (xneg)
609 left = -left;
610 if (yneg)
611 top = -top;
613 sprintf (geom_str, "=%dx%d%c%d%c%d",
614 FRAME_PIXEL_WIDTH (f),
615 FRAME_TOTAL_PIXEL_HEIGHT (f),
616 (xneg ? '-' : '+'), left,
617 (yneg ? '-' : '+'), top);
619 if (!gtk_window_parse_geometry (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
620 geom_str))
621 fprintf (stderr, "Failed to parse: '%s'\n", geom_str);
623 else if (f->size_hint_flags & PPosition)
624 gtk_window_move (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
625 f->left_pos, f->top_pos);
628 /* Function to handle resize of our frame. As we have a Gtk+ tool bar
629 and a Gtk+ menu bar, we get resize events for the edit part of the
630 frame only. We let Gtk+ deal with the Gtk+ parts.
631 F is the frame to resize.
632 PIXELWIDTH, PIXELHEIGHT is the new size in pixels. */
634 void
635 xg_frame_resized (f, pixelwidth, pixelheight)
636 FRAME_PTR f;
637 int pixelwidth, pixelheight;
639 int rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, pixelheight);
640 int columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, pixelwidth);
642 if (FRAME_GTK_WIDGET (f)
643 && (columns != FRAME_COLS (f)
644 || rows != FRAME_LINES (f)
645 || pixelwidth != FRAME_PIXEL_WIDTH (f)
646 || pixelheight != FRAME_PIXEL_HEIGHT (f)))
648 FRAME_PIXEL_WIDTH (f) = pixelwidth;
649 FRAME_PIXEL_HEIGHT (f) = pixelheight;
651 change_frame_size (f, rows, columns, 0, 1, 0);
652 SET_FRAME_GARBAGED (f);
653 cancel_mouse_face (f);
657 static void
658 flush_and_sync (f)
659 FRAME_PTR f;
661 gdk_window_process_all_updates ();
662 x_sync (f);
663 while (gtk_events_pending ())
665 gtk_main_iteration ();
666 gdk_window_process_all_updates ();
667 x_sync (f);
671 /* Resize the outer window of frame F after chainging the height.
672 COLUMNS/ROWS is the size the edit area shall have after the resize. */
674 void
675 xg_frame_set_char_size (f, cols, rows)
676 FRAME_PTR f;
677 int cols;
678 int rows;
680 int pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows)
681 + FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f);
682 int pixelwidth;
684 if (FRAME_PIXEL_HEIGHT (f) == 0)
685 return;
687 /* Take into account the size of the scroll bar. Always use the
688 number of columns occupied by the scroll bar here otherwise we
689 might end up with a frame width that is not a multiple of the
690 frame's character width which is bad for vertically split
691 windows. */
692 f->scroll_bar_actual_width
693 = FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f);
695 compute_fringe_widths (f, 0);
697 /* FRAME_TEXT_COLS_TO_PIXEL_WIDTH uses scroll_bar_actual_width, so call it
698 after calculating that value. */
699 pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, cols);
701 /* Must resize our top level widget. Font size may have changed,
702 but not rows/cols. */
703 gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
704 pixelwidth, pixelheight);
705 x_wm_set_size_hint (f, 0, 0);
707 SET_FRAME_GARBAGED (f);
709 /* We can not call change_frame_size here, we can not set pixel
710 width/height either. The window manager may override our resize
711 request, XMonad does this all the time. The best we can do
712 is try to sync, so lisp code sees the updated size as fast as
713 possible. */
714 flush_and_sync (f);
717 /* Handle height changes (i.e. add/remove menu/toolbar).
718 The policy is to keep the number of editable lines. */
720 static void
721 xg_height_changed (f)
722 FRAME_PTR f;
724 gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
725 FRAME_PIXEL_WIDTH (f), FRAME_TOTAL_PIXEL_HEIGHT (f));
726 f->output_data.x->hint_flags = 0;
727 x_wm_set_size_hint (f, 0, 0);
730 /* Convert an X Window WSESC on display DPY to its corresponding GtkWidget.
731 Must be done like this, because GtkWidget:s can have "hidden"
732 X Window that aren't accessible.
734 Return 0 if no widget match WDESC. */
736 GtkWidget *
737 xg_win_to_widget (dpy, wdesc)
738 Display *dpy;
739 Window wdesc;
741 gpointer gdkwin;
742 GtkWidget *gwdesc = 0;
744 BLOCK_INPUT;
746 gdkwin = gdk_xid_table_lookup_for_display (gdk_x11_lookup_xdisplay (dpy),
747 wdesc);
748 if (gdkwin)
750 GdkEvent event;
751 event.any.window = gdkwin;
752 gwdesc = gtk_get_event_widget (&event);
755 UNBLOCK_INPUT;
756 return gwdesc;
759 /* Fill in the GdkColor C so that it represents PIXEL.
760 W is the widget that color will be used for. Used to find colormap. */
762 static void
763 xg_pix_to_gcolor (w, pixel, c)
764 GtkWidget *w;
765 unsigned long pixel;
766 GdkColor *c;
768 GdkColormap *map = gtk_widget_get_colormap (w);
769 gdk_colormap_query_color (map, pixel, c);
772 /* Create and set up the GTK widgets for frame F.
773 Return 0 if creation failed, non-zero otherwise. */
776 xg_create_frame_widgets (f)
777 FRAME_PTR f;
779 GtkWidget *wtop;
780 GtkWidget *wvbox;
781 GtkWidget *wfixed;
782 GdkColor bg;
783 GtkRcStyle *style;
784 int i;
785 char *title = 0;
787 BLOCK_INPUT;
789 if (FRAME_X_EMBEDDED_P (f))
790 wtop = gtk_plug_new (f->output_data.x->parent_desc);
791 else
792 wtop = gtk_window_new (GTK_WINDOW_TOPLEVEL);
794 xg_set_screen (wtop, f);
796 wvbox = gtk_vbox_new (FALSE, 0);
797 wfixed = gtk_fixed_new (); /* Must have this to place scroll bars */
799 if (! wtop || ! wvbox || ! wfixed)
801 if (wtop) gtk_widget_destroy (wtop);
802 if (wvbox) gtk_widget_destroy (wvbox);
803 if (wfixed) gtk_widget_destroy (wfixed);
805 UNBLOCK_INPUT;
806 return 0;
809 /* Use same names as the Xt port does. I.e. Emacs.pane.emacs by default */
810 gtk_widget_set_name (wtop, EMACS_CLASS);
811 gtk_widget_set_name (wvbox, "pane");
812 gtk_widget_set_name (wfixed, SSDATA (Vx_resource_name));
814 /* If this frame has a title or name, set it in the title bar. */
815 if (! NILP (f->title)) title = SSDATA (ENCODE_UTF_8 (f->title));
816 else if (! NILP (f->name)) title = SSDATA (ENCODE_UTF_8 (f->name));
818 if (title) gtk_window_set_title (GTK_WINDOW (wtop), title);
820 FRAME_GTK_OUTER_WIDGET (f) = wtop;
821 FRAME_GTK_WIDGET (f) = wfixed;
822 f->output_data.x->vbox_widget = wvbox;
824 gtk_fixed_set_has_window (GTK_FIXED (wfixed), TRUE);
826 gtk_container_add (GTK_CONTAINER (wtop), wvbox);
827 gtk_box_pack_end (GTK_BOX (wvbox), wfixed, TRUE, TRUE, 0);
829 if (FRAME_EXTERNAL_TOOL_BAR (f))
830 update_frame_tool_bar (f);
832 /* We don't want this widget double buffered, because we draw on it
833 with regular X drawing primitives, so from a GTK/GDK point of
834 view, the widget is totally blank. When an expose comes, this
835 will make the widget blank, and then Emacs redraws it. This flickers
836 a lot, so we turn off double buffering. */
837 gtk_widget_set_double_buffered (wfixed, FALSE);
839 gtk_window_set_wmclass (GTK_WINDOW (wtop),
840 SSDATA (Vx_resource_name),
841 SSDATA (Vx_resource_class));
843 /* Add callback to do nothing on WM_DELETE_WINDOW. The default in
844 GTK is to destroy the widget. We want Emacs to do that instead. */
845 g_signal_connect (G_OBJECT (wtop), "delete-event",
846 G_CALLBACK (gtk_true), 0);
848 /* Convert our geometry parameters into a geometry string
849 and specify it.
850 GTK will itself handle calculating the real position this way. */
851 xg_set_geometry (f);
852 int grav = gtk_window_get_gravity (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)));
853 f->win_gravity = grav;
855 gtk_widget_add_events (wfixed,
856 GDK_POINTER_MOTION_MASK
857 | GDK_EXPOSURE_MASK
858 | GDK_BUTTON_PRESS_MASK
859 | GDK_BUTTON_RELEASE_MASK
860 | GDK_KEY_PRESS_MASK
861 | GDK_ENTER_NOTIFY_MASK
862 | GDK_LEAVE_NOTIFY_MASK
863 | GDK_FOCUS_CHANGE_MASK
864 | GDK_STRUCTURE_MASK
865 | GDK_VISIBILITY_NOTIFY_MASK);
867 /* Must realize the windows so the X window gets created. It is used
868 by callers of this function. */
869 gtk_widget_realize (wfixed);
870 FRAME_X_WINDOW (f) = GTK_WIDGET_TO_X_WIN (wfixed);
872 /* Since GTK clears its window by filling with the background color,
873 we must keep X and GTK background in sync. */
874 xg_pix_to_gcolor (wfixed, FRAME_BACKGROUND_PIXEL (f), &bg);
875 gtk_widget_modify_bg (wfixed, GTK_STATE_NORMAL, &bg);
877 /* Also, do not let any background pixmap to be set, this looks very
878 bad as Emacs overwrites the background pixmap with its own idea
879 of background color. */
880 style = gtk_widget_get_modifier_style (wfixed);
882 /* Must use g_strdup because gtk_widget_modify_style does g_free. */
883 style->bg_pixmap_name[GTK_STATE_NORMAL] = g_strdup ("<none>");
884 gtk_widget_modify_style (wfixed, style);
886 /* GTK does not set any border, and they look bad with GTK. */
887 /* That they look bad is no excuse for imposing this here. --Stef
888 It should be done by providing the proper default in Fx_create_Frame.
889 f->border_width = 0;
890 f->internal_border_width = 0; */
892 UNBLOCK_INPUT;
894 return 1;
897 /* Set the normal size hints for the window manager, for frame F.
898 FLAGS is the flags word to use--or 0 meaning preserve the flags
899 that the window now has.
900 If USER_POSITION is nonzero, we set the User Position
901 flag (this is useful when FLAGS is 0). */
903 void
904 x_wm_set_size_hint (f, flags, user_position)
905 FRAME_PTR f;
906 long flags;
907 int user_position;
909 /* Don't set size hints during initialization; that apparently leads
910 to a race condition. See the thread at
911 http://lists.gnu.org/archive/html/emacs-devel/2008-10/msg00033.html */
912 if (NILP (Vafter_init_time) || !FRAME_GTK_OUTER_WIDGET (f))
913 return;
915 /* Must use GTK routines here, otherwise GTK resets the size hints
916 to its own defaults. */
917 GdkGeometry size_hints;
918 gint hint_flags = 0;
919 int base_width, base_height;
920 int min_rows = 0, min_cols = 0;
921 int win_gravity = f->win_gravity;
923 if (flags)
925 memset (&size_hints, 0, sizeof (size_hints));
926 f->output_data.x->size_hints = size_hints;
927 f->output_data.x->hint_flags = hint_flags;
929 else
930 flags = f->size_hint_flags;
932 size_hints = f->output_data.x->size_hints;
933 hint_flags = f->output_data.x->hint_flags;
935 hint_flags |= GDK_HINT_RESIZE_INC | GDK_HINT_MIN_SIZE;
936 size_hints.width_inc = FRAME_COLUMN_WIDTH (f);
937 size_hints.height_inc = FRAME_LINE_HEIGHT (f);
939 hint_flags |= GDK_HINT_BASE_SIZE;
940 base_width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, 0);
941 base_height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, 0)
942 + FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f);
944 check_frame_size (f, &min_rows, &min_cols);
946 size_hints.base_width = base_width;
947 size_hints.base_height = base_height;
948 size_hints.min_width = base_width + min_cols * size_hints.width_inc;
949 size_hints.min_height = base_height + min_rows * size_hints.height_inc;
951 /* These currently have a one to one mapping with the X values, but I
952 don't think we should rely on that. */
953 hint_flags |= GDK_HINT_WIN_GRAVITY;
954 size_hints.win_gravity = 0;
955 if (win_gravity == NorthWestGravity)
956 size_hints.win_gravity = GDK_GRAVITY_NORTH_WEST;
957 else if (win_gravity == NorthGravity)
958 size_hints.win_gravity = GDK_GRAVITY_NORTH;
959 else if (win_gravity == NorthEastGravity)
960 size_hints.win_gravity = GDK_GRAVITY_NORTH_EAST;
961 else if (win_gravity == WestGravity)
962 size_hints.win_gravity = GDK_GRAVITY_WEST;
963 else if (win_gravity == CenterGravity)
964 size_hints.win_gravity = GDK_GRAVITY_CENTER;
965 else if (win_gravity == EastGravity)
966 size_hints.win_gravity = GDK_GRAVITY_EAST;
967 else if (win_gravity == SouthWestGravity)
968 size_hints.win_gravity = GDK_GRAVITY_SOUTH_WEST;
969 else if (win_gravity == SouthGravity)
970 size_hints.win_gravity = GDK_GRAVITY_SOUTH;
971 else if (win_gravity == SouthEastGravity)
972 size_hints.win_gravity = GDK_GRAVITY_SOUTH_EAST;
973 else if (win_gravity == StaticGravity)
974 size_hints.win_gravity = GDK_GRAVITY_STATIC;
976 if (flags & PPosition) hint_flags |= GDK_HINT_POS;
977 if (flags & USPosition) hint_flags |= GDK_HINT_USER_POS;
978 if (flags & USSize) hint_flags |= GDK_HINT_USER_SIZE;
980 if (user_position)
982 hint_flags &= ~GDK_HINT_POS;
983 hint_flags |= GDK_HINT_USER_POS;
986 if (hint_flags != f->output_data.x->hint_flags
987 || memcmp (&size_hints,
988 &f->output_data.x->size_hints,
989 sizeof (size_hints)) != 0)
991 BLOCK_INPUT;
992 gtk_window_set_geometry_hints (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
993 NULL, &size_hints, hint_flags);
994 f->output_data.x->size_hints = size_hints;
995 f->output_data.x->hint_flags = hint_flags;
996 UNBLOCK_INPUT;
1000 /* Change background color of a frame.
1001 Since GTK uses the background color to clear the window, we must
1002 keep the GTK and X colors in sync.
1003 F is the frame to change,
1004 BG is the pixel value to change to. */
1006 void
1007 xg_set_background_color (f, bg)
1008 FRAME_PTR f;
1009 unsigned long bg;
1011 if (FRAME_GTK_WIDGET (f))
1013 GdkColor gdk_bg;
1015 BLOCK_INPUT;
1016 xg_pix_to_gcolor (FRAME_GTK_WIDGET (f), bg, &gdk_bg);
1017 gtk_widget_modify_bg (FRAME_GTK_WIDGET (f), GTK_STATE_NORMAL, &gdk_bg);
1018 UNBLOCK_INPUT;
1023 /* Set the frame icon to ICON_PIXMAP/MASK. This must be done with GTK
1024 functions so GTK does not overwrite the icon. */
1026 void
1027 xg_set_frame_icon (f, icon_pixmap, icon_mask)
1028 FRAME_PTR f;
1029 Pixmap icon_pixmap;
1030 Pixmap icon_mask;
1032 GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (FRAME_X_DISPLAY (f));
1033 GdkPixmap *gpix = gdk_pixmap_foreign_new_for_display (gdpy, icon_pixmap);
1034 GdkPixmap *gmask = gdk_pixmap_foreign_new_for_display (gdpy, icon_mask);
1035 GdkPixbuf *gp = xg_get_pixbuf_from_pix_and_mask (gpix, gmask, NULL);
1037 gtk_window_set_icon (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), gp);
1042 /***********************************************************************
1043 Dialog functions
1044 ***********************************************************************/
1045 /* Return the dialog title to use for a dialog of type KEY.
1046 This is the encoding used by lwlib. We use the same for GTK. */
1048 static char *
1049 get_dialog_title (char key)
1051 char *title = "";
1053 switch (key) {
1054 case 'E': case 'e':
1055 title = "Error";
1056 break;
1058 case 'I': case 'i':
1059 title = "Information";
1060 break;
1062 case 'L': case 'l':
1063 title = "Prompt";
1064 break;
1066 case 'P': case 'p':
1067 title = "Prompt";
1068 break;
1070 case 'Q': case 'q':
1071 title = "Question";
1072 break;
1075 return title;
1078 /* Callback for dialogs that get WM_DELETE_WINDOW. We pop down
1079 the dialog, but return TRUE so the event does not propagate further
1080 in GTK. This prevents GTK from destroying the dialog widget automatically
1081 and we can always destrou the widget manually, regardles of how
1082 it was popped down (button press or WM_DELETE_WINDOW).
1083 W is the dialog widget.
1084 EVENT is the GdkEvent that represents WM_DELETE_WINDOW (not used).
1085 user_data is NULL (not used).
1087 Returns TRUE to end propagation of event. */
1089 static gboolean
1090 dialog_delete_callback (w, event, user_data)
1091 GtkWidget *w;
1092 GdkEvent *event;
1093 gpointer user_data;
1095 gtk_widget_unmap (w);
1096 return TRUE;
1099 /* Create a popup dialog window. See also xg_create_widget below.
1100 WV is a widget_value describing the dialog.
1101 SELECT_CB is the callback to use when a button has been pressed.
1102 DEACTIVATE_CB is the callback to use when the dialog pops down.
1104 Returns the GTK dialog widget. */
1106 static GtkWidget *
1107 create_dialog (wv, select_cb, deactivate_cb)
1108 widget_value *wv;
1109 GCallback select_cb;
1110 GCallback deactivate_cb;
1112 char *title = get_dialog_title (wv->name[0]);
1113 int total_buttons = wv->name[1] - '0';
1114 int right_buttons = wv->name[4] - '0';
1115 int left_buttons;
1116 int button_nr = 0;
1117 int button_spacing = 10;
1118 GtkWidget *wdialog = gtk_dialog_new ();
1119 widget_value *item;
1120 GtkBox *cur_box;
1121 GtkWidget *wvbox;
1122 GtkWidget *whbox_up;
1123 GtkWidget *whbox_down;
1125 /* If the number of buttons is greater than 4, make two rows of buttons
1126 instead. This looks better. */
1127 int make_two_rows = total_buttons > 4;
1129 if (right_buttons == 0) right_buttons = total_buttons/2;
1130 left_buttons = total_buttons - right_buttons;
1132 gtk_window_set_title (GTK_WINDOW (wdialog), title);
1133 gtk_widget_set_name (wdialog, "emacs-dialog");
1135 cur_box = GTK_BOX (GTK_DIALOG (wdialog)->action_area);
1137 if (make_two_rows)
1139 wvbox = gtk_vbox_new (TRUE, button_spacing);
1140 whbox_up = gtk_hbox_new (FALSE, 0);
1141 whbox_down = gtk_hbox_new (FALSE, 0);
1143 gtk_box_pack_start (cur_box, wvbox, FALSE, FALSE, 0);
1144 gtk_box_pack_start (GTK_BOX (wvbox), whbox_up, FALSE, FALSE, 0);
1145 gtk_box_pack_start (GTK_BOX (wvbox), whbox_down, FALSE, FALSE, 0);
1147 cur_box = GTK_BOX (whbox_up);
1150 g_signal_connect (G_OBJECT (wdialog), "delete-event",
1151 G_CALLBACK (dialog_delete_callback), 0);
1153 if (deactivate_cb)
1155 g_signal_connect (G_OBJECT (wdialog), "close", deactivate_cb, 0);
1156 g_signal_connect (G_OBJECT (wdialog), "response", deactivate_cb, 0);
1159 for (item = wv->contents; item; item = item->next)
1161 char *utf8_label = get_utf8_string (item->value);
1162 GtkWidget *w;
1163 GtkRequisition req;
1165 if (item->name && strcmp (item->name, "message") == 0)
1167 /* This is the text part of the dialog. */
1168 w = gtk_label_new (utf8_label);
1169 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (wdialog)->vbox),
1170 gtk_label_new (""),
1171 FALSE, FALSE, 0);
1172 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (wdialog)->vbox), w,
1173 TRUE, TRUE, 0);
1174 gtk_misc_set_alignment (GTK_MISC (w), 0.1, 0.5);
1176 /* Try to make dialog look better. Must realize first so
1177 the widget can calculate the size it needs. */
1178 gtk_widget_realize (w);
1179 gtk_widget_size_request (w, &req);
1180 gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (wdialog)->vbox),
1181 req.height);
1182 if (item->value && strlen (item->value) > 0)
1183 button_spacing = 2*req.width/strlen (item->value);
1185 else
1187 /* This is one button to add to the dialog. */
1188 w = gtk_button_new_with_label (utf8_label);
1189 if (! item->enabled)
1190 gtk_widget_set_sensitive (w, FALSE);
1191 if (select_cb)
1192 g_signal_connect (G_OBJECT (w), "clicked",
1193 select_cb, item->call_data);
1195 gtk_box_pack_start (cur_box, w, TRUE, TRUE, button_spacing);
1196 if (++button_nr == left_buttons)
1198 if (make_two_rows)
1199 cur_box = GTK_BOX (whbox_down);
1200 else
1201 gtk_box_pack_start (cur_box,
1202 gtk_label_new (""),
1203 TRUE, TRUE,
1204 button_spacing);
1208 if (utf8_label && utf8_label != item->value)
1209 g_free (utf8_label);
1212 return wdialog;
1217 /***********************************************************************
1218 File dialog functions
1219 ***********************************************************************/
1220 /* Return non-zero if the old file selection dialog is being used.
1221 Return zero if not. */
1224 xg_uses_old_file_dialog ()
1226 #ifdef HAVE_GTK_FILE_BOTH
1227 extern int x_gtk_use_old_file_dialog;
1228 return x_gtk_use_old_file_dialog;
1229 #else /* ! HAVE_GTK_FILE_BOTH */
1231 #ifdef HAVE_GTK_FILE_SELECTION_NEW
1232 return 1;
1233 #else
1234 return 0;
1235 #endif
1237 #endif /* ! HAVE_GTK_FILE_BOTH */
1241 /* Function that is called when the file or font dialogs pop down.
1242 W is the dialog widget, RESPONSE is the response code.
1243 USER_DATA is what we passed in to g_signal_connect (pointer to int). */
1245 static void
1246 xg_dialog_response_cb (w,
1247 response,
1248 user_data)
1249 GtkDialog *w;
1250 gint response;
1251 gpointer user_data;
1253 int *ptr = (int *) user_data;
1254 *ptr = response;
1258 /* Destroy the dialog. This makes it pop down. */
1260 static Lisp_Object
1261 pop_down_dialog (arg)
1262 Lisp_Object arg;
1264 struct Lisp_Save_Value *p = XSAVE_VALUE (arg);
1265 BLOCK_INPUT;
1266 gtk_widget_destroy (GTK_WIDGET (p->pointer));
1267 UNBLOCK_INPUT;
1268 return Qnil;
1271 typedef char * (*xg_get_file_func) P_ ((GtkWidget *));
1273 #ifdef HAVE_GTK_FILE_CHOOSER_DIALOG_NEW
1275 /* Return the selected file for file chooser dialog W.
1276 The returned string must be free:d. */
1278 static char *
1279 xg_get_file_name_from_chooser (w)
1280 GtkWidget *w;
1282 return gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (w));
1285 /* Callback called when the "Show hidden files" toggle is pressed.
1286 WIDGET is the toggle widget, DATA is the file chooser dialog. */
1288 static void
1289 xg_toggle_visibility_cb (widget, data)
1290 GtkWidget *widget;
1291 gpointer data;
1293 GtkFileChooser *dialog = GTK_FILE_CHOOSER (data);
1294 gboolean visible;
1295 g_object_get (G_OBJECT (dialog), "show-hidden", &visible, NULL);
1296 g_object_set (G_OBJECT (dialog), "show-hidden", !visible, NULL);
1300 /* Callback called when a property changes in a file chooser.
1301 GOBJECT is the file chooser dialog, ARG1 describes the property.
1302 USER_DATA is the toggle widget in the file chooser dialog.
1303 We use this to update the "Show hidden files" toggle when the user
1304 changes that property by right clicking in the file list. */
1306 static void
1307 xg_toggle_notify_cb (gobject, arg1, user_data)
1308 GObject *gobject;
1309 GParamSpec *arg1;
1310 gpointer user_data;
1312 extern int x_gtk_show_hidden_files;
1314 if (strcmp (arg1->name, "show-hidden") == 0)
1316 GtkFileChooser *dialog = GTK_FILE_CHOOSER (gobject);
1317 GtkWidget *wtoggle = GTK_WIDGET (user_data);
1318 gboolean visible, toggle_on;
1320 g_object_get (G_OBJECT (gobject), "show-hidden", &visible, NULL);
1321 toggle_on = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (wtoggle));
1323 if (!!visible != !!toggle_on)
1325 g_signal_handlers_block_by_func (G_OBJECT (wtoggle),
1326 G_CALLBACK (xg_toggle_visibility_cb),
1327 gobject);
1328 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wtoggle), visible);
1329 g_signal_handlers_unblock_by_func
1330 (G_OBJECT (wtoggle),
1331 G_CALLBACK (xg_toggle_visibility_cb),
1332 gobject);
1334 x_gtk_show_hidden_files = visible;
1338 /* Read a file name from the user using a file chooser dialog.
1339 F is the current frame.
1340 PROMPT is a prompt to show to the user. May not be NULL.
1341 DEFAULT_FILENAME is a default selection to be displayed. May be NULL.
1342 If MUSTMATCH_P is non-zero, the returned file name must be an existing
1343 file. *FUNC is set to a function that can be used to retrieve the
1344 selected file name from the returned widget.
1346 Returns the created widget. */
1348 static GtkWidget *
1349 xg_get_file_with_chooser (f, prompt, default_filename,
1350 mustmatch_p, only_dir_p, func)
1351 FRAME_PTR f;
1352 char *prompt;
1353 char *default_filename;
1354 int mustmatch_p, only_dir_p;
1355 xg_get_file_func *func;
1357 char message[1024];
1359 GtkWidget *filewin, *wtoggle, *wbox, *wmessage;
1360 GtkWindow *gwin = GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f));
1361 GtkFileChooserAction action = (mustmatch_p ?
1362 GTK_FILE_CHOOSER_ACTION_OPEN :
1363 GTK_FILE_CHOOSER_ACTION_SAVE);
1364 extern int x_gtk_show_hidden_files;
1365 extern int x_gtk_file_dialog_help_text;
1368 if (only_dir_p)
1369 action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
1371 filewin = gtk_file_chooser_dialog_new (prompt, gwin, action,
1372 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1373 (mustmatch_p || only_dir_p ?
1374 GTK_STOCK_OPEN : GTK_STOCK_OK),
1375 GTK_RESPONSE_OK,
1376 NULL);
1377 gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (filewin), TRUE);
1379 wbox = gtk_vbox_new (FALSE, 0);
1380 gtk_widget_show (wbox);
1381 wtoggle = gtk_check_button_new_with_label ("Show hidden files.");
1383 if (x_gtk_show_hidden_files)
1385 g_object_set (G_OBJECT (filewin), "show-hidden", TRUE, NULL);
1386 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wtoggle), TRUE);
1388 gtk_widget_show (wtoggle);
1389 g_signal_connect (G_OBJECT (wtoggle), "clicked",
1390 G_CALLBACK (xg_toggle_visibility_cb), filewin);
1391 g_signal_connect (G_OBJECT (filewin), "notify",
1392 G_CALLBACK (xg_toggle_notify_cb), wtoggle);
1394 if (x_gtk_file_dialog_help_text)
1396 message[0] = '\0';
1397 /* Gtk+ 2.10 has the file name text entry box integrated in the dialog.
1398 Show the C-l help text only for versions < 2.10. */
1399 if (gtk_check_version (2, 10, 0) && action != GTK_FILE_CHOOSER_ACTION_SAVE)
1400 strcat (message, "\nType C-l to display a file name text entry box.\n");
1401 strcat (message, "\nIf you don't like this file selector, use the "
1402 "corresponding\nkey binding or customize "
1403 "use-file-dialog to turn it off.");
1405 wmessage = gtk_label_new (message);
1406 gtk_widget_show (wmessage);
1409 gtk_box_pack_start (GTK_BOX (wbox), wtoggle, FALSE, FALSE, 0);
1410 if (x_gtk_file_dialog_help_text)
1411 gtk_box_pack_start (GTK_BOX (wbox), wmessage, FALSE, FALSE, 0);
1412 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (filewin), wbox);
1414 if (default_filename)
1416 Lisp_Object file;
1417 struct gcpro gcpro1;
1418 char *utf8_filename;
1419 GCPRO1 (file);
1421 file = build_string (default_filename);
1423 /* File chooser does not understand ~/... in the file name. It must be
1424 an absolute name starting with /. */
1425 if (default_filename[0] != '/')
1426 file = Fexpand_file_name (file, Qnil);
1428 utf8_filename = SSDATA (ENCODE_UTF_8 (file));
1429 if (! NILP (Ffile_directory_p (file)))
1430 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (filewin),
1431 utf8_filename);
1432 else
1434 gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (filewin),
1435 utf8_filename);
1436 if (action == GTK_FILE_CHOOSER_ACTION_SAVE)
1438 char *cp = strrchr (utf8_filename, '/');
1439 if (cp) ++cp;
1440 else cp = utf8_filename;
1441 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (filewin), cp);
1445 UNGCPRO;
1448 *func = xg_get_file_name_from_chooser;
1449 return filewin;
1451 #endif /* HAVE_GTK_FILE_CHOOSER_DIALOG_NEW */
1453 #ifdef HAVE_GTK_FILE_SELECTION_NEW
1455 /* Return the selected file for file selector dialog W.
1456 The returned string must be free:d. */
1458 static char *
1459 xg_get_file_name_from_selector (w)
1460 GtkWidget *w;
1462 GtkFileSelection *filesel = GTK_FILE_SELECTION (w);
1463 return xstrdup ((char*) gtk_file_selection_get_filename (filesel));
1466 /* Create a file selection dialog.
1467 F is the current frame.
1468 PROMPT is a prompt to show to the user. May not be NULL.
1469 DEFAULT_FILENAME is a default selection to be displayed. May be NULL.
1470 If MUSTMATCH_P is non-zero, the returned file name must be an existing
1471 file. *FUNC is set to a function that can be used to retrieve the
1472 selected file name from the returned widget.
1474 Returns the created widget. */
1476 static GtkWidget *
1477 xg_get_file_with_selection (f, prompt, default_filename,
1478 mustmatch_p, only_dir_p, func)
1479 FRAME_PTR f;
1480 char *prompt;
1481 char *default_filename;
1482 int mustmatch_p, only_dir_p;
1483 xg_get_file_func *func;
1485 GtkWidget *filewin;
1486 GtkFileSelection *filesel;
1488 filewin = gtk_file_selection_new (prompt);
1489 filesel = GTK_FILE_SELECTION (filewin);
1491 if (default_filename)
1492 gtk_file_selection_set_filename (filesel, default_filename);
1494 if (mustmatch_p)
1496 /* The selection_entry part of filesel is not documented. */
1497 gtk_widget_set_sensitive (filesel->selection_entry, FALSE);
1498 gtk_file_selection_hide_fileop_buttons (filesel);
1501 *func = xg_get_file_name_from_selector;
1503 return filewin;
1505 #endif /* HAVE_GTK_FILE_SELECTION_NEW */
1507 /* Read a file name from the user using a file dialog, either the old
1508 file selection dialog, or the new file chooser dialog. Which to use
1509 depends on what the GTK version used has, and what the value of
1510 gtk-use-old-file-dialog.
1511 F is the current frame.
1512 PROMPT is a prompt to show to the user. May not be NULL.
1513 DEFAULT_FILENAME is a default selection to be displayed. May be NULL.
1514 If MUSTMATCH_P is non-zero, the returned file name must be an existing
1515 file.
1517 Returns a file name or NULL if no file was selected.
1518 The returned string must be freed by the caller. */
1520 char *
1521 xg_get_file_name (f, prompt, default_filename, mustmatch_p, only_dir_p)
1522 FRAME_PTR f;
1523 char *prompt;
1524 char *default_filename;
1525 int mustmatch_p, only_dir_p;
1527 GtkWidget *w = 0;
1528 int count = SPECPDL_INDEX ();
1529 char *fn = 0;
1530 int filesel_done = 0;
1531 xg_get_file_func func;
1533 #if defined (HAVE_GTK_AND_PTHREAD) && defined (__SIGRTMIN)
1534 /* I really don't know why this is needed, but without this the GLIBC add on
1535 library linuxthreads hangs when the Gnome file chooser backend creates
1536 threads. */
1537 sigblock (sigmask (__SIGRTMIN));
1538 #endif /* HAVE_GTK_AND_PTHREAD */
1540 #ifdef HAVE_GTK_FILE_BOTH
1542 if (xg_uses_old_file_dialog ())
1543 w = xg_get_file_with_selection (f, prompt, default_filename,
1544 mustmatch_p, only_dir_p, &func);
1545 else
1546 w = xg_get_file_with_chooser (f, prompt, default_filename,
1547 mustmatch_p, only_dir_p, &func);
1549 #else /* not HAVE_GTK_FILE_BOTH */
1551 #ifdef HAVE_GTK_FILE_SELECTION_NEW
1552 w = xg_get_file_with_selection (f, prompt, default_filename,
1553 mustmatch_p, only_dir_p, &func);
1554 #endif
1555 #ifdef HAVE_GTK_FILE_CHOOSER_DIALOG_NEW
1556 w = xg_get_file_with_chooser (f, prompt, default_filename,
1557 mustmatch_p, only_dir_p, &func);
1558 #endif
1560 #endif /* HAVE_GTK_FILE_BOTH */
1562 xg_set_screen (w, f);
1563 gtk_widget_set_name (w, "emacs-filedialog");
1564 gtk_window_set_transient_for (GTK_WINDOW (w),
1565 GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)));
1566 gtk_window_set_destroy_with_parent (GTK_WINDOW (w), TRUE);
1567 gtk_window_set_modal (GTK_WINDOW (w), TRUE);
1569 g_signal_connect (G_OBJECT (w),
1570 "response",
1571 G_CALLBACK (xg_dialog_response_cb),
1572 &filesel_done);
1574 /* Don't destroy the widget if closed by the window manager close button. */
1575 g_signal_connect (G_OBJECT (w), "delete-event", G_CALLBACK (gtk_true), NULL);
1577 gtk_widget_show (w);
1579 record_unwind_protect (pop_down_dialog, make_save_value (w, 0));
1580 while (! filesel_done)
1582 x_menu_wait_for_event (0);
1583 gtk_main_iteration ();
1586 #if defined (HAVE_GTK_AND_PTHREAD) && defined (__SIGRTMIN)
1587 sigunblock (sigmask (__SIGRTMIN));
1588 #endif
1590 if (filesel_done == GTK_RESPONSE_OK)
1591 fn = (*func) (w);
1593 unbind_to (count, Qnil);
1595 return fn;
1598 #ifdef HAVE_FREETYPE
1599 /* Pop up a GTK font selector and return the name of the font the user
1600 selects, as a C string. The returned font name follows GTK's own
1601 format:
1603 `FAMILY [VALUE1 VALUE2] SIZE'
1605 This can be parsed using font_parse_fcname in font.c.
1606 DEFAULT_NAME, if non-zero, is the default font name. */
1608 char *
1609 xg_get_font_name (f, default_name)
1610 FRAME_PTR f;
1611 char *default_name;
1613 GtkWidget *w = 0;
1614 int count = SPECPDL_INDEX ();
1615 char *fontname = NULL;
1616 int done = 0;
1618 #if defined (HAVE_GTK_AND_PTHREAD) && defined (__SIGRTMIN)
1619 sigblock (sigmask (__SIGRTMIN));
1620 #endif /* HAVE_GTK_AND_PTHREAD */
1622 w = gtk_font_selection_dialog_new ("Pick a font");
1623 if (default_name)
1624 gtk_font_selection_dialog_set_font_name (GTK_FONT_SELECTION_DIALOG (w),
1625 default_name);
1627 xg_set_screen (w, f);
1628 gtk_widget_set_name (w, "emacs-fontdialog");
1629 gtk_window_set_transient_for (GTK_WINDOW (w),
1630 GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)));
1631 gtk_window_set_destroy_with_parent (GTK_WINDOW (w), TRUE);
1632 gtk_window_set_modal (GTK_WINDOW (w), TRUE);
1634 g_signal_connect (G_OBJECT (w), "response",
1635 G_CALLBACK (xg_dialog_response_cb), &done);
1637 /* Don't destroy the widget if closed by the window manager close button. */
1638 g_signal_connect (G_OBJECT (w), "delete-event", G_CALLBACK (gtk_true), NULL);
1640 gtk_widget_show (w);
1642 record_unwind_protect (pop_down_dialog, make_save_value (w, 0));
1643 while (!done)
1645 x_menu_wait_for_event (0);
1646 gtk_main_iteration ();
1649 #if defined (HAVE_GTK_AND_PTHREAD) && defined (__SIGRTMIN)
1650 sigunblock (sigmask (__SIGRTMIN));
1651 #endif
1653 if (done == GTK_RESPONSE_OK)
1654 fontname = gtk_font_selection_dialog_get_font_name
1655 ((GtkFontSelectionDialog *) w);
1657 unbind_to (count, Qnil);
1659 return fontname;
1661 #endif /* HAVE_FREETYPE */
1665 /***********************************************************************
1666 Menu functions.
1667 ***********************************************************************/
1669 /* The name of menu items that can be used for customization. Since GTK
1670 RC files are very crude and primitive, we have to set this on all
1671 menu item names so a user can easily customize menu items. */
1673 #define MENU_ITEM_NAME "emacs-menuitem"
1676 /* Linked list of all allocated struct xg_menu_cb_data. Used for marking
1677 during GC. The next member points to the items. */
1678 static xg_list_node xg_menu_cb_list;
1680 /* Linked list of all allocated struct xg_menu_item_cb_data. Used for marking
1681 during GC. The next member points to the items. */
1682 static xg_list_node xg_menu_item_cb_list;
1684 /* Allocate and initialize CL_DATA if NULL, otherwise increase ref_count.
1685 F is the frame CL_DATA will be initialized for.
1686 HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
1688 The menu bar and all sub menus under the menu bar in a frame
1689 share the same structure, hence the reference count.
1691 Returns CL_DATA if CL_DATA is not NULL, or a pointer to a newly
1692 allocated xg_menu_cb_data if CL_DATA is NULL. */
1694 static xg_menu_cb_data *
1695 make_cl_data (cl_data, f, highlight_cb)
1696 xg_menu_cb_data *cl_data;
1697 FRAME_PTR f;
1698 GCallback highlight_cb;
1700 if (! cl_data)
1702 cl_data = (xg_menu_cb_data*) xmalloc (sizeof (*cl_data));
1703 cl_data->f = f;
1704 cl_data->menu_bar_vector = f->menu_bar_vector;
1705 cl_data->menu_bar_items_used = f->menu_bar_items_used;
1706 cl_data->highlight_cb = highlight_cb;
1707 cl_data->ref_count = 0;
1709 xg_list_insert (&xg_menu_cb_list, &cl_data->ptrs);
1712 cl_data->ref_count++;
1714 return cl_data;
1717 /* Update CL_DATA with values from frame F and with HIGHLIGHT_CB.
1718 HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
1720 When the menu bar is updated, menu items may have been added and/or
1721 removed, so menu_bar_vector and menu_bar_items_used change. We must
1722 then update CL_DATA since it is used to determine which menu
1723 item that is invoked in the menu.
1724 HIGHLIGHT_CB could change, there is no check that the same
1725 function is given when modifying a menu bar as was given when
1726 creating the menu bar. */
1728 static void
1729 update_cl_data (cl_data, f, highlight_cb)
1730 xg_menu_cb_data *cl_data;
1731 FRAME_PTR f;
1732 GCallback highlight_cb;
1734 if (cl_data)
1736 cl_data->f = f;
1737 cl_data->menu_bar_vector = f->menu_bar_vector;
1738 cl_data->menu_bar_items_used = f->menu_bar_items_used;
1739 cl_data->highlight_cb = highlight_cb;
1743 /* Decrease reference count for CL_DATA.
1744 If reference count is zero, free CL_DATA. */
1746 static void
1747 unref_cl_data (cl_data)
1748 xg_menu_cb_data *cl_data;
1750 if (cl_data && cl_data->ref_count > 0)
1752 cl_data->ref_count--;
1753 if (cl_data->ref_count == 0)
1755 xg_list_remove (&xg_menu_cb_list, &cl_data->ptrs);
1756 xfree (cl_data);
1761 /* Function that marks all lisp data during GC. */
1763 void
1764 xg_mark_data ()
1766 xg_list_node *iter;
1768 for (iter = xg_menu_cb_list.next; iter; iter = iter->next)
1769 mark_object (((xg_menu_cb_data *) iter)->menu_bar_vector);
1771 for (iter = xg_menu_item_cb_list.next; iter; iter = iter->next)
1773 xg_menu_item_cb_data *cb_data = (xg_menu_item_cb_data *) iter;
1775 if (! NILP (cb_data->help))
1776 mark_object (cb_data->help);
1781 /* Callback called when a menu item is destroyed. Used to free data.
1782 W is the widget that is being destroyed (not used).
1783 CLIENT_DATA points to the xg_menu_item_cb_data associated with the W. */
1785 static void
1786 menuitem_destroy_callback (w, client_data)
1787 GtkWidget *w;
1788 gpointer client_data;
1790 if (client_data)
1792 xg_menu_item_cb_data *data = (xg_menu_item_cb_data*) client_data;
1793 xg_list_remove (&xg_menu_item_cb_list, &data->ptrs);
1794 xfree (data);
1798 /* Callback called when the pointer enters/leaves a menu item.
1799 W is the parent of the menu item.
1800 EVENT is either an enter event or leave event.
1801 CLIENT_DATA is not used.
1803 Returns FALSE to tell GTK to keep processing this event. */
1805 static gboolean
1806 menuitem_highlight_callback (w, event, client_data)
1807 GtkWidget *w;
1808 GdkEventCrossing *event;
1809 gpointer client_data;
1811 GdkEvent ev;
1812 GtkWidget *subwidget;
1813 xg_menu_item_cb_data *data;
1815 ev.crossing = *event;
1816 subwidget = gtk_get_event_widget (&ev);
1817 data = (xg_menu_item_cb_data *) g_object_get_data (G_OBJECT (subwidget),
1818 XG_ITEM_DATA);
1819 if (data)
1821 if (! NILP (data->help) && data->cl_data->highlight_cb)
1823 gpointer call_data = event->type == GDK_LEAVE_NOTIFY ? 0 : data;
1824 GtkCallback func = (GtkCallback) data->cl_data->highlight_cb;
1825 (*func) (subwidget, call_data);
1829 return FALSE;
1832 /* Callback called when a menu is destroyed. Used to free data.
1833 W is the widget that is being destroyed (not used).
1834 CLIENT_DATA points to the xg_menu_cb_data associated with W. */
1836 static void
1837 menu_destroy_callback (w, client_data)
1838 GtkWidget *w;
1839 gpointer client_data;
1841 unref_cl_data ((xg_menu_cb_data*) client_data);
1844 /* Callback called when a menu does a grab or ungrab. That means the
1845 menu has been activated or deactivated.
1846 Used to start a timer so the small timeout the menus in GTK uses before
1847 popping down a menu is seen by Emacs (see xg_process_timeouts above).
1848 W is the widget that does the grab (not used).
1849 UNGRAB_P is TRUE if this is an ungrab, FALSE if it is a grab.
1850 CLIENT_DATA is NULL (not used). */
1852 /* Keep track of total number of grabs. */
1853 static int menu_grab_callback_cnt;
1855 static void
1856 menu_grab_callback (GtkWidget *widget,
1857 gboolean ungrab_p,
1858 gpointer client_data)
1860 if (ungrab_p) menu_grab_callback_cnt--;
1861 else menu_grab_callback_cnt++;
1863 if (menu_grab_callback_cnt > 0 && ! xg_timer) xg_start_timer ();
1864 else if (menu_grab_callback_cnt == 0 && xg_timer) xg_stop_timer ();
1867 /* Make a GTK widget that contains both UTF8_LABEL and UTF8_KEY (both
1868 must be non-NULL) and can be inserted into a menu item.
1870 Returns the GtkHBox. */
1872 static GtkWidget *
1873 make_widget_for_menu_item (utf8_label, utf8_key)
1874 char *utf8_label;
1875 char *utf8_key;
1877 GtkWidget *wlbl;
1878 GtkWidget *wkey;
1879 GtkWidget *wbox;
1881 wbox = gtk_hbox_new (FALSE, 0);
1882 wlbl = gtk_label_new (utf8_label);
1883 wkey = gtk_label_new (utf8_key);
1885 gtk_misc_set_alignment (GTK_MISC (wlbl), 0.0, 0.5);
1886 gtk_misc_set_alignment (GTK_MISC (wkey), 0.0, 0.5);
1888 gtk_box_pack_start (GTK_BOX (wbox), wlbl, TRUE, TRUE, 0);
1889 gtk_box_pack_start (GTK_BOX (wbox), wkey, FALSE, FALSE, 0);
1891 gtk_widget_set_name (wlbl, MENU_ITEM_NAME);
1892 gtk_widget_set_name (wkey, MENU_ITEM_NAME);
1893 gtk_widget_set_name (wbox, MENU_ITEM_NAME);
1895 return wbox;
1898 /* Make and return a menu item widget with the key to the right.
1899 UTF8_LABEL is the text for the menu item (GTK uses UTF8 internally).
1900 UTF8_KEY is the text representing the key binding.
1901 ITEM is the widget_value describing the menu item.
1903 GROUP is an in/out parameter. If the menu item to be created is not
1904 part of any radio menu group, *GROUP contains NULL on entry and exit.
1905 If the menu item to be created is part of a radio menu group, on entry
1906 *GROUP contains the group to use, or NULL if this is the first item
1907 in the group. On exit, *GROUP contains the radio item group.
1909 Unfortunately, keys don't line up as nicely as in Motif,
1910 but the MacOS X version doesn't either, so I guess that is OK. */
1912 static GtkWidget *
1913 make_menu_item (utf8_label, utf8_key, item, group)
1914 char *utf8_label;
1915 char *utf8_key;
1916 widget_value *item;
1917 GSList **group;
1919 GtkWidget *w;
1920 GtkWidget *wtoadd = 0;
1922 /* It has been observed that some menu items have a NULL name field.
1923 This will lead to this function being called with a NULL utf8_label.
1924 GTK crashes on that so we set a blank label. Why there is a NULL
1925 name remains to be investigated. */
1926 if (! utf8_label) utf8_label = " ";
1928 if (utf8_key)
1929 wtoadd = make_widget_for_menu_item (utf8_label, utf8_key);
1931 if (item->button_type == BUTTON_TYPE_TOGGLE)
1933 *group = NULL;
1934 if (utf8_key) w = gtk_check_menu_item_new ();
1935 else w = gtk_check_menu_item_new_with_label (utf8_label);
1936 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w), item->selected);
1938 else if (item->button_type == BUTTON_TYPE_RADIO)
1940 if (utf8_key) w = gtk_radio_menu_item_new (*group);
1941 else w = gtk_radio_menu_item_new_with_label (*group, utf8_label);
1942 *group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (w));
1943 if (item->selected)
1944 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w), TRUE);
1946 else
1948 *group = NULL;
1949 if (utf8_key) w = gtk_menu_item_new ();
1950 else w = gtk_menu_item_new_with_label (utf8_label);
1953 if (wtoadd) gtk_container_add (GTK_CONTAINER (w), wtoadd);
1954 if (! item->enabled) gtk_widget_set_sensitive (w, FALSE);
1956 return w;
1959 /* Return non-zero if LABEL specifies a separator (GTK only has one
1960 separator type) */
1962 static char* separator_names[] = {
1963 "space",
1964 "no-line",
1965 "single-line",
1966 "double-line",
1967 "single-dashed-line",
1968 "double-dashed-line",
1969 "shadow-etched-in",
1970 "shadow-etched-out",
1971 "shadow-etched-in-dash",
1972 "shadow-etched-out-dash",
1973 "shadow-double-etched-in",
1974 "shadow-double-etched-out",
1975 "shadow-double-etched-in-dash",
1976 "shadow-double-etched-out-dash",
1980 static int
1981 xg_separator_p (char *label)
1983 if (! label) return 0;
1984 else if (strlen (label) > 3
1985 && strncmp (label, "--", 2) == 0
1986 && label[2] != '-')
1988 int i;
1990 label += 2;
1991 for (i = 0; separator_names[i]; ++i)
1992 if (strcmp (label, separator_names[i]) == 0)
1993 return 1;
1995 else
1997 /* Old-style separator, maybe. It's a separator if it contains
1998 only dashes. */
1999 while (*label == '-')
2000 ++label;
2001 if (*label == 0) return 1;
2004 return 0;
2007 static int xg_detached_menus;
2009 /* Returns non-zero if there are detached menus. */
2012 xg_have_tear_offs ()
2014 return xg_detached_menus > 0;
2017 /* Callback invoked when a detached menu window is removed. Here we
2018 decrease the xg_detached_menus count.
2019 WIDGET is the top level window that is removed (the parent of the menu).
2020 CLIENT_DATA is not used. */
2022 static void
2023 tearoff_remove (widget, client_data)
2024 GtkWidget *widget;
2025 gpointer client_data;
2027 if (xg_detached_menus > 0) --xg_detached_menus;
2030 /* Callback invoked when a menu is detached. It increases the
2031 xg_detached_menus count.
2032 WIDGET is the GtkTearoffMenuItem.
2033 CLIENT_DATA is not used. */
2035 static void
2036 tearoff_activate (widget, client_data)
2037 GtkWidget *widget;
2038 gpointer client_data;
2040 GtkWidget *menu = gtk_widget_get_parent (widget);
2041 if (gtk_menu_get_tearoff_state (GTK_MENU (menu)))
2043 ++xg_detached_menus;
2044 g_signal_connect (G_OBJECT (gtk_widget_get_toplevel (widget)),
2045 "destroy",
2046 G_CALLBACK (tearoff_remove), 0);
2051 /* Create a menu item widget, and connect the callbacks.
2052 ITEM decribes the menu item.
2053 F is the frame the created menu belongs to.
2054 SELECT_CB is the callback to use when a menu item is selected.
2055 HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
2056 CL_DATA points to the callback data to be used for this menu.
2057 GROUP is an in/out parameter. If the menu item to be created is not
2058 part of any radio menu group, *GROUP contains NULL on entry and exit.
2059 If the menu item to be created is part of a radio menu group, on entry
2060 *GROUP contains the group to use, or NULL if this is the first item
2061 in the group. On exit, *GROUP contains the radio item group.
2063 Returns the created GtkWidget. */
2065 static GtkWidget *
2066 xg_create_one_menuitem (item, f, select_cb, highlight_cb, cl_data, group)
2067 widget_value *item;
2068 FRAME_PTR f;
2069 GCallback select_cb;
2070 GCallback highlight_cb;
2071 xg_menu_cb_data *cl_data;
2072 GSList **group;
2074 char *utf8_label;
2075 char *utf8_key;
2076 GtkWidget *w;
2077 xg_menu_item_cb_data *cb_data;
2079 utf8_label = get_utf8_string (item->name);
2080 utf8_key = get_utf8_string (item->key);
2082 w = make_menu_item (utf8_label, utf8_key, item, group);
2084 if (utf8_label && utf8_label != item->name) g_free (utf8_label);
2085 if (utf8_key && utf8_key != item->key) g_free (utf8_key);
2087 cb_data = xmalloc (sizeof (xg_menu_item_cb_data));
2089 xg_list_insert (&xg_menu_item_cb_list, &cb_data->ptrs);
2091 cb_data->select_id = 0;
2092 cb_data->help = item->help;
2093 cb_data->cl_data = cl_data;
2094 cb_data->call_data = item->call_data;
2096 g_signal_connect (G_OBJECT (w),
2097 "destroy",
2098 G_CALLBACK (menuitem_destroy_callback),
2099 cb_data);
2101 /* Put cb_data in widget, so we can get at it when modifying menubar */
2102 g_object_set_data (G_OBJECT (w), XG_ITEM_DATA, cb_data);
2104 /* final item, not a submenu */
2105 if (item->call_data && ! item->contents)
2107 if (select_cb)
2108 cb_data->select_id
2109 = g_signal_connect (G_OBJECT (w), "activate", select_cb, cb_data);
2112 return w;
2115 static GtkWidget *create_menus P_ ((widget_value *, FRAME_PTR, GCallback,
2116 GCallback, GCallback, int, int, int,
2117 GtkWidget *, xg_menu_cb_data *, char *));
2119 /* Create a full menu tree specified by DATA.
2120 F is the frame the created menu belongs to.
2121 SELECT_CB is the callback to use when a menu item is selected.
2122 DEACTIVATE_CB is the callback to use when a sub menu is not shown anymore.
2123 HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
2124 POP_UP_P is non-zero if we shall create a popup menu.
2125 MENU_BAR_P is non-zero if we shall create a menu bar.
2126 ADD_TEAROFF_P is non-zero if we shall add a teroff menu item. Ignored
2127 if MENU_BAR_P is non-zero.
2128 TOPMENU is the topmost GtkWidget that others shall be placed under.
2129 It may be NULL, in that case we create the appropriate widget
2130 (menu bar or menu item depending on POP_UP_P and MENU_BAR_P)
2131 CL_DATA is the callback data we shall use for this menu, or NULL
2132 if we haven't set the first callback yet.
2133 NAME is the name to give to the top level menu if this function
2134 creates it. May be NULL to not set any name.
2136 Returns the top level GtkWidget. This is TOPLEVEL if TOPLEVEL is
2137 not NULL.
2139 This function calls itself to create submenus. */
2141 static GtkWidget *
2142 create_menus (data, f, select_cb, deactivate_cb, highlight_cb,
2143 pop_up_p, menu_bar_p, add_tearoff_p, topmenu, cl_data, name)
2144 widget_value *data;
2145 FRAME_PTR f;
2146 GCallback select_cb;
2147 GCallback deactivate_cb;
2148 GCallback highlight_cb;
2149 int pop_up_p;
2150 int menu_bar_p;
2151 int add_tearoff_p;
2152 GtkWidget *topmenu;
2153 xg_menu_cb_data *cl_data;
2154 char *name;
2156 widget_value *item;
2157 GtkWidget *wmenu = topmenu;
2158 GSList *group = NULL;
2160 if (! topmenu)
2162 if (! menu_bar_p)
2164 wmenu = gtk_menu_new ();
2165 xg_set_screen (wmenu, f);
2166 /* Connect this to the menu instead of items so we get enter/leave for
2167 disabled items also. TODO: Still does not get enter/leave for
2168 disabled items in detached menus. */
2169 g_signal_connect (G_OBJECT (wmenu),
2170 "enter-notify-event",
2171 G_CALLBACK (menuitem_highlight_callback),
2172 NULL);
2173 g_signal_connect (G_OBJECT (wmenu),
2174 "leave-notify-event",
2175 G_CALLBACK (menuitem_highlight_callback),
2176 NULL);
2178 else wmenu = gtk_menu_bar_new ();
2180 /* Put cl_data on the top menu for easier access. */
2181 cl_data = make_cl_data (cl_data, f, highlight_cb);
2182 g_object_set_data (G_OBJECT (wmenu), XG_FRAME_DATA, (gpointer)cl_data);
2183 g_signal_connect (G_OBJECT (wmenu), "destroy",
2184 G_CALLBACK (menu_destroy_callback), cl_data);
2186 if (name)
2187 gtk_widget_set_name (wmenu, name);
2189 if (deactivate_cb)
2190 g_signal_connect (G_OBJECT (wmenu),
2191 "selection-done", deactivate_cb, 0);
2193 g_signal_connect (G_OBJECT (wmenu),
2194 "grab-notify", G_CALLBACK (menu_grab_callback), 0);
2197 if (! menu_bar_p && add_tearoff_p)
2199 GtkWidget *tearoff = gtk_tearoff_menu_item_new ();
2200 gtk_menu_shell_append (GTK_MENU_SHELL (wmenu), tearoff);
2202 g_signal_connect (G_OBJECT (tearoff), "activate",
2203 G_CALLBACK (tearoff_activate), 0);
2206 for (item = data; item; item = item->next)
2208 GtkWidget *w;
2210 if (pop_up_p && !item->contents && !item->call_data
2211 && !xg_separator_p (item->name))
2213 char *utf8_label;
2214 /* A title for a popup. We do the same as GTK does when
2215 creating titles, but it does not look good. */
2216 group = NULL;
2217 utf8_label = get_utf8_string (item->name);
2219 gtk_menu_set_title (GTK_MENU (wmenu), utf8_label);
2220 w = gtk_menu_item_new_with_label (utf8_label);
2221 gtk_widget_set_sensitive (w, FALSE);
2222 if (utf8_label && utf8_label != item->name) g_free (utf8_label);
2224 else if (xg_separator_p (item->name))
2226 group = NULL;
2227 /* GTK only have one separator type. */
2228 w = gtk_separator_menu_item_new ();
2230 else
2232 w = xg_create_one_menuitem (item,
2234 item->contents ? 0 : select_cb,
2235 highlight_cb,
2236 cl_data,
2237 &group);
2239 /* Create a possibly empty submenu for menu bar items, since some
2240 themes don't highlight items correctly without it. */
2241 if (item->contents || menu_bar_p)
2243 GtkWidget *submenu = create_menus (item->contents,
2245 select_cb,
2246 deactivate_cb,
2247 highlight_cb,
2250 add_tearoff_p,
2252 cl_data,
2254 gtk_menu_item_set_submenu (GTK_MENU_ITEM (w), submenu);
2258 gtk_menu_shell_append (GTK_MENU_SHELL (wmenu), w);
2259 gtk_widget_set_name (w, MENU_ITEM_NAME);
2262 return wmenu;
2265 /* Create a menubar, popup menu or dialog, depending on the TYPE argument.
2266 TYPE can be "menubar", "popup" for popup menu, or "dialog" for a dialog
2267 with some text and buttons.
2268 F is the frame the created item belongs to.
2269 NAME is the name to use for the top widget.
2270 VAL is a widget_value structure describing items to be created.
2271 SELECT_CB is the callback to use when a menu item is selected or
2272 a dialog button is pressed.
2273 DEACTIVATE_CB is the callback to use when an item is deactivated.
2274 For a menu, when a sub menu is not shown anymore, for a dialog it is
2275 called when the dialog is popped down.
2276 HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
2278 Returns the widget created. */
2280 GtkWidget *
2281 xg_create_widget (type, name, f, val,
2282 select_cb, deactivate_cb, highlight_cb)
2283 char *type;
2284 char *name;
2285 FRAME_PTR f;
2286 widget_value *val;
2287 GCallback select_cb;
2288 GCallback deactivate_cb;
2289 GCallback highlight_cb;
2291 GtkWidget *w = 0;
2292 int menu_bar_p = strcmp (type, "menubar") == 0;
2293 int pop_up_p = strcmp (type, "popup") == 0;
2295 if (strcmp (type, "dialog") == 0)
2297 w = create_dialog (val, select_cb, deactivate_cb);
2298 xg_set_screen (w, f);
2299 gtk_window_set_transient_for (GTK_WINDOW (w),
2300 GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)));
2301 gtk_window_set_destroy_with_parent (GTK_WINDOW (w), TRUE);
2302 gtk_widget_set_name (w, "emacs-dialog");
2303 gtk_window_set_modal (GTK_WINDOW (w), TRUE);
2305 else if (menu_bar_p || pop_up_p)
2307 w = create_menus (val->contents,
2309 select_cb,
2310 deactivate_cb,
2311 highlight_cb,
2312 pop_up_p,
2313 menu_bar_p,
2314 menu_bar_p,
2317 name);
2319 /* Set the cursor to an arrow for popup menus when they are mapped.
2320 This is done by default for menu bar menus. */
2321 if (pop_up_p)
2323 /* Must realize so the GdkWindow inside the widget is created. */
2324 gtk_widget_realize (w);
2325 xg_set_cursor (w, FRAME_X_DISPLAY_INFO (f)->xg_cursor);
2328 else
2330 fprintf (stderr, "bad type in xg_create_widget: %s, doing nothing\n",
2331 type);
2334 return w;
2337 /* Return the label for menu item WITEM. */
2339 static const char *
2340 xg_get_menu_item_label (witem)
2341 GtkMenuItem *witem;
2343 GtkLabel *wlabel = GTK_LABEL (gtk_bin_get_child (GTK_BIN (witem)));
2344 return gtk_label_get_label (wlabel);
2347 /* Return non-zero if the menu item WITEM has the text LABEL. */
2349 static int
2350 xg_item_label_same_p (witem, label)
2351 GtkMenuItem *witem;
2352 char *label;
2354 int is_same = 0;
2355 char *utf8_label = get_utf8_string (label);
2356 const char *old_label = witem ? xg_get_menu_item_label (witem) : 0;
2358 if (! old_label && ! utf8_label)
2359 is_same = 1;
2360 else if (old_label && utf8_label)
2361 is_same = strcmp (utf8_label, old_label) == 0;
2363 if (utf8_label && utf8_label != label) g_free (utf8_label);
2365 return is_same;
2368 /* Destroy widgets in LIST. */
2370 static void
2371 xg_destroy_widgets (list)
2372 GList *list;
2374 GList *iter;
2376 for (iter = list; iter; iter = g_list_next (iter))
2378 GtkWidget *w = GTK_WIDGET (iter->data);
2380 /* Destroying the widget will remove it from the container it is in. */
2381 gtk_widget_destroy (w);
2385 /* Update the top level names in MENUBAR (i.e. not submenus).
2386 F is the frame the menu bar belongs to.
2387 *LIST is a list with the current menu bar names (menu item widgets).
2388 ITER is the item within *LIST that shall be updated.
2389 POS is the numerical position, starting at 0, of ITER in *LIST.
2390 VAL describes what the menu bar shall look like after the update.
2391 SELECT_CB is the callback to use when a menu item is selected.
2392 HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
2393 CL_DATA points to the callback data to be used for this menu bar.
2395 This function calls itself to walk through the menu bar names. */
2397 static void
2398 xg_update_menubar (menubar, f, list, iter, pos, val,
2399 select_cb, deactivate_cb, highlight_cb, cl_data)
2400 GtkWidget *menubar;
2401 FRAME_PTR f;
2402 GList **list;
2403 GList *iter;
2404 int pos;
2405 widget_value *val;
2406 GCallback select_cb;
2407 GCallback deactivate_cb;
2408 GCallback highlight_cb;
2409 xg_menu_cb_data *cl_data;
2411 if (! iter && ! val)
2412 return;
2413 else if (iter && ! val)
2415 /* Item(s) have been removed. Remove all remaining items. */
2416 xg_destroy_widgets (iter);
2418 /* All updated. */
2419 val = 0;
2420 iter = 0;
2422 else if (! iter && val)
2424 /* Item(s) added. Add all new items in one call. */
2425 create_menus (val, f, select_cb, deactivate_cb, highlight_cb,
2426 0, 1, 0, menubar, cl_data, 0);
2428 /* All updated. */
2429 val = 0;
2430 iter = 0;
2432 /* Below this neither iter or val is NULL */
2433 else if (xg_item_label_same_p (GTK_MENU_ITEM (iter->data), val->name))
2435 /* This item is still the same, check next item. */
2436 val = val->next;
2437 iter = g_list_next (iter);
2438 ++pos;
2440 else /* This item is changed. */
2442 GtkMenuItem *witem = GTK_MENU_ITEM (iter->data);
2443 GtkMenuItem *witem2 = 0;
2444 int val_in_menubar = 0;
2445 int iter_in_new_menubar = 0;
2446 GList *iter2;
2447 widget_value *cur;
2449 /* See if the changed entry (val) is present later in the menu bar */
2450 for (iter2 = iter;
2451 iter2 && ! val_in_menubar;
2452 iter2 = g_list_next (iter2))
2454 witem2 = GTK_MENU_ITEM (iter2->data);
2455 val_in_menubar = xg_item_label_same_p (witem2, val->name);
2458 /* See if the current entry (iter) is present later in the
2459 specification for the new menu bar. */
2460 for (cur = val; cur && ! iter_in_new_menubar; cur = cur->next)
2461 iter_in_new_menubar = xg_item_label_same_p (witem, cur->name);
2463 if (val_in_menubar && ! iter_in_new_menubar)
2465 int nr = pos;
2467 /* This corresponds to:
2468 Current: A B C
2469 New: A C
2470 Remove B. */
2472 gtk_widget_ref (GTK_WIDGET (witem));
2473 gtk_container_remove (GTK_CONTAINER (menubar), GTK_WIDGET (witem));
2474 gtk_widget_destroy (GTK_WIDGET (witem));
2476 /* Must get new list since the old changed. */
2477 g_list_free (*list);
2478 *list = iter = gtk_container_get_children (GTK_CONTAINER (menubar));
2479 while (nr-- > 0) iter = g_list_next (iter);
2481 else if (! val_in_menubar && ! iter_in_new_menubar)
2483 /* This corresponds to:
2484 Current: A B C
2485 New: A X C
2486 Rename B to X. This might seem to be a strange thing to do,
2487 since if there is a menu under B it will be totally wrong for X.
2488 But consider editing a C file. Then there is a C-mode menu
2489 (corresponds to B above).
2490 If then doing C-x C-f the minibuf menu (X above) replaces the
2491 C-mode menu. When returning from the minibuffer, we get
2492 back the C-mode menu. Thus we do:
2493 Rename B to X (C-mode to minibuf menu)
2494 Rename X to B (minibuf to C-mode menu).
2495 If the X menu hasn't been invoked, the menu under B
2496 is up to date when leaving the minibuffer. */
2497 GtkLabel *wlabel = GTK_LABEL (gtk_bin_get_child (GTK_BIN (witem)));
2498 char *utf8_label = get_utf8_string (val->name);
2499 GtkWidget *submenu = gtk_menu_item_get_submenu (witem);
2501 gtk_label_set_text (wlabel, utf8_label);
2503 /* If this item has a submenu that has been detached, change
2504 the title in the WM decorations also. */
2505 if (submenu && gtk_menu_get_tearoff_state (GTK_MENU (submenu)))
2506 /* Set the title of the detached window. */
2507 gtk_menu_set_title (GTK_MENU (submenu), utf8_label);
2509 iter = g_list_next (iter);
2510 val = val->next;
2511 ++pos;
2513 else if (! val_in_menubar && iter_in_new_menubar)
2515 /* This corresponds to:
2516 Current: A B C
2517 New: A X B C
2518 Insert X. */
2520 int nr = pos;
2521 GList *group = 0;
2522 GtkWidget *w = xg_create_one_menuitem (val,
2524 select_cb,
2525 highlight_cb,
2526 cl_data,
2527 &group);
2529 /* Create a possibly empty submenu for menu bar items, since some
2530 themes don't highlight items correctly without it. */
2531 GtkWidget *submenu = create_menus (NULL, f,
2532 select_cb, deactivate_cb,
2533 highlight_cb,
2534 0, 0, 0, 0, cl_data, 0);
2535 gtk_widget_set_name (w, MENU_ITEM_NAME);
2536 gtk_menu_shell_insert (GTK_MENU_SHELL (menubar), w, pos);
2537 gtk_menu_item_set_submenu (GTK_MENU_ITEM (w), submenu);
2539 g_list_free (*list);
2540 *list = iter = gtk_container_get_children (GTK_CONTAINER (menubar));
2541 while (nr-- > 0) iter = g_list_next (iter);
2542 iter = g_list_next (iter);
2543 val = val->next;
2544 ++pos;
2546 else /* if (val_in_menubar && iter_in_new_menubar) */
2548 int nr = pos;
2549 /* This corresponds to:
2550 Current: A B C
2551 New: A C B
2552 Move C before B */
2554 gtk_widget_ref (GTK_WIDGET (witem2));
2555 gtk_container_remove (GTK_CONTAINER (menubar), GTK_WIDGET (witem2));
2556 gtk_menu_shell_insert (GTK_MENU_SHELL (menubar),
2557 GTK_WIDGET (witem2), pos);
2558 gtk_widget_unref (GTK_WIDGET (witem2));
2560 g_list_free (*list);
2561 *list = iter = gtk_container_get_children (GTK_CONTAINER (menubar));
2562 while (nr-- > 0) iter = g_list_next (iter);
2563 if (iter) iter = g_list_next (iter);
2564 val = val->next;
2565 ++pos;
2569 /* Update the rest of the menu bar. */
2570 xg_update_menubar (menubar, f, list, iter, pos, val,
2571 select_cb, deactivate_cb, highlight_cb, cl_data);
2574 /* Update the menu item W so it corresponds to VAL.
2575 SELECT_CB is the callback to use when a menu item is selected.
2576 HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
2577 CL_DATA is the data to set in the widget for menu invocation. */
2579 static void
2580 xg_update_menu_item (val, w, select_cb, highlight_cb, cl_data)
2581 widget_value *val;
2582 GtkWidget *w;
2583 GCallback select_cb;
2584 GCallback highlight_cb;
2585 xg_menu_cb_data *cl_data;
2587 GtkWidget *wchild;
2588 GtkLabel *wlbl = 0;
2589 GtkLabel *wkey = 0;
2590 char *utf8_label;
2591 char *utf8_key;
2592 const char *old_label = 0;
2593 const char *old_key = 0;
2594 xg_menu_item_cb_data *cb_data;
2596 wchild = gtk_bin_get_child (GTK_BIN (w));
2597 utf8_label = get_utf8_string (val->name);
2598 utf8_key = get_utf8_string (val->key);
2600 /* See if W is a menu item with a key. See make_menu_item above. */
2601 if (GTK_IS_HBOX (wchild))
2603 GList *list = gtk_container_get_children (GTK_CONTAINER (wchild));
2605 wlbl = GTK_LABEL (list->data);
2606 wkey = GTK_LABEL (list->next->data);
2607 g_list_free (list);
2609 if (! utf8_key)
2611 /* Remove the key and keep just the label. */
2612 gtk_widget_ref (GTK_WIDGET (wlbl));
2613 gtk_container_remove (GTK_CONTAINER (w), wchild);
2614 gtk_container_add (GTK_CONTAINER (w), GTK_WIDGET (wlbl));
2615 wkey = 0;
2619 else /* Just a label. */
2621 wlbl = GTK_LABEL (wchild);
2623 /* Check if there is now a key. */
2624 if (utf8_key)
2626 GtkWidget *wtoadd = make_widget_for_menu_item (utf8_label, utf8_key);
2627 GList *list = gtk_container_get_children (GTK_CONTAINER (wtoadd));
2629 wlbl = GTK_LABEL (list->data);
2630 wkey = GTK_LABEL (list->next->data);
2631 g_list_free (list);
2633 gtk_container_remove (GTK_CONTAINER (w), wchild);
2634 gtk_container_add (GTK_CONTAINER (w), wtoadd);
2639 if (wkey) old_key = gtk_label_get_label (wkey);
2640 if (wlbl) old_label = gtk_label_get_label (wlbl);
2642 if (wkey && utf8_key && (! old_key || strcmp (utf8_key, old_key) != 0))
2643 gtk_label_set_text (wkey, utf8_key);
2645 if (! old_label || strcmp (utf8_label, old_label) != 0)
2646 gtk_label_set_text (wlbl, utf8_label);
2648 if (utf8_key && utf8_key != val->key) g_free (utf8_key);
2649 if (utf8_label && utf8_label != val->name) g_free (utf8_label);
2651 if (! val->enabled && GTK_WIDGET_SENSITIVE (w))
2652 gtk_widget_set_sensitive (w, FALSE);
2653 else if (val->enabled && ! GTK_WIDGET_SENSITIVE (w))
2654 gtk_widget_set_sensitive (w, TRUE);
2656 cb_data = (xg_menu_item_cb_data*) g_object_get_data (G_OBJECT (w),
2657 XG_ITEM_DATA);
2658 if (cb_data)
2660 cb_data->call_data = val->call_data;
2661 cb_data->help = val->help;
2662 cb_data->cl_data = cl_data;
2664 /* We assume the callback functions don't change. */
2665 if (val->call_data && ! val->contents)
2667 /* This item shall have a select callback. */
2668 if (! cb_data->select_id)
2669 cb_data->select_id
2670 = g_signal_connect (G_OBJECT (w), "activate",
2671 select_cb, cb_data);
2673 else if (cb_data->select_id)
2675 g_signal_handler_disconnect (w, cb_data->select_id);
2676 cb_data->select_id = 0;
2681 /* Update the toggle menu item W so it corresponds to VAL. */
2683 static void
2684 xg_update_toggle_item (val, w)
2685 widget_value *val;
2686 GtkWidget *w;
2688 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w), val->selected);
2691 /* Update the radio menu item W so it corresponds to VAL. */
2693 static void
2694 xg_update_radio_item (val, w)
2695 widget_value *val;
2696 GtkWidget *w;
2698 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w), val->selected);
2701 /* Update the sub menu SUBMENU and all its children so it corresponds to VAL.
2702 SUBMENU may be NULL, in that case a new menu is created.
2703 F is the frame the menu bar belongs to.
2704 VAL describes the contents of the menu bar.
2705 SELECT_CB is the callback to use when a menu item is selected.
2706 DEACTIVATE_CB is the callback to use when a sub menu is not shown anymore.
2707 HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
2708 CL_DATA is the call back data to use for any newly created items.
2710 Returns the updated submenu widget, that is SUBMENU unless SUBMENU
2711 was NULL. */
2713 static GtkWidget *
2714 xg_update_submenu (submenu, f, val,
2715 select_cb, deactivate_cb, highlight_cb, cl_data)
2716 GtkWidget *submenu;
2717 FRAME_PTR f;
2718 widget_value *val;
2719 GCallback select_cb;
2720 GCallback deactivate_cb;
2721 GCallback highlight_cb;
2722 xg_menu_cb_data *cl_data;
2724 GtkWidget *newsub = submenu;
2725 GList *list = 0;
2726 GList *iter;
2727 widget_value *cur;
2728 int has_tearoff_p = 0;
2729 GList *first_radio = 0;
2731 if (submenu)
2732 list = gtk_container_get_children (GTK_CONTAINER (submenu));
2734 for (cur = val, iter = list;
2735 cur && iter;
2736 iter = g_list_next (iter), cur = cur->next)
2738 GtkWidget *w = GTK_WIDGET (iter->data);
2740 /* Skip tearoff items, they have no counterpart in val. */
2741 if (GTK_IS_TEAROFF_MENU_ITEM (w))
2743 has_tearoff_p = 1;
2744 iter = g_list_next (iter);
2745 if (iter) w = GTK_WIDGET (iter->data);
2746 else break;
2749 /* Remember first radio button in a group. If we get a mismatch in
2750 a radio group we must rebuild the whole group so that the connections
2751 in GTK becomes correct. */
2752 if (cur->button_type == BUTTON_TYPE_RADIO && ! first_radio)
2753 first_radio = iter;
2754 else if (cur->button_type != BUTTON_TYPE_RADIO
2755 && ! GTK_IS_RADIO_MENU_ITEM (w))
2756 first_radio = 0;
2758 if (GTK_IS_SEPARATOR_MENU_ITEM (w))
2760 if (! xg_separator_p (cur->name))
2761 break;
2763 else if (GTK_IS_CHECK_MENU_ITEM (w))
2765 if (cur->button_type != BUTTON_TYPE_TOGGLE)
2766 break;
2767 xg_update_toggle_item (cur, w);
2768 xg_update_menu_item (cur, w, select_cb, highlight_cb, cl_data);
2770 else if (GTK_IS_RADIO_MENU_ITEM (w))
2772 if (cur->button_type != BUTTON_TYPE_RADIO)
2773 break;
2774 xg_update_radio_item (cur, w);
2775 xg_update_menu_item (cur, w, select_cb, highlight_cb, cl_data);
2777 else if (GTK_IS_MENU_ITEM (w))
2779 GtkMenuItem *witem = GTK_MENU_ITEM (w);
2780 GtkWidget *sub;
2782 if (cur->button_type != BUTTON_TYPE_NONE ||
2783 xg_separator_p (cur->name))
2784 break;
2786 xg_update_menu_item (cur, w, select_cb, highlight_cb, cl_data);
2788 sub = gtk_menu_item_get_submenu (witem);
2789 if (sub && ! cur->contents)
2791 /* Not a submenu anymore. */
2792 gtk_widget_ref (sub);
2793 gtk_menu_item_remove_submenu (witem);
2794 gtk_widget_destroy (sub);
2796 else if (cur->contents)
2798 GtkWidget *nsub;
2800 nsub = xg_update_submenu (sub, f, cur->contents,
2801 select_cb, deactivate_cb,
2802 highlight_cb, cl_data);
2804 /* If this item just became a submenu, we must set it. */
2805 if (nsub != sub)
2806 gtk_menu_item_set_submenu (witem, nsub);
2809 else
2811 /* Structural difference. Remove everything from here and down
2812 in SUBMENU. */
2813 break;
2817 /* Remove widgets from first structual change. */
2818 if (iter)
2820 /* If we are adding new menu items below, we must remove from
2821 first radio button so that radio groups become correct. */
2822 if (cur && first_radio) xg_destroy_widgets (first_radio);
2823 else xg_destroy_widgets (iter);
2826 if (cur)
2828 /* More items added. Create them. */
2829 newsub = create_menus (cur,
2831 select_cb,
2832 deactivate_cb,
2833 highlight_cb,
2836 ! has_tearoff_p,
2837 submenu,
2838 cl_data,
2842 if (list) g_list_free (list);
2844 return newsub;
2847 /* Update the MENUBAR.
2848 F is the frame the menu bar belongs to.
2849 VAL describes the contents of the menu bar.
2850 If DEEP_P is non-zero, rebuild all but the top level menu names in
2851 the MENUBAR. If DEEP_P is zero, just rebuild the names in the menubar.
2852 SELECT_CB is the callback to use when a menu item is selected.
2853 DEACTIVATE_CB is the callback to use when a sub menu is not shown anymore.
2854 HIGHLIGHT_CB is the callback to call when entering/leaving menu items. */
2856 void
2857 xg_modify_menubar_widgets (menubar, f, val, deep_p,
2858 select_cb, deactivate_cb, highlight_cb)
2859 GtkWidget *menubar;
2860 FRAME_PTR f;
2861 widget_value *val;
2862 int deep_p;
2863 GCallback select_cb;
2864 GCallback deactivate_cb;
2865 GCallback highlight_cb;
2867 xg_menu_cb_data *cl_data;
2868 GList *list = gtk_container_get_children (GTK_CONTAINER (menubar));
2870 if (! list) return;
2872 cl_data = (xg_menu_cb_data*) g_object_get_data (G_OBJECT (menubar),
2873 XG_FRAME_DATA);
2875 xg_update_menubar (menubar, f, &list, list, 0, val->contents,
2876 select_cb, deactivate_cb, highlight_cb, cl_data);
2878 if (deep_p)
2880 widget_value *cur;
2882 /* Update all sub menus.
2883 We must keep the submenus (GTK menu item widgets) since the
2884 X Window in the XEvent that activates the menu are those widgets. */
2886 /* Update cl_data, menu_item things in F may have changed. */
2887 update_cl_data (cl_data, f, highlight_cb);
2889 for (cur = val->contents; cur; cur = cur->next)
2891 GList *iter;
2892 GtkWidget *sub = 0;
2893 GtkWidget *newsub;
2894 GtkMenuItem *witem;
2896 /* Find sub menu that corresponds to val and update it. */
2897 for (iter = list ; iter; iter = g_list_next (iter))
2899 witem = GTK_MENU_ITEM (iter->data);
2900 if (xg_item_label_same_p (witem, cur->name))
2902 sub = gtk_menu_item_get_submenu (witem);
2903 break;
2907 newsub = xg_update_submenu (sub,
2909 cur->contents,
2910 select_cb,
2911 deactivate_cb,
2912 highlight_cb,
2913 cl_data);
2914 /* sub may still be NULL. If we just updated non deep and added
2915 a new menu bar item, it has no sub menu yet. So we set the
2916 newly created sub menu under witem. */
2917 if (newsub != sub)
2919 xg_set_screen (newsub, f);
2920 gtk_menu_item_set_submenu (witem, newsub);
2925 g_list_free (list);
2926 gtk_widget_show_all (menubar);
2929 /* Recompute all the widgets of frame F, when the menu bar has been
2930 changed. Value is non-zero if widgets were updated. */
2933 xg_update_frame_menubar (f)
2934 FRAME_PTR f;
2936 struct x_output *x = f->output_data.x;
2937 GtkRequisition req;
2939 if (!x->menubar_widget || GTK_WIDGET_MAPPED (x->menubar_widget))
2940 return 0;
2942 BLOCK_INPUT;
2944 gtk_box_pack_start (GTK_BOX (x->vbox_widget), x->menubar_widget,
2945 FALSE, FALSE, 0);
2946 gtk_box_reorder_child (GTK_BOX (x->vbox_widget), x->menubar_widget, 0);
2948 gtk_widget_show_all (x->menubar_widget);
2949 gtk_widget_size_request (x->menubar_widget, &req);
2950 FRAME_MENUBAR_HEIGHT (f) = req.height;
2951 xg_height_changed (f);
2952 UNBLOCK_INPUT;
2954 return 1;
2957 /* Get rid of the menu bar of frame F, and free its storage.
2958 This is used when deleting a frame, and when turning off the menu bar. */
2960 void
2961 free_frame_menubar (f)
2962 FRAME_PTR f;
2964 struct x_output *x = f->output_data.x;
2966 if (x->menubar_widget)
2968 BLOCK_INPUT;
2970 gtk_container_remove (GTK_CONTAINER (x->vbox_widget), x->menubar_widget);
2971 /* The menubar and its children shall be deleted when removed from
2972 the container. */
2973 x->menubar_widget = 0;
2974 FRAME_MENUBAR_HEIGHT (f) = 0;
2975 xg_height_changed (f);
2976 UNBLOCK_INPUT;
2982 /***********************************************************************
2983 Scroll bar functions
2984 ***********************************************************************/
2987 /* Setting scroll bar values invokes the callback. Use this variable
2988 to indicate that callback should do nothing. */
2990 int xg_ignore_gtk_scrollbar;
2992 /* Xlib's `Window' fits in 32 bits. But we want to store pointers, and they
2993 may be larger than 32 bits. Keep a mapping from integer index to widget
2994 pointers to get around the 32 bit limitation. */
2996 static struct
2998 GtkWidget **widgets;
2999 int max_size;
3000 int used;
3001 } id_to_widget;
3003 /* Grow this much every time we need to allocate more */
3005 #define ID_TO_WIDGET_INCR 32
3007 /* Store the widget pointer W in id_to_widget and return the integer index. */
3009 static int
3010 xg_store_widget_in_map (w)
3011 GtkWidget *w;
3013 int i;
3015 if (id_to_widget.max_size == id_to_widget.used)
3017 int new_size = id_to_widget.max_size + ID_TO_WIDGET_INCR;
3019 id_to_widget.widgets = xrealloc (id_to_widget.widgets,
3020 sizeof (GtkWidget *)*new_size);
3022 for (i = id_to_widget.max_size; i < new_size; ++i)
3023 id_to_widget.widgets[i] = 0;
3024 id_to_widget.max_size = new_size;
3027 /* Just loop over the array and find a free place. After all,
3028 how many scroll bars are we creating? Should be a small number.
3029 The check above guarantees we will find a free place. */
3030 for (i = 0; i < id_to_widget.max_size; ++i)
3032 if (! id_to_widget.widgets[i])
3034 id_to_widget.widgets[i] = w;
3035 ++id_to_widget.used;
3037 return i;
3041 /* Should never end up here */
3042 abort ();
3045 /* Remove pointer at IDX from id_to_widget.
3046 Called when scroll bar is destroyed. */
3048 static void
3049 xg_remove_widget_from_map (idx)
3050 int idx;
3052 if (idx < id_to_widget.max_size && id_to_widget.widgets[idx] != 0)
3054 id_to_widget.widgets[idx] = 0;
3055 --id_to_widget.used;
3059 /* Get the widget pointer at IDX from id_to_widget. */
3061 static GtkWidget *
3062 xg_get_widget_from_map (idx)
3063 int idx;
3065 if (idx < id_to_widget.max_size && id_to_widget.widgets[idx] != 0)
3066 return id_to_widget.widgets[idx];
3068 return 0;
3071 /* Return the scrollbar id for X Window WID on display DPY.
3072 Return -1 if WID not in id_to_widget. */
3075 xg_get_scroll_id_for_window (dpy, wid)
3076 Display *dpy;
3077 Window wid;
3079 int idx;
3080 GtkWidget *w;
3082 w = xg_win_to_widget (dpy, wid);
3084 if (w)
3086 for (idx = 0; idx < id_to_widget.max_size; ++idx)
3087 if (id_to_widget.widgets[idx] == w)
3088 return idx;
3091 return -1;
3094 /* Callback invoked when scroll bar WIDGET is destroyed.
3095 DATA is the index into id_to_widget for WIDGET.
3096 We free pointer to last scroll bar values here and remove the index. */
3098 static void
3099 xg_gtk_scroll_destroy (widget, data)
3100 GtkWidget *widget;
3101 gpointer data;
3103 gpointer p;
3104 int id = (int) (EMACS_INT) data; /* The EMACS_INT cast avoids a warning. */
3106 p = g_object_get_data (G_OBJECT (widget), XG_LAST_SB_DATA);
3107 xfree (p);
3108 xg_remove_widget_from_map (id);
3111 /* Callback for button press/release events. Used to start timer so that
3112 the scroll bar repetition timer in GTK gets handled.
3113 Also, sets bar->dragging to Qnil when dragging (button release) is done.
3114 WIDGET is the scroll bar widget the event is for (not used).
3115 EVENT contains the event.
3116 USER_DATA points to the struct scrollbar structure.
3118 Returns FALSE to tell GTK that it shall continue propagate the event
3119 to widgets. */
3121 static gboolean
3122 scroll_bar_button_cb (widget, event, user_data)
3123 GtkWidget *widget;
3124 GdkEventButton *event;
3125 gpointer user_data;
3127 if (event->type == GDK_BUTTON_PRESS && ! xg_timer)
3128 xg_start_timer ();
3129 else if (event->type == GDK_BUTTON_RELEASE)
3131 struct scroll_bar *bar = (struct scroll_bar *) user_data;
3132 if (xg_timer) xg_stop_timer ();
3133 bar->dragging = Qnil;
3136 return FALSE;
3139 /* Create a scroll bar widget for frame F. Store the scroll bar
3140 in BAR.
3141 SCROLL_CALLBACK is the callback to invoke when the value of the
3142 bar changes.
3143 SCROLL_BAR_NAME is the name we use for the scroll bar. Can be used
3144 to set resources for the widget. */
3146 void
3147 xg_create_scroll_bar (f, bar, scroll_callback, scroll_bar_name)
3148 FRAME_PTR f;
3149 struct scroll_bar *bar;
3150 GCallback scroll_callback;
3151 char *scroll_bar_name;
3153 GtkWidget *wscroll;
3154 GtkWidget *webox;
3155 GtkObject *vadj;
3156 int scroll_id;
3158 /* Page, step increment values are not so important here, they
3159 will be corrected in x_set_toolkit_scroll_bar_thumb. */
3160 vadj = gtk_adjustment_new (XG_SB_MIN, XG_SB_MIN, XG_SB_MAX,
3161 0.1, 0.1, 0.1);
3163 wscroll = gtk_vscrollbar_new (GTK_ADJUSTMENT (vadj));
3164 webox = gtk_event_box_new ();
3165 gtk_widget_set_name (wscroll, scroll_bar_name);
3166 gtk_range_set_update_policy (GTK_RANGE (wscroll), GTK_UPDATE_CONTINUOUS);
3168 scroll_id = xg_store_widget_in_map (wscroll);
3170 g_signal_connect (G_OBJECT (wscroll),
3171 "value-changed",
3172 scroll_callback,
3173 (gpointer) bar);
3174 /* The EMACS_INT cast avoids a warning. */
3175 g_signal_connect (G_OBJECT (wscroll),
3176 "destroy",
3177 G_CALLBACK (xg_gtk_scroll_destroy),
3178 (gpointer) (EMACS_INT) scroll_id);
3180 /* Connect to button press and button release to detect if any scroll bar
3181 has the pointer. */
3182 g_signal_connect (G_OBJECT (wscroll),
3183 "button-press-event",
3184 G_CALLBACK (scroll_bar_button_cb),
3185 (gpointer) bar);
3186 g_signal_connect (G_OBJECT (wscroll),
3187 "button-release-event",
3188 G_CALLBACK (scroll_bar_button_cb),
3189 (gpointer) bar);
3191 /* The scroll bar widget does not draw on a window of its own. Instead
3192 it draws on the parent window, in this case the edit widget. So
3193 whenever the edit widget is cleared, the scroll bar needs to redraw
3194 also, which causes flicker. Put an event box between the edit widget
3195 and the scroll bar, so the scroll bar instead draws itself on the
3196 event box window. */
3197 gtk_fixed_put (GTK_FIXED (f->output_data.x->edit_widget), webox, -1, -1);
3198 gtk_container_add (GTK_CONTAINER (webox), wscroll);
3201 /* Set the cursor to an arrow. */
3202 xg_set_cursor (webox, FRAME_X_DISPLAY_INFO (f)->xg_cursor);
3204 bar->x_window = scroll_id;
3207 /* Make the scroll bar represented by SCROLLBAR_ID visible. */
3209 void
3210 xg_show_scroll_bar (scrollbar_id)
3211 int scrollbar_id;
3213 GtkWidget *w = xg_get_widget_from_map (scrollbar_id);
3214 if (w)
3215 gtk_widget_show_all (gtk_widget_get_parent (w));
3218 /* Remove the scroll bar represented by SCROLLBAR_ID from the frame F. */
3220 void
3221 xg_remove_scroll_bar (f, scrollbar_id)
3222 FRAME_PTR f;
3223 int scrollbar_id;
3225 GtkWidget *w = xg_get_widget_from_map (scrollbar_id);
3226 if (w)
3228 GtkWidget *wparent = gtk_widget_get_parent (w);
3229 gtk_widget_destroy (w);
3230 gtk_widget_destroy (wparent);
3231 SET_FRAME_GARBAGED (f);
3235 /* Update the position of the vertical scroll bar represented by SCROLLBAR_ID
3236 in frame F.
3237 TOP/LEFT are the new pixel positions where the bar shall appear.
3238 WIDTH, HEIGHT is the size in pixels the bar shall have. */
3240 void
3241 xg_update_scrollbar_pos (f, scrollbar_id, top, left, width, height)
3242 FRAME_PTR f;
3243 int scrollbar_id;
3244 int top;
3245 int left;
3246 int width;
3247 int height;
3250 GtkWidget *wscroll = xg_get_widget_from_map (scrollbar_id);
3252 if (wscroll)
3254 GtkWidget *wfixed = f->output_data.x->edit_widget;
3255 GtkWidget *wparent = gtk_widget_get_parent (wscroll);
3257 /* Move and resize to new values. */
3258 gtk_fixed_move (GTK_FIXED (wfixed), wparent, left, top);
3259 gtk_widget_set_size_request (wscroll, width, height);
3260 gtk_widget_queue_draw (wparent);
3261 gdk_window_process_all_updates ();
3262 /* GTK does not redraw until the main loop is entered again, but
3263 if there are no X events pending we will not enter it. So we sync
3264 here to get some events. */
3265 x_sync (f);
3266 SET_FRAME_GARBAGED (f);
3267 cancel_mouse_face (f);
3271 /* Set the thumb size and position of scroll bar BAR. We are currently
3272 displaying PORTION out of a whole WHOLE, and our position POSITION. */
3274 void
3275 xg_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
3276 struct scroll_bar *bar;
3277 int portion, position, whole;
3279 GtkWidget *wscroll = xg_get_widget_from_map (bar->x_window);
3281 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
3283 if (wscroll && NILP (bar->dragging))
3285 GtkAdjustment *adj;
3286 gdouble shown;
3287 gdouble top;
3288 int size, value;
3289 int new_step;
3290 int changed = 0;
3292 adj = gtk_range_get_adjustment (GTK_RANGE (wscroll));
3294 /* We do the same as for MOTIF in xterm.c, assume 30 chars per line
3295 rather than the real portion value. This makes the thumb less likely
3296 to resize and that looks better. */
3297 portion = WINDOW_TOTAL_LINES (XWINDOW (bar->window)) * 30;
3298 /* When the thumb is at the bottom, position == whole.
3299 So we need to increase `whole' to make space for the thumb. */
3300 whole += portion;
3302 if (whole <= 0)
3303 top = 0, shown = 1;
3304 else
3306 top = (gdouble) position / whole;
3307 shown = (gdouble) portion / whole;
3310 size = shown * XG_SB_RANGE;
3311 size = min (size, XG_SB_RANGE);
3312 size = max (size, 1);
3314 value = top * XG_SB_RANGE;
3315 value = min (value, XG_SB_MAX - size);
3316 value = max (value, XG_SB_MIN);
3318 /* Assume all lines are of equal size. */
3319 new_step = size / max (1, FRAME_LINES (f));
3321 if ((int) adj->page_size != size
3322 || (int) adj->step_increment != new_step)
3324 adj->page_size = size;
3325 adj->step_increment = new_step;
3326 /* Assume a page increment is about 95% of the page size */
3327 adj->page_increment = (int) (0.95*adj->page_size);
3328 changed = 1;
3331 if (changed || (int) gtk_range_get_value (GTK_RANGE (wscroll)) != value)
3333 GtkWidget *wfixed = f->output_data.x->edit_widget;
3335 BLOCK_INPUT;
3337 /* gtk_range_set_value invokes the callback. Set
3338 ignore_gtk_scrollbar to make the callback do nothing */
3339 xg_ignore_gtk_scrollbar = 1;
3341 if ((int) gtk_range_get_value (GTK_RANGE (wscroll)) != value)
3342 gtk_range_set_value (GTK_RANGE (wscroll), (gdouble)value);
3343 else if (changed)
3344 gtk_adjustment_changed (adj);
3346 xg_ignore_gtk_scrollbar = 0;
3348 UNBLOCK_INPUT;
3354 /***********************************************************************
3355 Tool bar functions
3356 ***********************************************************************/
3357 /* The key for the data we put in the GtkImage widgets. The data is
3358 the image used by Emacs. We use this to see if we need to update
3359 the GtkImage with a new image. */
3360 #define XG_TOOL_BAR_IMAGE_DATA "emacs-tool-bar-image"
3362 /* The key for storing the latest modifiers so the activate callback can
3363 get them. */
3364 #define XG_TOOL_BAR_LAST_MODIFIER "emacs-tool-bar-modifier"
3366 /* The key for storing the button widget in its proxy menu item. */
3367 #define XG_TOOL_BAR_PROXY_BUTTON "emacs-tool-bar-proxy-button"
3369 /* The key for the data we put in the GtkImage widgets. The data is
3370 the stock name used by Emacs. We use this to see if we need to update
3371 the GtkImage with a new image. */
3372 #define XG_TOOL_BAR_STOCK_NAME "emacs-tool-bar-stock-name"
3374 /* As above, but this is used for named theme widgets, as opposed to
3375 stock items. */
3376 #define XG_TOOL_BAR_ICON_NAME "emacs-tool-bar-icon-name"
3378 /* Callback function invoked when a tool bar item is pressed.
3379 W is the button widget in the tool bar that got pressed,
3380 CLIENT_DATA is an integer that is the index of the button in the
3381 tool bar. 0 is the first button. */
3383 static gboolean
3384 xg_tool_bar_button_cb (widget, event, user_data)
3385 GtkWidget *widget;
3386 GdkEventButton *event;
3387 gpointer user_data;
3389 /* Casts to avoid warnings when gpointer is 64 bits and int is 32 bits */
3390 gpointer ptr = (gpointer) (EMACS_INT) event->state;
3391 g_object_set_data (G_OBJECT (widget), XG_TOOL_BAR_LAST_MODIFIER, ptr);
3392 return FALSE;
3396 /* Callback function invoked when a tool bar item is pressed.
3397 W is the button widget in the tool bar that got pressed,
3398 CLIENT_DATA is an integer that is the index of the button in the
3399 tool bar. 0 is the first button. */
3401 static void
3402 xg_tool_bar_callback (w, client_data)
3403 GtkWidget *w;
3404 gpointer client_data;
3406 /* The EMACS_INT cast avoids a warning. */
3407 int idx = (int) (EMACS_INT) client_data;
3408 int mod = (int) (EMACS_INT) g_object_get_data (G_OBJECT (w),
3409 XG_TOOL_BAR_LAST_MODIFIER);
3411 FRAME_PTR f = (FRAME_PTR) g_object_get_data (G_OBJECT (w), XG_FRAME_DATA);
3412 Lisp_Object key, frame;
3413 struct input_event event;
3414 EVENT_INIT (event);
3416 if (! f || ! f->n_tool_bar_items || NILP (f->tool_bar_items))
3417 return;
3419 idx *= TOOL_BAR_ITEM_NSLOTS;
3421 key = AREF (f->tool_bar_items, idx + TOOL_BAR_ITEM_KEY);
3422 XSETFRAME (frame, f);
3424 /* We generate two events here. The first one is to set the prefix
3425 to `(tool_bar)', see keyboard.c. */
3426 event.kind = TOOL_BAR_EVENT;
3427 event.frame_or_window = frame;
3428 event.arg = frame;
3429 kbd_buffer_store_event (&event);
3431 event.kind = TOOL_BAR_EVENT;
3432 event.frame_or_window = frame;
3433 event.arg = key;
3434 /* Convert between the modifier bits GDK uses and the modifier bits
3435 Emacs uses. This assumes GDK and X masks are the same, which they are when
3436 this is written. */
3437 event.modifiers = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f), mod);
3438 kbd_buffer_store_event (&event);
3440 /* Return focus to the frame after we have clicked on a detached
3441 tool bar button. */
3442 Fx_focus_frame (frame);
3445 /* Callback function invoked when a tool bar item is pressed in a detached
3446 tool bar or the overflow drop down menu.
3447 We just call xg_tool_bar_callback.
3448 W is the menu item widget that got pressed,
3449 CLIENT_DATA is an integer that is the index of the button in the
3450 tool bar. 0 is the first button. */
3452 static void
3453 xg_tool_bar_proxy_callback (w, client_data)
3454 GtkWidget *w;
3455 gpointer client_data;
3457 GtkWidget *wbutton = GTK_WIDGET (g_object_get_data (G_OBJECT (w),
3458 XG_TOOL_BAR_PROXY_BUTTON));
3459 xg_tool_bar_callback (wbutton, client_data);
3463 static gboolean
3464 xg_tool_bar_help_callback P_ ((GtkWidget *w,
3465 GdkEventCrossing *event,
3466 gpointer client_data));
3468 /* This callback is called when a help is to be shown for an item in
3469 the detached tool bar when the detached tool bar it is not expanded. */
3471 static gboolean
3472 xg_tool_bar_proxy_help_callback (w, event, client_data)
3473 GtkWidget *w;
3474 GdkEventCrossing *event;
3475 gpointer client_data;
3477 GtkWidget *wbutton = GTK_WIDGET (g_object_get_data (G_OBJECT (w),
3478 XG_TOOL_BAR_PROXY_BUTTON));
3480 xg_tool_bar_help_callback (wbutton, event, client_data);
3484 /* This callback is called when a tool item should create a proxy item,
3485 such as for the overflow menu. Also called when the tool bar is detached.
3486 If we don't create a proxy menu item, the detached tool bar will be
3487 blank. */
3489 static gboolean
3490 xg_tool_bar_menu_proxy (toolitem, user_data)
3491 GtkToolItem *toolitem;
3492 gpointer user_data;
3494 GtkWidget *weventbox = gtk_bin_get_child (GTK_BIN (toolitem));
3495 GtkButton *wbutton = GTK_BUTTON (gtk_bin_get_child (GTK_BIN (weventbox)));
3496 GtkWidget *wmenuitem = gtk_image_menu_item_new_with_label ("");
3497 GtkWidget *wmenuimage;
3499 if (gtk_button_get_use_stock (wbutton))
3500 wmenuimage = gtk_image_new_from_stock (gtk_button_get_label (wbutton),
3501 GTK_ICON_SIZE_MENU);
3502 else
3504 GtkImage *wimage = GTK_IMAGE (gtk_bin_get_child (GTK_BIN (wbutton)));
3505 GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (wbutton));
3506 GtkImageType store_type = gtk_image_get_storage_type (wimage);
3508 if (store_type == GTK_IMAGE_STOCK)
3510 gchar *stock_id;
3511 gtk_image_get_stock (wimage, &stock_id, NULL);
3512 wmenuimage = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_MENU);
3514 else if (store_type == GTK_IMAGE_ICON_SET)
3516 GtkIconSet *icon_set;
3517 gtk_image_get_icon_set (wimage, &icon_set, NULL);
3518 wmenuimage = gtk_image_new_from_icon_set (icon_set,
3519 GTK_ICON_SIZE_MENU);
3521 else if (store_type == GTK_IMAGE_PIXBUF)
3523 gint width, height;
3525 if (settings &&
3526 gtk_icon_size_lookup_for_settings (settings, GTK_ICON_SIZE_MENU,
3527 &width, &height))
3529 GdkPixbuf *src_pixbuf, *dest_pixbuf;
3531 src_pixbuf = gtk_image_get_pixbuf (wimage);
3532 dest_pixbuf = gdk_pixbuf_scale_simple (src_pixbuf, width, height,
3533 GDK_INTERP_BILINEAR);
3535 wmenuimage = gtk_image_new_from_pixbuf (dest_pixbuf);
3537 else
3539 fprintf (stderr, "internal error: GTK_IMAGE_PIXBUF failed\n");
3540 abort ();
3543 else if (store_type == GTK_IMAGE_ICON_NAME)
3545 const gchar *icon_name;
3546 GtkIconSize icon_size;
3548 gtk_image_get_icon_name (wimage, &icon_name, &icon_size);
3549 wmenuimage = gtk_image_new_from_icon_name (icon_name,
3550 GTK_ICON_SIZE_MENU);
3552 else
3554 fprintf (stderr, "internal error: store_type is %d\n", store_type);
3555 abort ();
3558 if (wmenuimage)
3559 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (wmenuitem), wmenuimage);
3561 g_signal_connect (G_OBJECT (wmenuitem),
3562 "activate",
3563 G_CALLBACK (xg_tool_bar_proxy_callback),
3564 user_data);
3567 g_object_set_data (G_OBJECT (wmenuitem), XG_TOOL_BAR_PROXY_BUTTON,
3568 (gpointer) wbutton);
3569 gtk_tool_item_set_proxy_menu_item (toolitem, "Emacs toolbar item", wmenuitem);
3570 gtk_widget_set_sensitive (wmenuitem, GTK_WIDGET_SENSITIVE (wbutton));
3572 /* Use enter/leave notify to show help. We use the events
3573 rather than the GtkButton specific signals "enter" and
3574 "leave", so we can have only one callback. The event
3575 will tell us what kind of event it is. */
3576 g_signal_connect (G_OBJECT (wmenuitem),
3577 "enter-notify-event",
3578 G_CALLBACK (xg_tool_bar_proxy_help_callback),
3579 user_data);
3580 g_signal_connect (G_OBJECT (wmenuitem),
3581 "leave-notify-event",
3582 G_CALLBACK (xg_tool_bar_proxy_help_callback),
3583 user_data);
3585 return TRUE;
3588 /* This callback is called when a tool bar is detached. We must set
3589 the height of the tool bar to zero when this happens so frame sizes
3590 are correctly calculated.
3591 WBOX is the handle box widget that enables detach/attach of the tool bar.
3592 W is the tool bar widget.
3593 CLIENT_DATA is a pointer to the frame the tool bar belongs to. */
3595 static void
3596 xg_tool_bar_detach_callback (wbox, w, client_data)
3597 GtkHandleBox *wbox;
3598 GtkWidget *w;
3599 gpointer client_data;
3601 FRAME_PTR f = (FRAME_PTR) client_data;
3602 extern int x_gtk_whole_detached_tool_bar;
3604 g_object_set (G_OBJECT (w), "show-arrow", !x_gtk_whole_detached_tool_bar,
3605 NULL);
3607 if (f)
3609 FRAME_X_OUTPUT (f)->toolbar_detached = 1;
3611 /* When detaching a tool bar, not everything dissapear. There are
3612 a few pixels left that are used to drop the tool bar back into
3613 place. */
3614 FRAME_TOOLBAR_HEIGHT (f) = 4;
3615 xg_height_changed (f);
3619 /* This callback is called when a tool bar is reattached. We must set
3620 the height of the tool bar when this happens so frame sizes
3621 are correctly calculated.
3622 WBOX is the handle box widget that enables detach/attach of the tool bar.
3623 W is the tool bar widget.
3624 CLIENT_DATA is a pointer to the frame the tool bar belongs to. */
3626 static void
3627 xg_tool_bar_attach_callback (wbox, w, client_data)
3628 GtkHandleBox *wbox;
3629 GtkWidget *w;
3630 gpointer client_data;
3632 FRAME_PTR f = (FRAME_PTR) client_data;
3633 g_object_set (G_OBJECT (w), "show-arrow", TRUE, NULL);
3635 if (f)
3637 GtkRequisition req;
3639 FRAME_X_OUTPUT (f)->toolbar_detached = 0;
3641 gtk_widget_size_request (w, &req);
3642 FRAME_TOOLBAR_HEIGHT (f) = req.height;
3643 xg_height_changed (f);
3647 /* This callback is called when the mouse enters or leaves a tool bar item.
3648 It is used for displaying and hiding the help text.
3649 W is the tool bar item, a button.
3650 EVENT is either an enter event or leave event.
3651 CLIENT_DATA is an integer that is the index of the button in the
3652 tool bar. 0 is the first button.
3654 Returns FALSE to tell GTK to keep processing this event. */
3656 static gboolean
3657 xg_tool_bar_help_callback (w, event, client_data)
3658 GtkWidget *w;
3659 GdkEventCrossing *event;
3660 gpointer client_data;
3662 /* The EMACS_INT cast avoids a warning. */
3663 int idx = (int) (EMACS_INT) client_data;
3664 FRAME_PTR f = (FRAME_PTR) g_object_get_data (G_OBJECT (w), XG_FRAME_DATA);
3665 Lisp_Object help, frame;
3667 if (! f || ! f->n_tool_bar_items || NILP (f->tool_bar_items))
3668 return FALSE;
3670 if (event->type == GDK_ENTER_NOTIFY)
3672 idx *= TOOL_BAR_ITEM_NSLOTS;
3673 help = AREF (f->tool_bar_items, idx + TOOL_BAR_ITEM_HELP);
3675 if (NILP (help))
3676 help = AREF (f->tool_bar_items, idx + TOOL_BAR_ITEM_CAPTION);
3678 else
3679 help = Qnil;
3681 XSETFRAME (frame, f);
3682 kbd_buffer_store_help_event (frame, help);
3684 return FALSE;
3688 /* This callback is called when a tool bar item shall be redrawn.
3689 It modifies the expose event so that the GtkImage widget redraws the
3690 whole image. This to overcome a bug that makes GtkImage draw the image
3691 in the wrong place when it tries to redraw just a part of the image.
3692 W is the GtkImage to be redrawn.
3693 EVENT is the expose event for W.
3694 CLIENT_DATA is unused.
3696 Returns FALSE to tell GTK to keep processing this event. */
3698 static gboolean
3699 xg_tool_bar_item_expose_callback (w, event, client_data)
3700 GtkWidget *w;
3701 GdkEventExpose *event;
3702 gpointer client_data;
3704 gint width, height;
3706 gdk_drawable_get_size (event->window, &width, &height);
3708 event->area.x -= width > event->area.width ? width-event->area.width : 0;
3709 event->area.y -= height > event->area.height ? height-event->area.height : 0;
3711 event->area.x = max (0, event->area.x);
3712 event->area.y = max (0, event->area.y);
3714 event->area.width = max (width, event->area.width);
3715 event->area.height = max (height, event->area.height);
3717 return FALSE;
3720 /* Attach a tool bar to frame F. */
3722 static void
3723 xg_pack_tool_bar (f)
3724 FRAME_PTR f;
3726 struct x_output *x = f->output_data.x;
3727 int vbox_pos = x->menubar_widget ? 1 : 0;
3729 x->handlebox_widget = gtk_handle_box_new ();
3730 g_signal_connect (G_OBJECT (x->handlebox_widget), "child-detached",
3731 G_CALLBACK (xg_tool_bar_detach_callback), f);
3732 g_signal_connect (G_OBJECT (x->handlebox_widget), "child-attached",
3733 G_CALLBACK (xg_tool_bar_attach_callback), f);
3735 gtk_container_add (GTK_CONTAINER (x->handlebox_widget),
3736 x->toolbar_widget);
3738 gtk_box_pack_start (GTK_BOX (x->vbox_widget), x->handlebox_widget,
3739 FALSE, FALSE, 0);
3741 gtk_box_reorder_child (GTK_BOX (x->vbox_widget), x->handlebox_widget,
3742 vbox_pos);
3743 gtk_widget_show_all (x->handlebox_widget);
3746 /* Create a tool bar for frame F. */
3748 static void
3749 xg_create_tool_bar (f)
3750 FRAME_PTR f;
3752 struct x_output *x = f->output_data.x;
3753 GtkRequisition req;
3755 x->toolbar_widget = gtk_toolbar_new ();
3756 x->toolbar_detached = 0;
3758 gtk_widget_set_name (x->toolbar_widget, "emacs-toolbar");
3760 /* We only have icons, so override any user setting. We could
3761 use the caption property of the toolbar item (see update_frame_tool_bar
3762 below), but some of those strings are long, making the toolbar so
3763 long it does not fit on the screen. The GtkToolbar widget makes every
3764 item equal size, so the longest caption determine the size of every
3765 tool bar item. I think the creators of the GtkToolbar widget
3766 counted on 4 or 5 character long strings. */
3767 gtk_toolbar_set_style (GTK_TOOLBAR (x->toolbar_widget), GTK_TOOLBAR_ICONS);
3768 gtk_toolbar_set_orientation (GTK_TOOLBAR (x->toolbar_widget),
3769 GTK_ORIENTATION_HORIZONTAL);
3773 #define PROP(IDX) AREF (f->tool_bar_items, i * TOOL_BAR_ITEM_NSLOTS + (IDX))
3775 /* Find the right-to-left image named by RTL in the tool bar images for F.
3776 Returns IMAGE if RTL is not found. */
3778 static Lisp_Object
3779 find_rtl_image (f, image, rtl)
3780 FRAME_PTR f;
3781 Lisp_Object image;
3782 Lisp_Object rtl;
3784 int i;
3785 Lisp_Object file, rtl_name;
3786 struct gcpro gcpro1, gcpro2;
3787 GCPRO2 (file, rtl_name);
3789 rtl_name = Ffile_name_nondirectory (rtl);
3791 for (i = 0; i < f->n_tool_bar_items; ++i)
3793 Lisp_Object rtl_image = PROP (TOOL_BAR_ITEM_IMAGES);
3794 if (!NILP (file = file_for_image (rtl_image)))
3796 file = call1 (intern ("file-name-sans-extension"),
3797 Ffile_name_nondirectory (file));
3798 if (EQ (Fequal (file, rtl_name), Qt))
3800 image = rtl_image;
3801 break;
3806 return image;
3809 /* Update the tool bar for frame F. Add new buttons and remove old. */
3811 void
3812 update_frame_tool_bar (f)
3813 FRAME_PTR f;
3815 int i;
3816 GtkRequisition old_req, new_req;
3817 struct x_output *x = f->output_data.x;
3818 int hmargin = 0, vmargin = 0;
3819 GtkToolbar *wtoolbar;
3820 GtkToolItem *ti;
3821 GtkTextDirection dir;
3822 int pack_tool_bar = x->handlebox_widget == NULL;
3824 if (! FRAME_GTK_WIDGET (f))
3825 return;
3827 BLOCK_INPUT;
3829 if (INTEGERP (Vtool_bar_button_margin)
3830 && XINT (Vtool_bar_button_margin) > 0)
3832 hmargin = XFASTINT (Vtool_bar_button_margin);
3833 vmargin = XFASTINT (Vtool_bar_button_margin);
3835 else if (CONSP (Vtool_bar_button_margin))
3837 if (INTEGERP (XCAR (Vtool_bar_button_margin))
3838 && XINT (XCAR (Vtool_bar_button_margin)) > 0)
3839 hmargin = XFASTINT (XCAR (Vtool_bar_button_margin));
3841 if (INTEGERP (XCDR (Vtool_bar_button_margin))
3842 && XINT (XCDR (Vtool_bar_button_margin)) > 0)
3843 vmargin = XFASTINT (XCDR (Vtool_bar_button_margin));
3846 /* The natural size (i.e. when GTK uses 0 as margin) looks best,
3847 so take DEFAULT_TOOL_BAR_BUTTON_MARGIN to mean "default for GTK",
3848 i.e. zero. This means that margins less than
3849 DEFAULT_TOOL_BAR_BUTTON_MARGIN has no effect. */
3850 hmargin = max (0, hmargin - DEFAULT_TOOL_BAR_BUTTON_MARGIN);
3851 vmargin = max (0, vmargin - DEFAULT_TOOL_BAR_BUTTON_MARGIN);
3853 if (! x->toolbar_widget)
3854 xg_create_tool_bar (f);
3856 wtoolbar = GTK_TOOLBAR (x->toolbar_widget);
3857 gtk_widget_size_request (GTK_WIDGET (wtoolbar), &old_req);
3858 dir = gtk_widget_get_direction (x->toolbar_widget);
3860 for (i = 0; i < f->n_tool_bar_items; ++i)
3863 int enabled_p = !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P));
3864 int selected_p = !NILP (PROP (TOOL_BAR_ITEM_SELECTED_P));
3865 int idx;
3866 int img_id;
3867 int icon_size = 0;
3868 struct image *img = NULL;
3869 Lisp_Object image;
3870 Lisp_Object stock = Qnil;
3871 GtkStockItem stock_item;
3872 char *stock_name = NULL;
3873 char *icon_name = NULL;
3874 Lisp_Object rtl;
3875 GtkWidget *wbutton = NULL;
3876 GtkWidget *weventbox;
3877 Lisp_Object func = intern ("x-gtk-map-stock");
3878 Lisp_Object specified_file;
3880 ti = gtk_toolbar_get_nth_item (GTK_TOOLBAR (x->toolbar_widget), i);
3882 if (ti)
3884 weventbox = gtk_bin_get_child (GTK_BIN (ti));
3885 wbutton = gtk_bin_get_child (GTK_BIN (weventbox));
3888 image = PROP (TOOL_BAR_ITEM_IMAGES);
3890 /* Ignore invalid image specifications. */
3891 if (!valid_image_p (image))
3893 if (wbutton) gtk_widget_hide (wbutton);
3894 continue;
3897 specified_file = file_for_image (image);
3898 if (!NILP (specified_file) && EQ (Qt, Ffboundp (func)))
3899 stock = call1 (func, specified_file);
3901 if (! NILP (stock) && STRINGP (stock))
3903 stock_name = SSDATA (stock);
3904 if (stock_name[0] == 'n' && stock_name[1] == ':')
3906 GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (wtoolbar));
3907 GtkIconTheme *icon_theme = gtk_icon_theme_get_for_screen (screen);
3909 icon_name = stock_name + 2;
3910 stock_name = NULL;
3911 stock = Qnil;
3913 if (! gtk_icon_theme_has_icon (icon_theme, icon_name))
3914 icon_name = NULL;
3915 else
3916 icon_size = gtk_toolbar_get_icon_size (wtoolbar);
3918 else if (gtk_stock_lookup (SSDATA (stock), &stock_item))
3919 icon_size = gtk_toolbar_get_icon_size (wtoolbar);
3920 else
3922 stock = Qnil;
3923 stock_name = NULL;
3927 if (stock_name == NULL && icon_name == NULL)
3929 /* No stock image, or stock item not known. Try regular image. */
3931 /* If image is a vector, choose the image according to the
3932 button state. */
3933 if (dir == GTK_TEXT_DIR_RTL
3934 && !NILP (rtl = PROP (TOOL_BAR_ITEM_RTL_IMAGE))
3935 && STRINGP (rtl))
3937 image = find_rtl_image (f, image, rtl);
3940 if (VECTORP (image))
3942 if (enabled_p)
3943 idx = (selected_p
3944 ? TOOL_BAR_IMAGE_ENABLED_SELECTED
3945 : TOOL_BAR_IMAGE_ENABLED_DESELECTED);
3946 else
3947 idx = (selected_p
3948 ? TOOL_BAR_IMAGE_DISABLED_SELECTED
3949 : TOOL_BAR_IMAGE_DISABLED_DESELECTED);
3951 xassert (ASIZE (image) >= idx);
3952 image = AREF (image, idx);
3954 else
3955 idx = -1;
3957 img_id = lookup_image (f, image);
3958 img = IMAGE_FROM_ID (f, img_id);
3959 prepare_image_for_display (f, img);
3961 if (img->load_failed_p || img->pixmap == None)
3963 if (ti)
3964 gtk_widget_hide_all (GTK_WIDGET (ti));
3965 else
3967 /* Insert an empty (non-image) button */
3968 weventbox = gtk_event_box_new ();
3969 wbutton = gtk_button_new ();
3970 gtk_button_set_focus_on_click (GTK_BUTTON (wbutton), FALSE);
3971 gtk_button_set_relief (GTK_BUTTON (wbutton),
3972 GTK_RELIEF_NONE);
3973 gtk_container_add (GTK_CONTAINER (weventbox), wbutton);
3974 ti = gtk_tool_item_new ();
3975 gtk_container_add (GTK_CONTAINER (ti), weventbox);
3976 gtk_toolbar_insert (GTK_TOOLBAR (x->toolbar_widget), ti, -1);
3978 continue;
3982 if (ti == NULL)
3984 GtkWidget *w;
3985 if (stock_name)
3987 w = gtk_image_new_from_stock (stock_name, icon_size);
3988 g_object_set_data_full (G_OBJECT (w), XG_TOOL_BAR_STOCK_NAME,
3989 (gpointer) xstrdup (stock_name),
3990 (GDestroyNotify) xfree);
3992 else if (icon_name)
3994 w = gtk_image_new_from_icon_name (icon_name, icon_size);
3995 g_object_set_data_full (G_OBJECT (w), XG_TOOL_BAR_ICON_NAME,
3996 (gpointer) xstrdup (icon_name),
3997 (GDestroyNotify) xfree);
3999 else
4001 w = xg_get_image_for_pixmap (f, img, x->widget, NULL);
4002 /* Save the image so we can see if an update is needed when
4003 this function is called again. */
4004 g_object_set_data (G_OBJECT (w), XG_TOOL_BAR_IMAGE_DATA,
4005 (gpointer)img->pixmap);
4008 gtk_misc_set_padding (GTK_MISC (w), hmargin, vmargin);
4009 wbutton = gtk_button_new ();
4010 gtk_button_set_focus_on_click (GTK_BUTTON (wbutton), FALSE);
4011 gtk_button_set_relief (GTK_BUTTON (wbutton), GTK_RELIEF_NONE);
4012 gtk_container_add (GTK_CONTAINER (wbutton), w);
4013 weventbox = gtk_event_box_new ();
4014 gtk_container_add (GTK_CONTAINER (weventbox), wbutton);
4015 ti = gtk_tool_item_new ();
4016 gtk_container_add (GTK_CONTAINER (ti), weventbox);
4017 gtk_toolbar_insert (GTK_TOOLBAR (x->toolbar_widget), ti, -1);
4020 /* The EMACS_INT cast avoids a warning. */
4021 g_signal_connect (G_OBJECT (ti), "create-menu-proxy",
4022 G_CALLBACK (xg_tool_bar_menu_proxy),
4023 (gpointer) (EMACS_INT) i);
4025 g_signal_connect (G_OBJECT (wbutton), "clicked",
4026 G_CALLBACK (xg_tool_bar_callback),
4027 (gpointer) (EMACS_INT) i);
4029 gtk_widget_show_all (GTK_WIDGET (ti));
4032 g_object_set_data (G_OBJECT (weventbox), XG_FRAME_DATA, (gpointer)f);
4034 /* Catch expose events to overcome an annoying redraw bug, see
4035 comment for xg_tool_bar_item_expose_callback. */
4036 g_signal_connect (G_OBJECT (ti),
4037 "expose-event",
4038 G_CALLBACK (xg_tool_bar_item_expose_callback),
4041 gtk_widget_set_sensitive (wbutton, enabled_p);
4042 gtk_tool_item_set_homogeneous (ti, FALSE);
4044 /* Callback to save modifyer mask (Shift/Control, etc). GTK makes
4045 no distinction based on modifiers in the activate callback,
4046 so we have to do it ourselves. */
4047 g_signal_connect (wbutton, "button-release-event",
4048 G_CALLBACK (xg_tool_bar_button_cb),
4049 NULL);
4051 g_object_set_data (G_OBJECT (wbutton), XG_FRAME_DATA, (gpointer)f);
4053 /* Use enter/leave notify to show help. We use the events
4054 rather than the GtkButton specific signals "enter" and
4055 "leave", so we can have only one callback. The event
4056 will tell us what kind of event it is. */
4057 /* The EMACS_INT cast avoids a warning. */
4058 g_signal_connect (G_OBJECT (weventbox),
4059 "enter-notify-event",
4060 G_CALLBACK (xg_tool_bar_help_callback),
4061 (gpointer) (EMACS_INT) i);
4062 g_signal_connect (G_OBJECT (weventbox),
4063 "leave-notify-event",
4064 G_CALLBACK (xg_tool_bar_help_callback),
4065 (gpointer) (EMACS_INT) i);
4067 else
4069 GtkWidget *wimage = gtk_bin_get_child (GTK_BIN (wbutton));
4070 Pixmap old_img = (Pixmap)g_object_get_data (G_OBJECT (wimage),
4071 XG_TOOL_BAR_IMAGE_DATA);
4072 gpointer old_stock_name = g_object_get_data (G_OBJECT (wimage),
4073 XG_TOOL_BAR_STOCK_NAME);
4074 gpointer old_icon_name = g_object_get_data (G_OBJECT (wimage),
4075 XG_TOOL_BAR_ICON_NAME);
4076 if (stock_name &&
4077 (! old_stock_name || strcmp (old_stock_name, stock_name) != 0))
4079 gtk_image_set_from_stock (GTK_IMAGE (wimage),
4080 stock_name, icon_size);
4081 g_object_set_data_full (G_OBJECT (wimage), XG_TOOL_BAR_STOCK_NAME,
4082 (gpointer) xstrdup (stock_name),
4083 (GDestroyNotify) xfree);
4084 g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_IMAGE_DATA,
4085 NULL);
4086 g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_ICON_NAME, NULL);
4088 else if (icon_name &&
4089 (! old_icon_name || strcmp (old_icon_name, icon_name) != 0))
4091 gtk_image_set_from_icon_name (GTK_IMAGE (wimage),
4092 icon_name, icon_size);
4093 g_object_set_data_full (G_OBJECT (wimage), XG_TOOL_BAR_ICON_NAME,
4094 (gpointer) xstrdup (icon_name),
4095 (GDestroyNotify) xfree);
4096 g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_IMAGE_DATA,
4097 NULL);
4098 g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_STOCK_NAME,
4099 NULL);
4101 else if (img && old_img != img->pixmap)
4103 (void) xg_get_image_for_pixmap (f, img, x->widget, wimage);
4104 g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_IMAGE_DATA,
4105 (gpointer)img->pixmap);
4107 g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_STOCK_NAME,
4108 NULL);
4109 g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_ICON_NAME, NULL);
4112 gtk_misc_set_padding (GTK_MISC (wimage), hmargin, vmargin);
4114 gtk_widget_set_sensitive (wbutton, enabled_p);
4115 gtk_widget_show_all (GTK_WIDGET (ti));
4118 #undef PROP
4121 /* Remove buttons not longer needed. We just hide them so they
4122 can be reused later on. */
4125 ti = gtk_toolbar_get_nth_item (GTK_TOOLBAR (x->toolbar_widget), i++);
4126 if (ti) gtk_widget_hide_all (GTK_WIDGET (ti));
4127 } while (ti != NULL);
4129 new_req.height = 0;
4130 if (pack_tool_bar && f->n_tool_bar_items != 0)
4131 xg_pack_tool_bar (f);
4134 gtk_widget_size_request (GTK_WIDGET (x->toolbar_widget), &new_req);
4135 if (old_req.height != new_req.height
4136 && ! FRAME_X_OUTPUT (f)->toolbar_detached)
4138 FRAME_TOOLBAR_HEIGHT (f) = new_req.height;
4139 xg_height_changed (f);
4141 UNBLOCK_INPUT;
4144 /* Deallocate all resources for the tool bar on frame F.
4145 Remove the tool bar. */
4147 void
4148 free_frame_tool_bar (f)
4149 FRAME_PTR f;
4151 struct x_output *x = f->output_data.x;
4153 if (x->toolbar_widget)
4155 int is_packed = x->handlebox_widget != 0;
4156 BLOCK_INPUT;
4157 /* We may have created the toolbar_widget in xg_create_tool_bar, but
4158 not the x->handlebox_widget which is created in xg_pack_tool_bar. */
4159 if (is_packed)
4160 gtk_container_remove (GTK_CONTAINER (x->vbox_widget),
4161 x->handlebox_widget);
4162 else
4163 gtk_widget_destroy (x->toolbar_widget);
4165 x->toolbar_widget = 0;
4166 x->handlebox_widget = 0;
4167 FRAME_TOOLBAR_HEIGHT (f) = 0;
4168 xg_height_changed (f);
4170 UNBLOCK_INPUT;
4176 /***********************************************************************
4177 Initializing
4178 ***********************************************************************/
4179 void
4180 xg_initialize ()
4182 GtkBindingSet *binding_set;
4184 #if HAVE_XFT
4185 /* Work around a bug with corrupted data if libXft gets unloaded. This way
4186 we keep it permanently linked in. */
4187 XftInit (0);
4188 #endif
4190 gdpy_def = NULL;
4191 xg_ignore_gtk_scrollbar = 0;
4192 xg_detached_menus = 0;
4193 xg_menu_cb_list.prev = xg_menu_cb_list.next =
4194 xg_menu_item_cb_list.prev = xg_menu_item_cb_list.next = 0;
4196 id_to_widget.max_size = id_to_widget.used = 0;
4197 id_to_widget.widgets = 0;
4199 /* Remove F10 as a menu accelerator, it does not mix well with Emacs key
4200 bindings. It doesn't seem to be any way to remove properties,
4201 so we set it to VoidSymbol which in X means "no key". */
4202 gtk_settings_set_string_property (gtk_settings_get_default (),
4203 "gtk-menu-bar-accel",
4204 "VoidSymbol",
4205 EMACS_CLASS);
4207 /* Make GTK text input widgets use Emacs style keybindings. This is
4208 Emacs after all. */
4209 gtk_settings_set_string_property (gtk_settings_get_default (),
4210 "gtk-key-theme-name",
4211 "Emacs",
4212 EMACS_CLASS);
4214 /* Make dialogs close on C-g. Since file dialog inherits from
4215 dialog, this works for them also. */
4216 binding_set = gtk_binding_set_by_class (g_type_class_ref (GTK_TYPE_DIALOG));
4217 gtk_binding_entry_add_signal (binding_set, GDK_g, GDK_CONTROL_MASK,
4218 "close", 0);
4220 /* Make menus close on C-g. */
4221 binding_set = gtk_binding_set_by_class (g_type_class_ref
4222 (GTK_TYPE_MENU_SHELL));
4223 gtk_binding_entry_add_signal (binding_set, GDK_g, GDK_CONTROL_MASK,
4224 "cancel", 0);
4227 #endif /* USE_GTK */
4229 /* arch-tag: fe7104da-bc1e-4aba-9bd1-f349c528f7e3
4230 (do not change this comment) */