merge from upstream
[emacs.git] / src / gtkutil.c
blobbabf0f74b80a41a11d7aaf5d81b49cac5b267a01
1 /* Functions for creating and updating GTK widgets.
3 Copyright (C) 2003-2011 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 <signal.h>
24 #include <stdio.h>
25 #include <setjmp.h>
26 #include "lisp.h"
27 #include "xterm.h"
28 #include "blockinput.h"
29 #include "syssignal.h"
30 #include "window.h"
31 #include "gtkutil.h"
32 #include "termhooks.h"
33 #include "keyboard.h"
34 #include "charset.h"
35 #include "coding.h"
36 #include <gdk/gdkkeysyms.h>
37 #include "xsettings.h"
39 #ifdef HAVE_XFT
40 #include <X11/Xft/Xft.h>
41 #endif
43 #ifdef HAVE_GTK3
44 #include <gtk/gtkx.h>
45 #include "emacsgtkfixed.h"
46 #endif
48 #define FRAME_TOTAL_PIXEL_HEIGHT(f) \
49 (FRAME_PIXEL_HEIGHT (f) + FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f))
51 #define FRAME_TOTAL_PIXEL_WIDTH(f) \
52 (FRAME_PIXEL_WIDTH (f) + FRAME_TOOLBAR_WIDTH (f))
54 #ifndef HAVE_GTK_WIDGET_SET_HAS_WINDOW
55 #define gtk_widget_set_has_window(w, b) \
56 (gtk_fixed_set_has_window (GTK_FIXED (w), b))
57 #endif
58 #ifndef HAVE_GTK_DIALOG_GET_ACTION_AREA
59 #define gtk_dialog_get_action_area(w) ((w)->action_area)
60 #define gtk_dialog_get_content_area(w) ((w)->vbox)
61 #endif
62 #ifndef HAVE_GTK_WIDGET_GET_SENSITIVE
63 #define gtk_widget_get_sensitive(w) (GTK_WIDGET_SENSITIVE (w))
64 #endif
65 #ifndef HAVE_GTK_ADJUSTMENT_GET_PAGE_SIZE
66 #define gtk_adjustment_set_page_size(w, s) ((w)->page_size = (s))
67 #define gtk_adjustment_set_page_increment(w, s) ((w)->page_increment = (s))
68 #define gtk_adjustment_get_step_increment(w) ((w)->step_increment)
69 #define gtk_adjustment_set_step_increment(w, s) ((w)->step_increment = (s))
70 #endif
71 #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 11
72 #define remove_submenu(w) gtk_menu_item_set_submenu ((w), NULL)
73 #else
74 #define remove_submenu(w) gtk_menu_item_remove_submenu ((w))
75 #endif
77 #ifndef HAVE_GTK3
78 #ifdef USE_GTK_TOOLTIP
79 #define gdk_window_get_screen(w) gdk_drawable_get_screen (w)
80 #endif
81 #define gdk_window_get_geometry(w, a, b, c, d) \
82 gdk_window_get_geometry (w, a, b, c, d, 0)
83 #define gdk_x11_window_lookup_for_display(d, w) \
84 gdk_xid_table_lookup_for_display (d, w)
85 #ifndef GDK_KEY_g
86 #define GDK_KEY_g GDK_g
87 #endif
88 #endif
90 #define XG_BIN_CHILD(x) gtk_bin_get_child (GTK_BIN (x))
92 static void update_theme_scrollbar_width (void);
95 /***********************************************************************
96 Display handling functions
97 ***********************************************************************/
99 /* Keep track of the default display, or NULL if there is none. Emacs
100 may close all its displays. */
102 static GdkDisplay *gdpy_def;
104 /* When the GTK widget W is to be created on a display for F that
105 is not the default display, set the display for W.
106 W can be a GtkMenu or a GtkWindow widget. */
108 static void
109 xg_set_screen (GtkWidget *w, FRAME_PTR f)
111 if (FRAME_X_DISPLAY (f) != DEFAULT_GDK_DISPLAY ())
113 GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (FRAME_X_DISPLAY (f));
114 GdkScreen *gscreen = gdk_display_get_default_screen (gdpy);
116 if (GTK_IS_MENU (w))
117 gtk_menu_set_screen (GTK_MENU (w), gscreen);
118 else
119 gtk_window_set_screen (GTK_WINDOW (w), gscreen);
124 /* Open a display named by DISPLAY_NAME. The display is returned in *DPY.
125 *DPY is set to NULL if the display can't be opened.
127 Returns non-zero if display could be opened, zero if display could not
128 be opened, and less than zero if the GTK version doesn't support
129 multipe displays. */
131 void
132 xg_display_open (char *display_name, Display **dpy)
134 GdkDisplay *gdpy;
136 gdpy = gdk_display_open (display_name);
137 if (!gdpy_def && gdpy)
139 gdpy_def = gdpy;
140 gdk_display_manager_set_default_display (gdk_display_manager_get (),
141 gdpy);
144 *dpy = gdpy ? GDK_DISPLAY_XDISPLAY (gdpy) : NULL;
148 /* Close display DPY. */
150 void
151 xg_display_close (Display *dpy)
153 GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (dpy);
155 /* If this is the default display, try to change it before closing.
156 If there is no other display to use, gdpy_def is set to NULL, and
157 the next call to xg_display_open resets the default display. */
158 if (gdk_display_get_default () == gdpy)
160 struct x_display_info *dpyinfo;
161 GdkDisplay *gdpy_new = NULL;
163 /* Find another display. */
164 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
165 if (dpyinfo->display != dpy)
167 gdpy_new = gdk_x11_lookup_xdisplay (dpyinfo->display);
168 gdk_display_manager_set_default_display (gdk_display_manager_get (),
169 gdpy_new);
170 break;
172 gdpy_def = gdpy_new;
175 #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 10
176 /* GTK 2.2-2.8 has a bug that makes gdk_display_close crash (bug
177 http://bugzilla.gnome.org/show_bug.cgi?id=85715). This way we
178 can continue running, but there will be memory leaks. */
179 g_object_run_dispose (G_OBJECT (gdpy));
180 #else
181 /* This seems to be fixed in GTK 2.10. */
182 gdk_display_close (gdpy);
183 #endif
187 /***********************************************************************
188 Utility functions
189 ***********************************************************************/
190 /* The next two variables and functions are taken from lwlib. */
191 static widget_value *widget_value_free_list;
192 static int malloc_cpt;
194 /* Allocate a widget_value structure, either by taking one from the
195 widget_value_free_list or by malloc:ing a new one.
197 Return a pointer to the allocated structure. */
199 widget_value *
200 malloc_widget_value (void)
202 widget_value *wv;
203 if (widget_value_free_list)
205 wv = widget_value_free_list;
206 widget_value_free_list = wv->free_list;
207 wv->free_list = 0;
209 else
211 wv = (widget_value *) xmalloc (sizeof (widget_value));
212 malloc_cpt++;
214 memset (wv, 0, sizeof (widget_value));
215 return wv;
218 /* This is analogous to free. It frees only what was allocated
219 by malloc_widget_value, and no substructures. */
221 void
222 free_widget_value (widget_value *wv)
224 if (wv->free_list)
225 abort ();
227 if (malloc_cpt > 25)
229 /* When the number of already allocated cells is too big,
230 We free it. */
231 xfree (wv);
232 malloc_cpt--;
234 else
236 wv->free_list = widget_value_free_list;
237 widget_value_free_list = wv;
242 /* Create and return the cursor to be used for popup menus and
243 scroll bars on display DPY. */
245 GdkCursor *
246 xg_create_default_cursor (Display *dpy)
248 GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (dpy);
249 return gdk_cursor_new_for_display (gdpy, GDK_LEFT_PTR);
252 static GdkPixbuf *
253 xg_get_pixbuf_from_pixmap (FRAME_PTR f, Pixmap pix)
255 int iunused;
256 GdkPixbuf *tmp_buf;
257 Window wunused;
258 unsigned int width, height, uunused;
259 XImage *xim;
261 XGetGeometry (FRAME_X_DISPLAY (f), pix, &wunused, &iunused, &iunused,
262 &width, &height, &uunused, &uunused);
264 xim = XGetImage (FRAME_X_DISPLAY (f), pix, 0, 0, width, height,
265 ~0, XYPixmap);
266 if (!xim) return 0;
268 tmp_buf = gdk_pixbuf_new_from_data ((guchar *) xim->data,
269 GDK_COLORSPACE_RGB,
270 FALSE,
271 xim->bitmap_unit,
272 (int) width,
273 (int) height,
274 xim->bytes_per_line,
275 NULL,
276 NULL);
277 XDestroyImage (xim);
278 return tmp_buf;
281 /* Apply GMASK to GPIX and return a GdkPixbuf with an alpha channel. */
283 static GdkPixbuf *
284 xg_get_pixbuf_from_pix_and_mask (FRAME_PTR f,
285 Pixmap pix,
286 Pixmap mask)
288 int width, height;
289 GdkPixbuf *icon_buf, *tmp_buf;
291 tmp_buf = xg_get_pixbuf_from_pixmap (f, pix);
292 icon_buf = gdk_pixbuf_add_alpha (tmp_buf, FALSE, 0, 0, 0);
293 g_object_unref (G_OBJECT (tmp_buf));
295 width = gdk_pixbuf_get_width (icon_buf);
296 height = gdk_pixbuf_get_height (icon_buf);
298 if (mask)
300 GdkPixbuf *mask_buf = xg_get_pixbuf_from_pixmap (f, mask);
301 guchar *pixels = gdk_pixbuf_get_pixels (icon_buf);
302 guchar *mask_pixels = gdk_pixbuf_get_pixels (mask_buf);
303 int rowstride = gdk_pixbuf_get_rowstride (icon_buf);
304 int mask_rowstride = gdk_pixbuf_get_rowstride (mask_buf);
305 int y;
307 for (y = 0; y < height; ++y)
309 guchar *iconptr, *maskptr;
310 int x;
312 iconptr = pixels + y * rowstride;
313 maskptr = mask_pixels + y * mask_rowstride;
315 for (x = 0; x < width; ++x)
317 /* In a bitmap, RGB is either 255/255/255 or 0/0/0. Checking
318 just R is sufficient. */
319 if (maskptr[0] == 0)
320 iconptr[3] = 0; /* 0, 1, 2 is R, G, B. 3 is alpha. */
322 iconptr += rowstride/width;
323 maskptr += mask_rowstride/width;
327 g_object_unref (G_OBJECT (mask_buf));
330 return icon_buf;
333 static Lisp_Object
334 file_for_image (Lisp_Object image)
336 Lisp_Object specified_file = Qnil;
337 Lisp_Object tail;
339 for (tail = XCDR (image);
340 NILP (specified_file) && CONSP (tail) && CONSP (XCDR (tail));
341 tail = XCDR (XCDR (tail)))
342 if (EQ (XCAR (tail), QCfile))
343 specified_file = XCAR (XCDR (tail));
345 return specified_file;
348 /* For the image defined in IMG, make and return a GtkImage. For displays with
349 8 planes or less we must make a GdkPixbuf and apply the mask manually.
350 Otherwise the highlightning and dimming the tool bar code in GTK does
351 will look bad. For display with more than 8 planes we just use the
352 pixmap and mask directly. For monochrome displays, GTK doesn't seem
353 able to use external pixmaps, it looks bad whatever we do.
354 The image is defined on the display where frame F is.
355 WIDGET is used to find the GdkColormap to use for the GdkPixbuf.
356 If OLD_WIDGET is NULL, a new widget is constructed and returned.
357 If OLD_WIDGET is not NULL, that widget is modified. */
359 static GtkWidget *
360 xg_get_image_for_pixmap (FRAME_PTR f,
361 struct image *img,
362 GtkWidget *widget,
363 GtkImage *old_widget)
365 GdkPixbuf *icon_buf;
367 /* If we have a file, let GTK do all the image handling.
368 This seems to be the only way to make insensitive and activated icons
369 look good in all cases. */
370 Lisp_Object specified_file = file_for_image (img->spec);
371 Lisp_Object file;
373 /* We already loaded the image once before calling this
374 function, so this only fails if the image file has been removed.
375 In that case, use the pixmap already loaded. */
377 if (STRINGP (specified_file)
378 && STRINGP (file = x_find_image_file (specified_file)))
380 if (! old_widget)
381 old_widget = GTK_IMAGE (gtk_image_new_from_file (SSDATA (file)));
382 else
383 gtk_image_set_from_file (old_widget, SSDATA (file));
385 return GTK_WIDGET (old_widget);
388 /* No file, do the image handling ourselves. This will look very bad
389 on a monochrome display, and sometimes bad on all displays with
390 certain themes. */
392 /* This is a workaround to make icons look good on pseudo color
393 displays. Apparently GTK expects the images to have an alpha
394 channel. If they don't, insensitive and activated icons will
395 look bad. This workaround does not work on monochrome displays,
396 and is strictly not needed on true color/static color displays (i.e.
397 16 bits and higher). But we do it anyway so we get a pixbuf that is
398 not associated with the img->pixmap. The img->pixmap may be removed
399 by clearing the image cache and then the tool bar redraw fails, since
400 Gtk+ assumes the pixmap is always there. */
401 icon_buf = xg_get_pixbuf_from_pix_and_mask (f, img->pixmap, img->mask);
403 if (icon_buf)
405 if (! old_widget)
406 old_widget = GTK_IMAGE (gtk_image_new_from_pixbuf (icon_buf));
407 else
408 gtk_image_set_from_pixbuf (old_widget, icon_buf);
410 g_object_unref (G_OBJECT (icon_buf));
413 return GTK_WIDGET (old_widget);
417 /* Set CURSOR on W and all widgets W contain. We must do like this
418 for scroll bars and menu because they create widgets internally,
419 and it is those widgets that are visible. */
421 static void
422 xg_set_cursor (GtkWidget *w, GdkCursor *cursor)
424 GdkWindow *window = gtk_widget_get_window(w);
425 GList *children = gdk_window_peek_children (window);
427 gdk_window_set_cursor (window, cursor);
429 /* The scroll bar widget has more than one GDK window (had to look at
430 the source to figure this out), and there is no way to set cursor
431 on widgets in GTK. So we must set the cursor for all GDK windows.
432 Ditto for menus. */
434 for ( ; children; children = g_list_next (children))
435 gdk_window_set_cursor (GDK_WINDOW (children->data), cursor);
438 /* Insert NODE into linked LIST. */
440 static void
441 xg_list_insert (xg_list_node *list, xg_list_node *node)
443 xg_list_node *list_start = list->next;
445 if (list_start) list_start->prev = node;
446 node->next = list_start;
447 node->prev = 0;
448 list->next = node;
451 /* Remove NODE from linked LIST. */
453 static void
454 xg_list_remove (xg_list_node *list, xg_list_node *node)
456 xg_list_node *list_start = list->next;
457 if (node == list_start)
459 list->next = node->next;
460 if (list->next) list->next->prev = 0;
462 else
464 node->prev->next = node->next;
465 if (node->next) node->next->prev = node->prev;
469 /* Allocate and return a utf8 version of STR. If STR is already
470 utf8 or NULL, just return a copy of STR.
471 A new string is allocated and the caller must free the result
472 with g_free. */
474 static char *
475 get_utf8_string (const char *str)
477 char *utf8_str;
479 if (!str) return NULL;
481 /* If not UTF-8, try current locale. */
482 if (!g_utf8_validate (str, -1, NULL))
483 utf8_str = g_locale_to_utf8 (str, -1, 0, 0, 0);
484 else
485 return g_strdup (str);
487 if (!utf8_str)
489 /* Probably some control characters in str. Escape them. */
490 size_t nr_bad = 0;
491 gsize bytes_read;
492 gsize bytes_written;
493 unsigned char *p = (unsigned char *)str;
494 char *cp, *up;
495 GError *err = NULL;
497 while (! (cp = g_locale_to_utf8 ((char *)p, -1, &bytes_read,
498 &bytes_written, &err))
499 && err->code == G_CONVERT_ERROR_ILLEGAL_SEQUENCE)
501 ++nr_bad;
502 p += bytes_written+1;
503 g_error_free (err);
504 err = NULL;
507 if (err)
509 g_error_free (err);
510 err = NULL;
512 if (cp) g_free (cp);
514 up = utf8_str = xmalloc (strlen (str) + nr_bad * 4 + 1);
515 p = (unsigned char *)str;
517 while (! (cp = g_locale_to_utf8 ((char *)p, -1, &bytes_read,
518 &bytes_written, &err))
519 && err->code == G_CONVERT_ERROR_ILLEGAL_SEQUENCE)
521 strncpy (up, (char *)p, bytes_written);
522 sprintf (up + bytes_written, "\\%03o", p[bytes_written]);
523 up[bytes_written+4] = '\0';
524 up += bytes_written+4;
525 p += bytes_written+1;
526 g_error_free (err);
527 err = NULL;
530 if (cp)
532 strcat (utf8_str, cp);
533 g_free (cp);
535 if (err)
537 g_error_free (err);
538 err = NULL;
541 return utf8_str;
544 /* Check for special colors used in face spec for region face.
545 The colors are fetched from the Gtk+ theme.
546 Return 1 if color was found, 0 if not. */
549 xg_check_special_colors (struct frame *f,
550 const char *color_name,
551 XColor *color)
553 int success_p = 0;
554 int get_bg = strcmp ("gtk_selection_bg_color", color_name) == 0;
555 int get_fg = !get_bg && strcmp ("gtk_selection_fg_color", color_name) == 0;
557 if (! FRAME_GTK_WIDGET (f) || ! (get_bg || get_fg))
558 return success_p;
560 BLOCK_INPUT;
562 #ifdef HAVE_GTK3
563 GtkStyleContext *gsty
564 = gtk_widget_get_style_context (FRAME_GTK_OUTER_WIDGET (f));
565 GdkRGBA col;
566 char buf[64];
567 int state = GTK_STATE_FLAG_SELECTED|GTK_STATE_FLAG_FOCUSED;
568 if (get_fg)
569 gtk_style_context_get_color (gsty, state, &col);
570 else
571 gtk_style_context_get_background_color (gsty, state, &col);
573 sprintf (buf, "rgbi:%lf/%lf/%lf", col.red, col.green, col.blue);
574 success_p = XParseColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
575 buf, color);
576 #else
577 GtkStyle *gsty = gtk_widget_get_style (FRAME_GTK_WIDGET (f));
578 GdkColor *grgb = get_bg
579 ? &gsty->bg[GTK_STATE_SELECTED]
580 : &gsty->fg[GTK_STATE_SELECTED];
582 color->red = grgb->red;
583 color->green = grgb->green;
584 color->blue = grgb->blue;
585 color->pixel = grgb->pixel;
586 success_p = 1;
587 #endif
590 UNBLOCK_INPUT;
591 return success_p;
596 /***********************************************************************
597 Tooltips
598 ***********************************************************************/
599 /* Gtk+ calls this callback when the parent of our tooltip dummy changes.
600 We use that to pop down the tooltip. This happens if Gtk+ for some
601 reason wants to change or hide the tooltip. */
603 #ifdef USE_GTK_TOOLTIP
605 static void
606 hierarchy_ch_cb (GtkWidget *widget,
607 GtkWidget *previous_toplevel,
608 gpointer user_data)
610 FRAME_PTR f = (FRAME_PTR) user_data;
611 struct x_output *x = f->output_data.x;
612 GtkWidget *top = gtk_widget_get_toplevel (x->ttip_lbl);
614 if (! top || ! GTK_IS_WINDOW (top))
615 gtk_widget_hide (previous_toplevel);
618 /* Callback called when Gtk+ thinks a tooltip should be displayed.
619 We use it to get the tooltip window and the tooltip widget so
620 we can manipulate the ourselves.
622 Return FALSE ensures that the tooltip is not shown. */
624 static gboolean
625 qttip_cb (GtkWidget *widget,
626 gint xpos,
627 gint ypos,
628 gboolean keyboard_mode,
629 GtkTooltip *tooltip,
630 gpointer user_data)
632 FRAME_PTR f = (FRAME_PTR) user_data;
633 struct x_output *x = f->output_data.x;
634 if (x->ttip_widget == NULL)
636 g_object_set (G_OBJECT (widget), "has-tooltip", FALSE, NULL);
637 x->ttip_widget = tooltip;
638 g_object_ref (G_OBJECT (tooltip));
639 x->ttip_lbl = gtk_label_new ("");
640 g_object_ref (G_OBJECT (x->ttip_lbl));
641 gtk_tooltip_set_custom (tooltip, x->ttip_lbl);
642 x->ttip_window = GTK_WINDOW (gtk_widget_get_toplevel (x->ttip_lbl));
643 /* ATK needs an empty title for some reason. */
644 gtk_window_set_title (x->ttip_window, "");
645 /* Realize so we can safely get screen later on. */
646 gtk_widget_realize (GTK_WIDGET (x->ttip_window));
647 gtk_widget_realize (x->ttip_lbl);
649 g_signal_connect (x->ttip_lbl, "hierarchy-changed",
650 G_CALLBACK (hierarchy_ch_cb), f);
652 return FALSE;
655 #endif /* USE_GTK_TOOLTIP */
657 /* Prepare a tooltip to be shown, i.e. calculate WIDTH and HEIGHT.
658 Return zero if no system tooltip available, non-zero otherwise. */
661 xg_prepare_tooltip (FRAME_PTR f,
662 Lisp_Object string,
663 int *width,
664 int *height)
666 #ifndef USE_GTK_TOOLTIP
667 return 0;
668 #else
669 struct x_output *x = f->output_data.x;
670 GtkWidget *widget;
671 GdkWindow *gwin;
672 GdkScreen *screen;
673 GtkSettings *settings;
674 gboolean tt_enabled = TRUE;
675 GtkRequisition req;
676 Lisp_Object encoded_string;
678 if (!x->ttip_lbl) return 0;
680 BLOCK_INPUT;
681 encoded_string = ENCODE_UTF_8 (string);
682 widget = GTK_WIDGET (x->ttip_lbl);
683 gwin = gtk_widget_get_window (GTK_WIDGET (x->ttip_window));
684 screen = gdk_window_get_screen (gwin);
685 settings = gtk_settings_get_for_screen (screen);
686 g_object_get (settings, "gtk-enable-tooltips", &tt_enabled, NULL);
687 if (tt_enabled)
689 g_object_set (settings, "gtk-enable-tooltips", FALSE, NULL);
690 /* Record that we disabled it so it can be enabled again. */
691 g_object_set_data (G_OBJECT (x->ttip_window), "restore-tt",
692 (gpointer)f);
695 /* Prevent Gtk+ from hiding tooltip on mouse move and such. */
696 g_object_set_data (G_OBJECT
697 (gtk_widget_get_display (GTK_WIDGET (x->ttip_window))),
698 "gdk-display-current-tooltip", NULL);
700 /* Put out dummy widget in so we can get callbacks for unrealize and
701 hierarchy-changed. */
702 gtk_tooltip_set_custom (x->ttip_widget, widget);
704 gtk_tooltip_set_text (x->ttip_widget, SSDATA (encoded_string));
705 gtk_widget_get_preferred_size (GTK_WIDGET (x->ttip_window), NULL, &req);
706 if (width) *width = req.width;
707 if (height) *height = req.height;
709 UNBLOCK_INPUT;
711 return 1;
712 #endif /* USE_GTK_TOOLTIP */
715 /* Show the tooltip at ROOT_X and ROOT_Y.
716 xg_prepare_tooltip must have been called before this function. */
718 void
719 xg_show_tooltip (FRAME_PTR f, int root_x, int root_y)
721 #ifdef USE_GTK_TOOLTIP
722 struct x_output *x = f->output_data.x;
723 if (x->ttip_window)
725 BLOCK_INPUT;
726 gtk_window_move (x->ttip_window, root_x, root_y);
727 gtk_widget_show_all (GTK_WIDGET (x->ttip_window));
728 UNBLOCK_INPUT;
730 #endif
733 /* Hide tooltip if shown. Do nothing if not shown.
734 Return non-zero if tip was hidden, non-ero if not (i.e. not using
735 system tooltips). */
738 xg_hide_tooltip (FRAME_PTR f)
740 int ret = 0;
741 #ifdef USE_GTK_TOOLTIP
742 if (f->output_data.x->ttip_window)
744 GtkWindow *win = f->output_data.x->ttip_window;
745 BLOCK_INPUT;
746 gtk_widget_hide (GTK_WIDGET (win));
748 if (g_object_get_data (G_OBJECT (win), "restore-tt"))
750 GdkWindow *gwin = gtk_widget_get_window (GTK_WIDGET (win));
751 GdkScreen *screen = gdk_window_get_screen (gwin);
752 GtkSettings *settings = gtk_settings_get_for_screen (screen);
753 g_object_set (settings, "gtk-enable-tooltips", TRUE, NULL);
755 UNBLOCK_INPUT;
757 ret = 1;
759 #endif
760 return ret;
764 /***********************************************************************
765 General functions for creating widgets, resizing, events, e.t.c.
766 ***********************************************************************/
768 /* Make a geometry string and pass that to GTK. It seems this is the
769 only way to get geometry position right if the user explicitly
770 asked for a position when starting Emacs.
771 F is the frame we shall set geometry for. */
773 static void
774 xg_set_geometry (FRAME_PTR f)
776 if (f->size_hint_flags & (USPosition | PPosition))
778 int left = f->left_pos;
779 int xneg = f->size_hint_flags & XNegative;
780 int top = f->top_pos;
781 int yneg = f->size_hint_flags & YNegative;
782 char geom_str[32];
784 if (xneg)
785 left = -left;
786 if (yneg)
787 top = -top;
789 sprintf (geom_str, "=%dx%d%c%d%c%d",
790 FRAME_PIXEL_WIDTH (f),
791 FRAME_PIXEL_HEIGHT (f),
792 (xneg ? '-' : '+'), left,
793 (yneg ? '-' : '+'), top);
795 if (!gtk_window_parse_geometry (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
796 geom_str))
797 fprintf (stderr, "Failed to parse: '%s'\n", geom_str);
801 /* Clear under internal border if any. As we use a mix of Gtk+ and X calls
802 and use a GtkFixed widget, this doesn't happen automatically. */
804 static void
805 xg_clear_under_internal_border (FRAME_PTR f)
807 if (FRAME_INTERNAL_BORDER_WIDTH (f) > 0)
809 GtkWidget *wfixed = f->output_data.x->edit_widget;
810 gtk_widget_queue_draw (wfixed);
811 gdk_window_process_all_updates ();
812 x_clear_area (FRAME_X_DISPLAY (f),
813 FRAME_X_WINDOW (f),
814 0, 0,
815 FRAME_PIXEL_WIDTH (f),
816 FRAME_INTERNAL_BORDER_WIDTH (f), 0);
817 x_clear_area (FRAME_X_DISPLAY (f),
818 FRAME_X_WINDOW (f),
819 0, 0,
820 FRAME_INTERNAL_BORDER_WIDTH (f),
821 FRAME_PIXEL_HEIGHT (f), 0);
822 x_clear_area (FRAME_X_DISPLAY (f),
823 FRAME_X_WINDOW (f),
824 0, FRAME_PIXEL_HEIGHT (f) - FRAME_INTERNAL_BORDER_WIDTH (f),
825 FRAME_PIXEL_WIDTH (f),
826 FRAME_INTERNAL_BORDER_WIDTH (f), 0);
827 x_clear_area (FRAME_X_DISPLAY (f),
828 FRAME_X_WINDOW (f),
829 FRAME_PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH (f),
831 FRAME_INTERNAL_BORDER_WIDTH (f),
832 FRAME_PIXEL_HEIGHT (f), 0);
836 /* Function to handle resize of our frame. As we have a Gtk+ tool bar
837 and a Gtk+ menu bar, we get resize events for the edit part of the
838 frame only. We let Gtk+ deal with the Gtk+ parts.
839 F is the frame to resize.
840 PIXELWIDTH, PIXELHEIGHT is the new size in pixels. */
842 void
843 xg_frame_resized (FRAME_PTR f, int pixelwidth, int pixelheight)
845 int rows, columns;
847 if (pixelwidth == -1 && pixelheight == -1)
849 if (FRAME_GTK_WIDGET (f) && gtk_widget_get_mapped (FRAME_GTK_WIDGET (f)))
850 gdk_window_get_geometry (gtk_widget_get_window (FRAME_GTK_WIDGET (f)),
851 0, 0,
852 &pixelwidth, &pixelheight);
853 else return;
857 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, pixelheight);
858 columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, pixelwidth);
860 if (columns != FRAME_COLS (f)
861 || rows != FRAME_LINES (f)
862 || pixelwidth != FRAME_PIXEL_WIDTH (f)
863 || pixelheight != FRAME_PIXEL_HEIGHT (f))
865 FRAME_PIXEL_WIDTH (f) = pixelwidth;
866 FRAME_PIXEL_HEIGHT (f) = pixelheight;
868 xg_clear_under_internal_border (f);
869 change_frame_size (f, rows, columns, 0, 1, 0);
870 SET_FRAME_GARBAGED (f);
871 cancel_mouse_face (f);
875 /* Resize the outer window of frame F after chainging the height.
876 COLUMNS/ROWS is the size the edit area shall have after the resize. */
878 void
879 xg_frame_set_char_size (FRAME_PTR f, int cols, int rows)
881 int pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows)
882 + FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f);
883 int pixelwidth;
885 if (FRAME_PIXEL_HEIGHT (f) == 0)
886 return;
888 /* Take into account the size of the scroll bar. Always use the
889 number of columns occupied by the scroll bar here otherwise we
890 might end up with a frame width that is not a multiple of the
891 frame's character width which is bad for vertically split
892 windows. */
893 f->scroll_bar_actual_width
894 = FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f);
896 compute_fringe_widths (f, 0);
898 /* FRAME_TEXT_COLS_TO_PIXEL_WIDTH uses scroll_bar_actual_width, so call it
899 after calculating that value. */
900 pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, cols)
901 + FRAME_TOOLBAR_WIDTH (f);
904 /* Do this before resize, as we don't know yet if we will be resized. */
905 xg_clear_under_internal_border (f);
907 /* Must resize our top level widget. Font size may have changed,
908 but not rows/cols. */
909 gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
910 pixelwidth, pixelheight);
911 x_wm_set_size_hint (f, 0, 0);
913 SET_FRAME_GARBAGED (f);
914 cancel_mouse_face (f);
916 /* We can not call change_frame_size for a mapped frame,
917 we can not set pixel width/height either. The window manager may
918 override our resize request, XMonad does this all the time.
919 The best we can do is try to sync, so lisp code sees the updated
920 size as fast as possible.
921 For unmapped windows, we can set rows/cols. When
922 the frame is mapped again we will (hopefully) get the correct size. */
923 if (f->async_visible)
925 /* Must call this to flush out events */
926 (void)gtk_events_pending ();
927 gdk_flush ();
928 x_wait_for_event (f, ConfigureNotify);
930 else
932 change_frame_size (f, rows, cols, 0, 1, 0);
933 FRAME_PIXEL_WIDTH (f) = pixelwidth;
934 FRAME_PIXEL_HEIGHT (f) = pixelheight;
938 /* Handle height/width changes (i.e. add/remove/move menu/toolbar).
939 The policy is to keep the number of editable lines. */
941 static void
942 xg_height_or_width_changed (FRAME_PTR f)
944 gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
945 FRAME_TOTAL_PIXEL_WIDTH (f),
946 FRAME_TOTAL_PIXEL_HEIGHT (f));
947 f->output_data.x->hint_flags = 0;
948 x_wm_set_size_hint (f, 0, 0);
951 /* Convert an X Window WSESC on display DPY to its corresponding GtkWidget.
952 Must be done like this, because GtkWidget:s can have "hidden"
953 X Window that aren't accessible.
955 Return 0 if no widget match WDESC. */
957 GtkWidget *
958 xg_win_to_widget (Display *dpy, Window wdesc)
960 gpointer gdkwin;
961 GtkWidget *gwdesc = 0;
963 BLOCK_INPUT;
965 gdkwin = gdk_x11_window_lookup_for_display (gdk_x11_lookup_xdisplay (dpy),
966 wdesc);
967 if (gdkwin)
969 GdkEvent event;
970 event.any.window = gdkwin;
971 gwdesc = gtk_get_event_widget (&event);
974 UNBLOCK_INPUT;
975 return gwdesc;
978 /* Set the background of widget W to PIXEL. */
980 static void
981 xg_set_widget_bg (FRAME_PTR f, GtkWidget *w, long unsigned int pixel)
983 #ifdef HAVE_GTK3
984 GdkRGBA bg;
985 XColor xbg;
986 xbg.pixel = pixel;
987 if (XQueryColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &xbg))
989 bg.red = (double)xbg.red/65536.0;
990 bg.green = (double)xbg.green/65536.0;
991 bg.blue = (double)xbg.blue/65536.0;
992 bg.alpha = 1.0;
993 gtk_widget_override_background_color (w, GTK_STATE_FLAG_NORMAL, &bg);
995 #else
996 GdkColor bg;
997 GdkColormap *map = gtk_widget_get_colormap (w);
998 gdk_colormap_query_color (map, pixel, &bg);
999 gtk_widget_modify_bg (FRAME_GTK_WIDGET (f), GTK_STATE_NORMAL, &bg);
1000 #endif
1003 /* Callback called when the gtk theme changes.
1004 We notify lisp code so it can fix faces used for region for example. */
1006 static void
1007 style_changed_cb (GObject *go,
1008 GParamSpec *spec,
1009 gpointer user_data)
1011 struct input_event event;
1012 GdkDisplay *gdpy = (GdkDisplay *) user_data;
1013 const char *display_name = gdk_display_get_name (gdpy);
1014 Display *dpy = GDK_DISPLAY_XDISPLAY (gdpy);
1016 EVENT_INIT (event);
1017 event.kind = CONFIG_CHANGED_EVENT;
1018 event.frame_or_window = make_string (display_name, strlen (display_name));
1019 /* Theme doesn't change often, so intern is called seldom. */
1020 event.arg = intern ("theme-name");
1021 kbd_buffer_store_event (&event);
1023 update_theme_scrollbar_width ();
1025 /* If scroll bar width changed, we need set the new size on all frames
1026 on this display. */
1027 if (dpy)
1029 Lisp_Object rest, frame;
1030 FOR_EACH_FRAME (rest, frame)
1032 FRAME_PTR f = XFRAME (frame);
1033 if (FRAME_X_DISPLAY (f) == dpy)
1035 x_set_scroll_bar_default_width (f);
1036 xg_frame_set_char_size (f, FRAME_COLS (f), FRAME_LINES (f));
1042 /* Called when a delete-event occurs on WIDGET. */
1044 static gboolean
1045 delete_cb (GtkWidget *widget,
1046 GdkEvent *event,
1047 gpointer user_data)
1049 #ifdef HAVE_GTK3
1050 /* The event doesn't arrive in the normal event loop. Send event
1051 here. */
1052 FRAME_PTR f = (FRAME_PTR) user_data;
1053 struct input_event ie;
1055 EVENT_INIT (ie);
1056 ie.kind = DELETE_WINDOW_EVENT;
1057 XSETFRAME (ie.frame_or_window, f);
1058 kbd_buffer_store_event (&ie);
1059 #endif
1061 return TRUE;
1064 /* Create and set up the GTK widgets for frame F.
1065 Return 0 if creation failed, non-zero otherwise. */
1072 xg_create_frame_widgets (FRAME_PTR f)
1074 GtkWidget *wtop;
1075 GtkWidget *wvbox, *whbox;
1076 GtkWidget *wfixed;
1077 GtkRcStyle *style;
1078 char *title = 0;
1080 BLOCK_INPUT;
1082 if (FRAME_X_EMBEDDED_P (f))
1083 wtop = gtk_plug_new (f->output_data.x->parent_desc);
1084 else
1085 wtop = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1087 xg_set_screen (wtop, f);
1089 wvbox = gtk_vbox_new (FALSE, 0);
1090 whbox = gtk_hbox_new (FALSE, 0);
1092 #ifdef HAVE_GTK3
1093 f->gwfixed = wfixed = emacs_fixed_new ();
1094 #else
1095 f->gwfixed = wfixed = gtk_fixed_new ();
1096 #endif
1098 if (! wtop || ! wvbox || ! whbox || ! wfixed)
1100 if (wtop) gtk_widget_destroy (wtop);
1101 if (wvbox) gtk_widget_destroy (wvbox);
1102 if (whbox) gtk_widget_destroy (whbox);
1103 if (wfixed) gtk_widget_destroy (wfixed);
1105 UNBLOCK_INPUT;
1106 return 0;
1109 /* Use same names as the Xt port does. I.e. Emacs.pane.emacs by default */
1110 gtk_widget_set_name (wtop, EMACS_CLASS);
1111 gtk_widget_set_name (wvbox, "pane");
1112 gtk_widget_set_name (wfixed, SSDATA (Vx_resource_name));
1114 /* If this frame has a title or name, set it in the title bar. */
1115 if (! NILP (f->title)) title = SSDATA (ENCODE_UTF_8 (f->title));
1116 else if (! NILP (f->name)) title = SSDATA (ENCODE_UTF_8 (f->name));
1118 if (title) gtk_window_set_title (GTK_WINDOW (wtop), title);
1120 FRAME_GTK_OUTER_WIDGET (f) = wtop;
1121 FRAME_GTK_WIDGET (f) = wfixed;
1122 f->output_data.x->vbox_widget = wvbox;
1123 f->output_data.x->hbox_widget = whbox;
1125 gtk_widget_set_has_window (wfixed, TRUE);
1127 gtk_container_add (GTK_CONTAINER (wtop), wvbox);
1128 gtk_box_pack_start (GTK_BOX (wvbox), whbox, TRUE, TRUE, 0);
1129 gtk_box_pack_start (GTK_BOX (whbox), wfixed, TRUE, TRUE, 0);
1131 if (FRAME_EXTERNAL_TOOL_BAR (f))
1132 update_frame_tool_bar (f);
1134 /* We don't want this widget double buffered, because we draw on it
1135 with regular X drawing primitives, so from a GTK/GDK point of
1136 view, the widget is totally blank. When an expose comes, this
1137 will make the widget blank, and then Emacs redraws it. This flickers
1138 a lot, so we turn off double buffering. */
1139 gtk_widget_set_double_buffered (wfixed, FALSE);
1141 gtk_window_set_wmclass (GTK_WINDOW (wtop),
1142 SSDATA (Vx_resource_name),
1143 SSDATA (Vx_resource_class));
1145 /* Add callback to do nothing on WM_DELETE_WINDOW. The default in
1146 GTK is to destroy the widget. We want Emacs to do that instead. */
1147 g_signal_connect (G_OBJECT (wtop), "delete-event",
1148 G_CALLBACK (delete_cb), f);
1150 /* Convert our geometry parameters into a geometry string
1151 and specify it.
1152 GTK will itself handle calculating the real position this way. */
1153 xg_set_geometry (f);
1154 f->win_gravity
1155 = gtk_window_get_gravity (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)));
1157 gtk_widget_add_events (wfixed,
1158 GDK_POINTER_MOTION_MASK
1159 | GDK_EXPOSURE_MASK
1160 | GDK_BUTTON_PRESS_MASK
1161 | GDK_BUTTON_RELEASE_MASK
1162 | GDK_KEY_PRESS_MASK
1163 | GDK_ENTER_NOTIFY_MASK
1164 | GDK_LEAVE_NOTIFY_MASK
1165 | GDK_FOCUS_CHANGE_MASK
1166 | GDK_STRUCTURE_MASK
1167 | GDK_VISIBILITY_NOTIFY_MASK);
1169 /* Must realize the windows so the X window gets created. It is used
1170 by callers of this function. */
1171 gtk_widget_realize (wfixed);
1172 FRAME_X_WINDOW (f) = GTK_WIDGET_TO_X_WIN (wfixed);
1174 /* Since GTK clears its window by filling with the background color,
1175 we must keep X and GTK background in sync. */
1176 xg_set_widget_bg (f, wfixed, FRAME_BACKGROUND_PIXEL (f));
1178 #ifndef HAVE_GTK3
1179 /* Also, do not let any background pixmap to be set, this looks very
1180 bad as Emacs overwrites the background pixmap with its own idea
1181 of background color. */
1182 style = gtk_widget_get_modifier_style (wfixed);
1184 /* Must use g_strdup because gtk_widget_modify_style does g_free. */
1185 style->bg_pixmap_name[GTK_STATE_NORMAL] = g_strdup ("<none>");
1186 gtk_widget_modify_style (wfixed, style);
1187 #else
1188 gtk_widget_set_can_focus (wfixed, TRUE);
1189 gtk_window_set_resizable (GTK_WINDOW (wtop), TRUE);
1190 #endif
1192 #ifdef USE_GTK_TOOLTIP
1193 /* Steal a tool tip window we can move ourselves. */
1194 f->output_data.x->ttip_widget = 0;
1195 f->output_data.x->ttip_lbl = 0;
1196 f->output_data.x->ttip_window = 0;
1197 gtk_widget_set_tooltip_text (wtop, "Dummy text");
1198 g_signal_connect (wtop, "query-tooltip", G_CALLBACK (qttip_cb), f);
1199 #endif
1202 GdkScreen *screen = gtk_widget_get_screen (wtop);
1203 GtkSettings *gs = gtk_settings_get_for_screen (screen);
1204 /* Only connect this signal once per screen. */
1205 if (! g_signal_handler_find (G_OBJECT (gs),
1206 G_SIGNAL_MATCH_FUNC,
1207 0, 0, 0,
1208 G_CALLBACK (style_changed_cb),
1211 g_signal_connect (G_OBJECT (gs), "notify::gtk-theme-name",
1212 G_CALLBACK (style_changed_cb),
1213 gdk_screen_get_display (screen));
1217 UNBLOCK_INPUT;
1219 return 1;
1222 void
1223 xg_free_frame_widgets (FRAME_PTR f)
1225 if (FRAME_GTK_OUTER_WIDGET (f))
1227 #ifdef USE_GTK_TOOLTIP
1228 struct x_output *x = f->output_data.x;
1229 #endif
1230 gtk_widget_destroy (FRAME_GTK_OUTER_WIDGET (f));
1231 FRAME_X_WINDOW (f) = 0; /* Set to avoid XDestroyWindow in xterm.c */
1232 FRAME_GTK_OUTER_WIDGET (f) = 0;
1233 #ifdef USE_GTK_TOOLTIP
1234 if (x->ttip_lbl)
1235 gtk_widget_destroy (x->ttip_lbl);
1236 if (x->ttip_widget)
1237 g_object_unref (G_OBJECT (x->ttip_widget));
1238 #endif
1242 /* Set the normal size hints for the window manager, for frame F.
1243 FLAGS is the flags word to use--or 0 meaning preserve the flags
1244 that the window now has.
1245 If USER_POSITION is nonzero, we set the User Position
1246 flag (this is useful when FLAGS is 0). */
1248 void
1249 x_wm_set_size_hint (FRAME_PTR f, long int flags, int user_position)
1251 /* Must use GTK routines here, otherwise GTK resets the size hints
1252 to its own defaults. */
1253 GdkGeometry size_hints;
1254 gint hint_flags = 0;
1255 int base_width, base_height;
1256 int min_rows = 0, min_cols = 0;
1257 int win_gravity = f->win_gravity;
1259 /* Don't set size hints during initialization; that apparently leads
1260 to a race condition. See the thread at
1261 http://lists.gnu.org/archive/html/emacs-devel/2008-10/msg00033.html */
1262 if (NILP (Vafter_init_time) || !FRAME_GTK_OUTER_WIDGET (f))
1263 return;
1265 if (flags)
1267 memset (&size_hints, 0, sizeof (size_hints));
1268 f->output_data.x->size_hints = size_hints;
1269 f->output_data.x->hint_flags = hint_flags;
1271 else
1272 flags = f->size_hint_flags;
1274 size_hints = f->output_data.x->size_hints;
1275 hint_flags = f->output_data.x->hint_flags;
1277 hint_flags |= GDK_HINT_RESIZE_INC | GDK_HINT_MIN_SIZE;
1278 size_hints.width_inc = FRAME_COLUMN_WIDTH (f);
1279 size_hints.height_inc = FRAME_LINE_HEIGHT (f);
1281 hint_flags |= GDK_HINT_BASE_SIZE;
1282 base_width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, 0) + FRAME_TOOLBAR_WIDTH (f);
1283 base_height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, 0)
1284 + FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f);
1286 check_frame_size (f, &min_rows, &min_cols);
1288 size_hints.base_width = base_width;
1289 size_hints.base_height = base_height;
1290 size_hints.min_width = base_width + min_cols * size_hints.width_inc;
1291 size_hints.min_height = base_height + min_rows * size_hints.height_inc;
1293 #ifdef HAVE_GTK3
1294 /* Gtk3 ignores min width/height and overwrites them with its own idea
1295 of min width/height. Put out min values to the widget so Gtk
1296 gets the same value we want it to be. Without this, a user can't
1297 shrink an Emacs frame.
1299 if (FRAME_GTK_WIDGET (f))
1300 emacs_fixed_set_min_size (EMACS_FIXED (FRAME_GTK_WIDGET (f)),
1301 size_hints.min_width,
1302 size_hints.min_height);
1303 #endif
1305 /* These currently have a one to one mapping with the X values, but I
1306 don't think we should rely on that. */
1307 hint_flags |= GDK_HINT_WIN_GRAVITY;
1308 size_hints.win_gravity = 0;
1309 if (win_gravity == NorthWestGravity)
1310 size_hints.win_gravity = GDK_GRAVITY_NORTH_WEST;
1311 else if (win_gravity == NorthGravity)
1312 size_hints.win_gravity = GDK_GRAVITY_NORTH;
1313 else if (win_gravity == NorthEastGravity)
1314 size_hints.win_gravity = GDK_GRAVITY_NORTH_EAST;
1315 else if (win_gravity == WestGravity)
1316 size_hints.win_gravity = GDK_GRAVITY_WEST;
1317 else if (win_gravity == CenterGravity)
1318 size_hints.win_gravity = GDK_GRAVITY_CENTER;
1319 else if (win_gravity == EastGravity)
1320 size_hints.win_gravity = GDK_GRAVITY_EAST;
1321 else if (win_gravity == SouthWestGravity)
1322 size_hints.win_gravity = GDK_GRAVITY_SOUTH_WEST;
1323 else if (win_gravity == SouthGravity)
1324 size_hints.win_gravity = GDK_GRAVITY_SOUTH;
1325 else if (win_gravity == SouthEastGravity)
1326 size_hints.win_gravity = GDK_GRAVITY_SOUTH_EAST;
1327 else if (win_gravity == StaticGravity)
1328 size_hints.win_gravity = GDK_GRAVITY_STATIC;
1330 if (user_position)
1332 hint_flags &= ~GDK_HINT_POS;
1333 hint_flags |= GDK_HINT_USER_POS;
1336 if (hint_flags != f->output_data.x->hint_flags
1337 || memcmp (&size_hints,
1338 &f->output_data.x->size_hints,
1339 sizeof (size_hints)) != 0)
1341 BLOCK_INPUT;
1342 gtk_window_set_geometry_hints (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
1343 NULL, &size_hints, hint_flags);
1344 f->output_data.x->size_hints = size_hints;
1345 f->output_data.x->hint_flags = hint_flags;
1346 UNBLOCK_INPUT;
1350 /* Change background color of a frame.
1351 Since GTK uses the background color to clear the window, we must
1352 keep the GTK and X colors in sync.
1353 F is the frame to change,
1354 BG is the pixel value to change to. */
1356 void
1357 xg_set_background_color (FRAME_PTR f, long unsigned int bg)
1359 if (FRAME_GTK_WIDGET (f))
1361 BLOCK_INPUT;
1362 xg_set_widget_bg (f, FRAME_GTK_WIDGET (f), FRAME_BACKGROUND_PIXEL (f));
1363 UNBLOCK_INPUT;
1368 /* Set the frame icon to ICON_PIXMAP/MASK. This must be done with GTK
1369 functions so GTK does not overwrite the icon. */
1371 void
1372 xg_set_frame_icon (FRAME_PTR f, Pixmap icon_pixmap, Pixmap icon_mask)
1374 GdkPixbuf *gp = xg_get_pixbuf_from_pix_and_mask (f,
1375 icon_pixmap,
1376 icon_mask);
1377 if (gp)
1378 gtk_window_set_icon (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), gp);
1383 /***********************************************************************
1384 Dialog functions
1385 ***********************************************************************/
1386 /* Return the dialog title to use for a dialog of type KEY.
1387 This is the encoding used by lwlib. We use the same for GTK. */
1389 static const char *
1390 get_dialog_title (char key)
1392 const char *title = "";
1394 switch (key) {
1395 case 'E': case 'e':
1396 title = "Error";
1397 break;
1399 case 'I': case 'i':
1400 title = "Information";
1401 break;
1403 case 'L': case 'l':
1404 title = "Prompt";
1405 break;
1407 case 'P': case 'p':
1408 title = "Prompt";
1409 break;
1411 case 'Q': case 'q':
1412 title = "Question";
1413 break;
1416 return title;
1419 /* Callback for dialogs that get WM_DELETE_WINDOW. We pop down
1420 the dialog, but return TRUE so the event does not propagate further
1421 in GTK. This prevents GTK from destroying the dialog widget automatically
1422 and we can always destrou the widget manually, regardles of how
1423 it was popped down (button press or WM_DELETE_WINDOW).
1424 W is the dialog widget.
1425 EVENT is the GdkEvent that represents WM_DELETE_WINDOW (not used).
1426 user_data is NULL (not used).
1428 Returns TRUE to end propagation of event. */
1430 static gboolean
1431 dialog_delete_callback (GtkWidget *w, GdkEvent *event, gpointer user_data)
1433 gtk_widget_unmap (w);
1434 return TRUE;
1437 /* Create a popup dialog window. See also xg_create_widget below.
1438 WV is a widget_value describing the dialog.
1439 SELECT_CB is the callback to use when a button has been pressed.
1440 DEACTIVATE_CB is the callback to use when the dialog pops down.
1442 Returns the GTK dialog widget. */
1444 static GtkWidget *
1445 create_dialog (widget_value *wv,
1446 GCallback select_cb,
1447 GCallback deactivate_cb)
1449 const char *title = get_dialog_title (wv->name[0]);
1450 int total_buttons = wv->name[1] - '0';
1451 int right_buttons = wv->name[4] - '0';
1452 int left_buttons;
1453 int button_nr = 0;
1454 int button_spacing = 10;
1455 GtkWidget *wdialog = gtk_dialog_new ();
1456 GtkDialog *wd = GTK_DIALOG (wdialog);
1457 GtkBox *cur_box = GTK_BOX (gtk_dialog_get_action_area (wd));
1458 widget_value *item;
1459 GtkWidget *whbox_down;
1461 /* If the number of buttons is greater than 4, make two rows of buttons
1462 instead. This looks better. */
1463 int make_two_rows = total_buttons > 4;
1465 if (right_buttons == 0) right_buttons = total_buttons/2;
1466 left_buttons = total_buttons - right_buttons;
1468 gtk_window_set_title (GTK_WINDOW (wdialog), title);
1469 gtk_widget_set_name (wdialog, "emacs-dialog");
1472 if (make_two_rows)
1474 GtkWidget *wvbox = gtk_vbox_new (TRUE, button_spacing);
1475 GtkWidget *whbox_up = gtk_hbox_new (FALSE, 0);
1476 whbox_down = gtk_hbox_new (FALSE, 0);
1478 gtk_box_pack_start (cur_box, wvbox, FALSE, FALSE, 0);
1479 gtk_box_pack_start (GTK_BOX (wvbox), whbox_up, FALSE, FALSE, 0);
1480 gtk_box_pack_start (GTK_BOX (wvbox), whbox_down, FALSE, FALSE, 0);
1482 cur_box = GTK_BOX (whbox_up);
1485 g_signal_connect (G_OBJECT (wdialog), "delete-event",
1486 G_CALLBACK (dialog_delete_callback), 0);
1488 if (deactivate_cb)
1490 g_signal_connect (G_OBJECT (wdialog), "close", deactivate_cb, 0);
1491 g_signal_connect (G_OBJECT (wdialog), "response", deactivate_cb, 0);
1494 for (item = wv->contents; item; item = item->next)
1496 char *utf8_label = get_utf8_string (item->value);
1497 GtkWidget *w;
1498 GtkRequisition req;
1500 if (item->name && strcmp (item->name, "message") == 0)
1502 GtkBox *wvbox = GTK_BOX (gtk_dialog_get_content_area (wd));
1503 /* This is the text part of the dialog. */
1504 w = gtk_label_new (utf8_label);
1505 gtk_box_pack_start (wvbox, gtk_label_new (""), FALSE, FALSE, 0);
1506 gtk_box_pack_start (wvbox, w, TRUE, TRUE, 0);
1507 gtk_misc_set_alignment (GTK_MISC (w), 0.1, 0.5);
1509 /* Try to make dialog look better. Must realize first so
1510 the widget can calculate the size it needs. */
1511 gtk_widget_realize (w);
1512 gtk_widget_get_preferred_size (w, NULL, &req);
1513 gtk_box_set_spacing (wvbox, req.height);
1514 if (item->value && strlen (item->value) > 0)
1515 button_spacing = 2*req.width/strlen (item->value);
1517 else
1519 /* This is one button to add to the dialog. */
1520 w = gtk_button_new_with_label (utf8_label);
1521 if (! item->enabled)
1522 gtk_widget_set_sensitive (w, FALSE);
1523 if (select_cb)
1524 g_signal_connect (G_OBJECT (w), "clicked",
1525 select_cb, item->call_data);
1527 gtk_box_pack_start (cur_box, w, TRUE, TRUE, button_spacing);
1528 if (++button_nr == left_buttons)
1530 if (make_two_rows)
1531 cur_box = GTK_BOX (whbox_down);
1532 else
1533 gtk_box_pack_start (cur_box,
1534 gtk_label_new (""),
1535 TRUE, TRUE,
1536 button_spacing);
1540 if (utf8_label)
1541 g_free (utf8_label);
1544 return wdialog;
1547 struct xg_dialog_data
1549 GMainLoop *loop;
1550 int response;
1551 GtkWidget *w;
1552 guint timerid;
1555 /* Function that is called when the file or font dialogs pop down.
1556 W is the dialog widget, RESPONSE is the response code.
1557 USER_DATA is what we passed in to g_signal_connect. */
1559 static void
1560 xg_dialog_response_cb (GtkDialog *w,
1561 gint response,
1562 gpointer user_data)
1564 struct xg_dialog_data *dd = (struct xg_dialog_data *)user_data;
1565 dd->response = response;
1566 g_main_loop_quit (dd->loop);
1570 /* Destroy the dialog. This makes it pop down. */
1572 static Lisp_Object
1573 pop_down_dialog (Lisp_Object arg)
1575 struct Lisp_Save_Value *p = XSAVE_VALUE (arg);
1576 struct xg_dialog_data *dd = (struct xg_dialog_data *) p->pointer;
1578 BLOCK_INPUT;
1579 if (dd->w) gtk_widget_destroy (dd->w);
1580 if (dd->timerid != 0) g_source_remove (dd->timerid);
1582 g_main_loop_quit (dd->loop);
1583 g_main_loop_unref (dd->loop);
1585 UNBLOCK_INPUT;
1587 return Qnil;
1590 /* If there are any emacs timers pending, add a timeout to main loop in DATA.
1591 We pass in DATA as gpointer* so we can use this as a callback. */
1593 static gboolean
1594 xg_maybe_add_timer (gpointer data)
1596 struct xg_dialog_data *dd = (struct xg_dialog_data *) data;
1597 EMACS_TIME next_time = timer_check ();
1598 long secs = EMACS_SECS (next_time);
1599 long usecs = EMACS_USECS (next_time);
1601 dd->timerid = 0;
1603 if (secs >= 0 && usecs >= 0 && secs < ((guint)-1)/1000)
1605 dd->timerid = g_timeout_add (secs * 1000 + usecs/1000,
1606 xg_maybe_add_timer,
1607 dd);
1609 return FALSE;
1613 /* Pops up a modal dialog W and waits for response.
1614 We don't use gtk_dialog_run because we want to process emacs timers.
1615 The dialog W is not destroyed when this function returns. */
1617 static int
1618 xg_dialog_run (FRAME_PTR f, GtkWidget *w)
1620 int count = SPECPDL_INDEX ();
1621 struct xg_dialog_data dd;
1623 xg_set_screen (w, f);
1624 gtk_window_set_transient_for (GTK_WINDOW (w),
1625 GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)));
1626 gtk_window_set_destroy_with_parent (GTK_WINDOW (w), TRUE);
1627 gtk_window_set_modal (GTK_WINDOW (w), TRUE);
1629 dd.loop = g_main_loop_new (NULL, FALSE);
1630 dd.response = GTK_RESPONSE_CANCEL;
1631 dd.w = w;
1632 dd.timerid = 0;
1634 g_signal_connect (G_OBJECT (w),
1635 "response",
1636 G_CALLBACK (xg_dialog_response_cb),
1637 &dd);
1638 /* Don't destroy the widget if closed by the window manager close button. */
1639 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 (&dd, 0));
1644 (void) xg_maybe_add_timer (&dd);
1645 g_main_loop_run (dd.loop);
1647 dd.w = 0;
1648 unbind_to (count, Qnil);
1650 return dd.response;
1654 /***********************************************************************
1655 File dialog functions
1656 ***********************************************************************/
1657 /* Return non-zero if the old file selection dialog is being used.
1658 Return zero if not. */
1661 xg_uses_old_file_dialog (void)
1663 #ifdef HAVE_GTK_FILE_SELECTION_NEW
1664 return x_gtk_use_old_file_dialog;
1665 #else
1666 return 0;
1667 #endif
1671 typedef char * (*xg_get_file_func) (GtkWidget *);
1673 /* Return the selected file for file chooser dialog W.
1674 The returned string must be free:d. */
1676 static char *
1677 xg_get_file_name_from_chooser (GtkWidget *w)
1679 return gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (w));
1682 /* Callback called when the "Show hidden files" toggle is pressed.
1683 WIDGET is the toggle widget, DATA is the file chooser dialog. */
1685 static void
1686 xg_toggle_visibility_cb (GtkWidget *widget, gpointer data)
1688 GtkFileChooser *dialog = GTK_FILE_CHOOSER (data);
1689 gboolean visible;
1690 g_object_get (G_OBJECT (dialog), "show-hidden", &visible, NULL);
1691 g_object_set (G_OBJECT (dialog), "show-hidden", !visible, NULL);
1695 /* Callback called when a property changes in a file chooser.
1696 GOBJECT is the file chooser dialog, ARG1 describes the property.
1697 USER_DATA is the toggle widget in the file chooser dialog.
1698 We use this to update the "Show hidden files" toggle when the user
1699 changes that property by right clicking in the file list. */
1701 static void
1702 xg_toggle_notify_cb (GObject *gobject, GParamSpec *arg1, gpointer user_data)
1704 if (strcmp (arg1->name, "show-hidden") == 0)
1706 GtkWidget *wtoggle = GTK_WIDGET (user_data);
1707 gboolean visible, toggle_on;
1709 g_object_get (G_OBJECT (gobject), "show-hidden", &visible, NULL);
1710 toggle_on = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (wtoggle));
1712 if (!!visible != !!toggle_on)
1714 g_signal_handlers_block_by_func (G_OBJECT (wtoggle),
1715 G_CALLBACK (xg_toggle_visibility_cb),
1716 gobject);
1717 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wtoggle), visible);
1718 g_signal_handlers_unblock_by_func
1719 (G_OBJECT (wtoggle),
1720 G_CALLBACK (xg_toggle_visibility_cb),
1721 gobject);
1723 x_gtk_show_hidden_files = visible;
1727 /* Read a file name from the user using a file chooser dialog.
1728 F is the current frame.
1729 PROMPT is a prompt to show to the user. May not be NULL.
1730 DEFAULT_FILENAME is a default selection to be displayed. May be NULL.
1731 If MUSTMATCH_P is non-zero, the returned file name must be an existing
1732 file. *FUNC is set to a function that can be used to retrieve the
1733 selected file name from the returned widget.
1735 Returns the created widget. */
1737 static GtkWidget *
1738 xg_get_file_with_chooser (FRAME_PTR f,
1739 char *prompt,
1740 char *default_filename,
1741 int mustmatch_p, int only_dir_p,
1742 xg_get_file_func *func)
1744 char msgbuf[1024];
1746 GtkWidget *filewin, *wtoggle, *wbox, *wmessage IF_LINT (= NULL);
1747 GtkWindow *gwin = GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f));
1748 GtkFileChooserAction action = (mustmatch_p ?
1749 GTK_FILE_CHOOSER_ACTION_OPEN :
1750 GTK_FILE_CHOOSER_ACTION_SAVE);
1752 if (only_dir_p)
1753 action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
1755 filewin = gtk_file_chooser_dialog_new (prompt, gwin, action,
1756 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1757 (mustmatch_p || only_dir_p ?
1758 GTK_STOCK_OPEN : GTK_STOCK_OK),
1759 GTK_RESPONSE_OK,
1760 NULL);
1761 gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (filewin), TRUE);
1763 wbox = gtk_vbox_new (FALSE, 0);
1764 gtk_widget_show (wbox);
1765 wtoggle = gtk_check_button_new_with_label ("Show hidden files.");
1767 if (x_gtk_show_hidden_files)
1769 g_object_set (G_OBJECT (filewin), "show-hidden", TRUE, NULL);
1770 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wtoggle), TRUE);
1772 gtk_widget_show (wtoggle);
1773 g_signal_connect (G_OBJECT (wtoggle), "clicked",
1774 G_CALLBACK (xg_toggle_visibility_cb), filewin);
1775 g_signal_connect (G_OBJECT (filewin), "notify",
1776 G_CALLBACK (xg_toggle_notify_cb), wtoggle);
1778 if (x_gtk_file_dialog_help_text)
1780 msgbuf[0] = '\0';
1781 /* Gtk+ 2.10 has the file name text entry box integrated in the dialog.
1782 Show the C-l help text only for versions < 2.10. */
1783 if (gtk_check_version (2, 10, 0) && action != GTK_FILE_CHOOSER_ACTION_SAVE)
1784 strcat (msgbuf, "\nType C-l to display a file name text entry box.\n");
1785 strcat (msgbuf, "\nIf you don't like this file selector, use the "
1786 "corresponding\nkey binding or customize "
1787 "use-file-dialog to turn it off.");
1789 wmessage = gtk_label_new (msgbuf);
1790 gtk_widget_show (wmessage);
1793 gtk_box_pack_start (GTK_BOX (wbox), wtoggle, FALSE, FALSE, 0);
1794 if (x_gtk_file_dialog_help_text)
1795 gtk_box_pack_start (GTK_BOX (wbox), wmessage, FALSE, FALSE, 0);
1796 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (filewin), wbox);
1798 if (default_filename)
1800 Lisp_Object file;
1801 struct gcpro gcpro1;
1802 char *utf8_filename;
1803 GCPRO1 (file);
1805 file = build_string (default_filename);
1807 /* File chooser does not understand ~/... in the file name. It must be
1808 an absolute name starting with /. */
1809 if (default_filename[0] != '/')
1810 file = Fexpand_file_name (file, Qnil);
1812 utf8_filename = SSDATA (ENCODE_UTF_8 (file));
1813 if (! NILP (Ffile_directory_p (file)))
1814 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (filewin),
1815 utf8_filename);
1816 else
1818 gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (filewin),
1819 utf8_filename);
1820 if (action == GTK_FILE_CHOOSER_ACTION_SAVE)
1822 char *cp = strrchr (utf8_filename, '/');
1823 if (cp) ++cp;
1824 else cp = utf8_filename;
1825 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (filewin), cp);
1829 UNGCPRO;
1832 *func = xg_get_file_name_from_chooser;
1833 return filewin;
1836 #ifdef HAVE_GTK_FILE_SELECTION_NEW
1838 /* Return the selected file for file selector dialog W.
1839 The returned string must be free:d. */
1841 static char *
1842 xg_get_file_name_from_selector (GtkWidget *w)
1844 GtkFileSelection *filesel = GTK_FILE_SELECTION (w);
1845 return xstrdup ((char*) gtk_file_selection_get_filename (filesel));
1848 /* Create a file selection dialog.
1849 F is the current frame.
1850 PROMPT is a prompt to show to the user. May not be NULL.
1851 DEFAULT_FILENAME is a default selection to be displayed. May be NULL.
1852 If MUSTMATCH_P is non-zero, the returned file name must be an existing
1853 file. *FUNC is set to a function that can be used to retrieve the
1854 selected file name from the returned widget.
1856 Returns the created widget. */
1858 static GtkWidget *
1859 xg_get_file_with_selection (FRAME_PTR f,
1860 char *prompt,
1861 char *default_filename,
1862 int mustmatch_p, int only_dir_p,
1863 xg_get_file_func *func)
1865 GtkWidget *filewin;
1866 GtkFileSelection *filesel;
1868 filewin = gtk_file_selection_new (prompt);
1869 filesel = GTK_FILE_SELECTION (filewin);
1871 if (default_filename)
1872 gtk_file_selection_set_filename (filesel, default_filename);
1874 if (mustmatch_p)
1876 /* The selection_entry part of filesel is not documented. */
1877 gtk_widget_set_sensitive (filesel->selection_entry, FALSE);
1878 gtk_file_selection_hide_fileop_buttons (filesel);
1881 *func = xg_get_file_name_from_selector;
1883 return filewin;
1885 #endif /* HAVE_GTK_FILE_SELECTION_NEW */
1887 /* Read a file name from the user using a file dialog, either the old
1888 file selection dialog, or the new file chooser dialog. Which to use
1889 depends on what the GTK version used has, and what the value of
1890 gtk-use-old-file-dialog.
1891 F is the current frame.
1892 PROMPT is a prompt to show to the user. May not be NULL.
1893 DEFAULT_FILENAME is a default selection to be displayed. May be NULL.
1894 If MUSTMATCH_P is non-zero, the returned file name must be an existing
1895 file.
1897 Returns a file name or NULL if no file was selected.
1898 The returned string must be freed by the caller. */
1900 char *
1901 xg_get_file_name (FRAME_PTR f,
1902 char *prompt,
1903 char *default_filename,
1904 int mustmatch_p,
1905 int only_dir_p)
1907 GtkWidget *w = 0;
1908 char *fn = 0;
1909 int filesel_done = 0;
1910 xg_get_file_func func;
1912 #if defined (HAVE_GTK_AND_PTHREAD) && defined (__SIGRTMIN)
1913 /* I really don't know why this is needed, but without this the GLIBC add on
1914 library linuxthreads hangs when the Gnome file chooser backend creates
1915 threads. */
1916 sigblock (sigmask (__SIGRTMIN));
1917 #endif /* HAVE_GTK_AND_PTHREAD */
1919 #ifdef HAVE_GTK_FILE_SELECTION_NEW
1921 if (xg_uses_old_file_dialog ())
1922 w = xg_get_file_with_selection (f, prompt, default_filename,
1923 mustmatch_p, only_dir_p, &func);
1924 else
1925 w = xg_get_file_with_chooser (f, prompt, default_filename,
1926 mustmatch_p, only_dir_p, &func);
1928 #else /* not HAVE_GTK_FILE_SELECTION_NEW */
1929 w = xg_get_file_with_chooser (f, prompt, default_filename,
1930 mustmatch_p, only_dir_p, &func);
1931 #endif /* not HAVE_GTK_FILE_SELECTION_NEW */
1933 gtk_widget_set_name (w, "emacs-filedialog");
1935 filesel_done = xg_dialog_run (f, w);
1937 #if defined (HAVE_GTK_AND_PTHREAD) && defined (__SIGRTMIN)
1938 sigunblock (sigmask (__SIGRTMIN));
1939 #endif
1941 if (filesel_done == GTK_RESPONSE_OK)
1942 fn = (*func) (w);
1944 gtk_widget_destroy (w);
1945 return fn;
1948 #ifdef HAVE_FREETYPE
1949 /* Pop up a GTK font selector and return the name of the font the user
1950 selects, as a C string. The returned font name follows GTK's own
1951 format:
1953 `FAMILY [VALUE1 VALUE2] SIZE'
1955 This can be parsed using font_parse_fcname in font.c.
1956 DEFAULT_NAME, if non-zero, is the default font name. */
1958 char *
1959 xg_get_font_name (FRAME_PTR f, const char *default_name)
1961 GtkWidget *w;
1962 char *fontname = NULL;
1963 int done = 0;
1965 #if defined (HAVE_GTK_AND_PTHREAD) && defined (__SIGRTMIN)
1966 sigblock (sigmask (__SIGRTMIN));
1967 #endif /* HAVE_GTK_AND_PTHREAD */
1969 w = gtk_font_selection_dialog_new ("Pick a font");
1970 if (!default_name)
1971 default_name = "Monospace 10";
1972 gtk_font_selection_dialog_set_font_name (GTK_FONT_SELECTION_DIALOG (w),
1973 default_name);
1975 gtk_widget_set_name (w, "emacs-fontdialog");
1977 done = xg_dialog_run (f, w);
1979 #if defined (HAVE_GTK_AND_PTHREAD) && defined (__SIGRTMIN)
1980 sigunblock (sigmask (__SIGRTMIN));
1981 #endif
1983 if (done == GTK_RESPONSE_OK)
1984 fontname = gtk_font_selection_dialog_get_font_name
1985 (GTK_FONT_SELECTION_DIALOG (w));
1987 gtk_widget_destroy (w);
1988 return fontname;
1990 #endif /* HAVE_FREETYPE */
1994 /***********************************************************************
1995 Menu functions.
1996 ***********************************************************************/
1998 /* The name of menu items that can be used for customization. Since GTK
1999 RC files are very crude and primitive, we have to set this on all
2000 menu item names so a user can easily customize menu items. */
2002 #define MENU_ITEM_NAME "emacs-menuitem"
2005 /* Linked list of all allocated struct xg_menu_cb_data. Used for marking
2006 during GC. The next member points to the items. */
2007 static xg_list_node xg_menu_cb_list;
2009 /* Linked list of all allocated struct xg_menu_item_cb_data. Used for marking
2010 during GC. The next member points to the items. */
2011 static xg_list_node xg_menu_item_cb_list;
2013 /* Allocate and initialize CL_DATA if NULL, otherwise increase ref_count.
2014 F is the frame CL_DATA will be initialized for.
2015 HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
2017 The menu bar and all sub menus under the menu bar in a frame
2018 share the same structure, hence the reference count.
2020 Returns CL_DATA if CL_DATA is not NULL, or a pointer to a newly
2021 allocated xg_menu_cb_data if CL_DATA is NULL. */
2023 static xg_menu_cb_data *
2024 make_cl_data (xg_menu_cb_data *cl_data, FRAME_PTR f, GCallback highlight_cb)
2026 if (! cl_data)
2028 cl_data = (xg_menu_cb_data*) xmalloc (sizeof (*cl_data));
2029 cl_data->f = f;
2030 cl_data->menu_bar_vector = f->menu_bar_vector;
2031 cl_data->menu_bar_items_used = f->menu_bar_items_used;
2032 cl_data->highlight_cb = highlight_cb;
2033 cl_data->ref_count = 0;
2035 xg_list_insert (&xg_menu_cb_list, &cl_data->ptrs);
2038 cl_data->ref_count++;
2040 return cl_data;
2043 /* Update CL_DATA with values from frame F and with HIGHLIGHT_CB.
2044 HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
2046 When the menu bar is updated, menu items may have been added and/or
2047 removed, so menu_bar_vector and menu_bar_items_used change. We must
2048 then update CL_DATA since it is used to determine which menu
2049 item that is invoked in the menu.
2050 HIGHLIGHT_CB could change, there is no check that the same
2051 function is given when modifying a menu bar as was given when
2052 creating the menu bar. */
2054 static void
2055 update_cl_data (xg_menu_cb_data *cl_data,
2056 FRAME_PTR f,
2057 GCallback highlight_cb)
2059 if (cl_data)
2061 cl_data->f = f;
2062 cl_data->menu_bar_vector = f->menu_bar_vector;
2063 cl_data->menu_bar_items_used = f->menu_bar_items_used;
2064 cl_data->highlight_cb = highlight_cb;
2068 /* Decrease reference count for CL_DATA.
2069 If reference count is zero, free CL_DATA. */
2071 static void
2072 unref_cl_data (xg_menu_cb_data *cl_data)
2074 if (cl_data && cl_data->ref_count > 0)
2076 cl_data->ref_count--;
2077 if (cl_data->ref_count == 0)
2079 xg_list_remove (&xg_menu_cb_list, &cl_data->ptrs);
2080 xfree (cl_data);
2085 /* Function that marks all lisp data during GC. */
2087 void
2088 xg_mark_data (void)
2090 xg_list_node *iter;
2092 for (iter = xg_menu_cb_list.next; iter; iter = iter->next)
2093 mark_object (((xg_menu_cb_data *) iter)->menu_bar_vector);
2095 for (iter = xg_menu_item_cb_list.next; iter; iter = iter->next)
2097 xg_menu_item_cb_data *cb_data = (xg_menu_item_cb_data *) iter;
2099 if (! NILP (cb_data->help))
2100 mark_object (cb_data->help);
2105 /* Callback called when a menu item is destroyed. Used to free data.
2106 W is the widget that is being destroyed (not used).
2107 CLIENT_DATA points to the xg_menu_item_cb_data associated with the W. */
2109 static void
2110 menuitem_destroy_callback (GtkWidget *w, gpointer client_data)
2112 if (client_data)
2114 xg_menu_item_cb_data *data = (xg_menu_item_cb_data*) client_data;
2115 xg_list_remove (&xg_menu_item_cb_list, &data->ptrs);
2116 xfree (data);
2120 /* Callback called when the pointer enters/leaves a menu item.
2121 W is the parent of the menu item.
2122 EVENT is either an enter event or leave event.
2123 CLIENT_DATA is not used.
2125 Returns FALSE to tell GTK to keep processing this event. */
2127 static gboolean
2128 menuitem_highlight_callback (GtkWidget *w,
2129 GdkEventCrossing *event,
2130 gpointer client_data)
2132 GdkEvent ev;
2133 GtkWidget *subwidget;
2134 xg_menu_item_cb_data *data;
2136 ev.crossing = *event;
2137 subwidget = gtk_get_event_widget (&ev);
2138 data = (xg_menu_item_cb_data *) g_object_get_data (G_OBJECT (subwidget),
2139 XG_ITEM_DATA);
2140 if (data)
2142 if (! NILP (data->help) && data->cl_data->highlight_cb)
2144 gpointer call_data = event->type == GDK_LEAVE_NOTIFY ? 0 : data;
2145 GtkCallback func = (GtkCallback) data->cl_data->highlight_cb;
2146 (*func) (subwidget, call_data);
2150 return FALSE;
2153 /* Callback called when a menu is destroyed. Used to free data.
2154 W is the widget that is being destroyed (not used).
2155 CLIENT_DATA points to the xg_menu_cb_data associated with W. */
2157 static void
2158 menu_destroy_callback (GtkWidget *w, gpointer client_data)
2160 unref_cl_data ((xg_menu_cb_data*) client_data);
2163 /* Make a GTK widget that contains both UTF8_LABEL and UTF8_KEY (both
2164 must be non-NULL) and can be inserted into a menu item.
2166 Returns the GtkHBox. */
2168 static GtkWidget *
2169 make_widget_for_menu_item (const char *utf8_label, const char *utf8_key)
2171 GtkWidget *wlbl;
2172 GtkWidget *wkey;
2173 GtkWidget *wbox;
2175 wbox = gtk_hbox_new (FALSE, 0);
2176 wlbl = gtk_label_new (utf8_label);
2177 wkey = gtk_label_new (utf8_key);
2179 gtk_misc_set_alignment (GTK_MISC (wlbl), 0.0, 0.5);
2180 gtk_misc_set_alignment (GTK_MISC (wkey), 0.0, 0.5);
2182 gtk_box_pack_start (GTK_BOX (wbox), wlbl, TRUE, TRUE, 0);
2183 gtk_box_pack_start (GTK_BOX (wbox), wkey, FALSE, FALSE, 0);
2185 gtk_widget_set_name (wlbl, MENU_ITEM_NAME);
2186 gtk_widget_set_name (wkey, MENU_ITEM_NAME);
2187 gtk_widget_set_name (wbox, MENU_ITEM_NAME);
2189 return wbox;
2192 /* Make and return a menu item widget with the key to the right.
2193 UTF8_LABEL is the text for the menu item (GTK uses UTF8 internally).
2194 UTF8_KEY is the text representing the key binding.
2195 ITEM is the widget_value describing the menu item.
2197 GROUP is an in/out parameter. If the menu item to be created is not
2198 part of any radio menu group, *GROUP contains NULL on entry and exit.
2199 If the menu item to be created is part of a radio menu group, on entry
2200 *GROUP contains the group to use, or NULL if this is the first item
2201 in the group. On exit, *GROUP contains the radio item group.
2203 Unfortunately, keys don't line up as nicely as in Motif,
2204 but the MacOS X version doesn't either, so I guess that is OK. */
2206 static GtkWidget *
2207 make_menu_item (const char *utf8_label,
2208 const char *utf8_key,
2209 widget_value *item,
2210 GSList **group)
2212 GtkWidget *w;
2213 GtkWidget *wtoadd = 0;
2215 /* It has been observed that some menu items have a NULL name field.
2216 This will lead to this function being called with a NULL utf8_label.
2217 GTK crashes on that so we set a blank label. Why there is a NULL
2218 name remains to be investigated. */
2219 if (! utf8_label) utf8_label = " ";
2221 if (utf8_key)
2222 wtoadd = make_widget_for_menu_item (utf8_label, utf8_key);
2224 if (item->button_type == BUTTON_TYPE_TOGGLE)
2226 *group = NULL;
2227 if (utf8_key) w = gtk_check_menu_item_new ();
2228 else w = gtk_check_menu_item_new_with_label (utf8_label);
2229 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w), item->selected);
2231 else if (item->button_type == BUTTON_TYPE_RADIO)
2233 if (utf8_key) w = gtk_radio_menu_item_new (*group);
2234 else w = gtk_radio_menu_item_new_with_label (*group, utf8_label);
2235 *group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (w));
2236 if (item->selected)
2237 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w), TRUE);
2239 else
2241 *group = NULL;
2242 if (utf8_key) w = gtk_menu_item_new ();
2243 else w = gtk_menu_item_new_with_label (utf8_label);
2246 if (wtoadd) gtk_container_add (GTK_CONTAINER (w), wtoadd);
2247 if (! item->enabled) gtk_widget_set_sensitive (w, FALSE);
2249 return w;
2252 static int xg_detached_menus;
2254 /* Returns non-zero if there are detached menus. */
2257 xg_have_tear_offs (void)
2259 return xg_detached_menus > 0;
2262 /* Callback invoked when a detached menu window is removed. Here we
2263 decrease the xg_detached_menus count.
2264 WIDGET is the top level window that is removed (the parent of the menu).
2265 CLIENT_DATA is not used. */
2267 static void
2268 tearoff_remove (GtkWidget *widget, gpointer client_data)
2270 if (xg_detached_menus > 0) --xg_detached_menus;
2273 /* Callback invoked when a menu is detached. It increases the
2274 xg_detached_menus count.
2275 WIDGET is the GtkTearoffMenuItem.
2276 CLIENT_DATA is not used. */
2278 static void
2279 tearoff_activate (GtkWidget *widget, gpointer client_data)
2281 GtkWidget *menu = gtk_widget_get_parent (widget);
2282 if (gtk_menu_get_tearoff_state (GTK_MENU (menu)))
2284 ++xg_detached_menus;
2285 g_signal_connect (G_OBJECT (gtk_widget_get_toplevel (widget)),
2286 "destroy",
2287 G_CALLBACK (tearoff_remove), 0);
2292 /* Create a menu item widget, and connect the callbacks.
2293 ITEM decribes the menu item.
2294 F is the frame the created menu belongs to.
2295 SELECT_CB is the callback to use when a menu item is selected.
2296 HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
2297 CL_DATA points to the callback data to be used for this menu.
2298 GROUP is an in/out parameter. If the menu item to be created is not
2299 part of any radio menu group, *GROUP contains NULL on entry and exit.
2300 If the menu item to be created is part of a radio menu group, on entry
2301 *GROUP contains the group to use, or NULL if this is the first item
2302 in the group. On exit, *GROUP contains the radio item group.
2304 Returns the created GtkWidget. */
2306 static GtkWidget *
2307 xg_create_one_menuitem (widget_value *item,
2308 FRAME_PTR f,
2309 GCallback select_cb,
2310 GCallback highlight_cb,
2311 xg_menu_cb_data *cl_data,
2312 GSList **group)
2314 char *utf8_label;
2315 char *utf8_key;
2316 GtkWidget *w;
2317 xg_menu_item_cb_data *cb_data;
2319 utf8_label = get_utf8_string (item->name);
2320 utf8_key = get_utf8_string (item->key);
2322 w = make_menu_item (utf8_label, utf8_key, item, group);
2324 if (utf8_label) g_free (utf8_label);
2325 if (utf8_key) g_free (utf8_key);
2327 cb_data = xmalloc (sizeof (xg_menu_item_cb_data));
2329 xg_list_insert (&xg_menu_item_cb_list, &cb_data->ptrs);
2331 cb_data->select_id = 0;
2332 cb_data->help = item->help;
2333 cb_data->cl_data = cl_data;
2334 cb_data->call_data = item->call_data;
2336 g_signal_connect (G_OBJECT (w),
2337 "destroy",
2338 G_CALLBACK (menuitem_destroy_callback),
2339 cb_data);
2341 /* Put cb_data in widget, so we can get at it when modifying menubar */
2342 g_object_set_data (G_OBJECT (w), XG_ITEM_DATA, cb_data);
2344 /* final item, not a submenu */
2345 if (item->call_data && ! item->contents)
2347 if (select_cb)
2348 cb_data->select_id
2349 = g_signal_connect (G_OBJECT (w), "activate", select_cb, cb_data);
2352 return w;
2355 /* Create a full menu tree specified by DATA.
2356 F is the frame the created menu belongs to.
2357 SELECT_CB is the callback to use when a menu item is selected.
2358 DEACTIVATE_CB is the callback to use when a sub menu is not shown anymore.
2359 HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
2360 POP_UP_P is non-zero if we shall create a popup menu.
2361 MENU_BAR_P is non-zero if we shall create a menu bar.
2362 ADD_TEAROFF_P is non-zero if we shall add a teroff menu item. Ignored
2363 if MENU_BAR_P is non-zero.
2364 TOPMENU is the topmost GtkWidget that others shall be placed under.
2365 It may be NULL, in that case we create the appropriate widget
2366 (menu bar or menu item depending on POP_UP_P and MENU_BAR_P)
2367 CL_DATA is the callback data we shall use for this menu, or NULL
2368 if we haven't set the first callback yet.
2369 NAME is the name to give to the top level menu if this function
2370 creates it. May be NULL to not set any name.
2372 Returns the top level GtkWidget. This is TOPLEVEL if TOPLEVEL is
2373 not NULL.
2375 This function calls itself to create submenus. */
2377 static GtkWidget *
2378 create_menus (widget_value *data,
2379 FRAME_PTR f,
2380 GCallback select_cb,
2381 GCallback deactivate_cb,
2382 GCallback highlight_cb,
2383 int pop_up_p,
2384 int menu_bar_p,
2385 int add_tearoff_p,
2386 GtkWidget *topmenu,
2387 xg_menu_cb_data *cl_data,
2388 const char *name)
2390 widget_value *item;
2391 GtkWidget *wmenu = topmenu;
2392 GSList *group = NULL;
2394 if (! topmenu)
2396 if (! menu_bar_p)
2398 wmenu = gtk_menu_new ();
2399 xg_set_screen (wmenu, f);
2400 /* Connect this to the menu instead of items so we get enter/leave for
2401 disabled items also. TODO: Still does not get enter/leave for
2402 disabled items in detached menus. */
2403 g_signal_connect (G_OBJECT (wmenu),
2404 "enter-notify-event",
2405 G_CALLBACK (menuitem_highlight_callback),
2406 NULL);
2407 g_signal_connect (G_OBJECT (wmenu),
2408 "leave-notify-event",
2409 G_CALLBACK (menuitem_highlight_callback),
2410 NULL);
2412 else
2414 wmenu = gtk_menu_bar_new ();
2415 /* Set width of menu bar to a small value so it doesn't enlarge
2416 a small initial frame size. The width will be set to the
2417 width of the frame later on when it is added to a container.
2418 height -1: Natural height. */
2419 gtk_widget_set_size_request (wmenu, 1, -1);
2422 /* Put cl_data on the top menu for easier access. */
2423 cl_data = make_cl_data (cl_data, f, highlight_cb);
2424 g_object_set_data (G_OBJECT (wmenu), XG_FRAME_DATA, (gpointer)cl_data);
2425 g_signal_connect (G_OBJECT (wmenu), "destroy",
2426 G_CALLBACK (menu_destroy_callback), cl_data);
2428 if (name)
2429 gtk_widget_set_name (wmenu, name);
2431 if (deactivate_cb)
2432 g_signal_connect (G_OBJECT (wmenu),
2433 "selection-done", deactivate_cb, 0);
2436 if (! menu_bar_p && add_tearoff_p)
2438 GtkWidget *tearoff = gtk_tearoff_menu_item_new ();
2439 gtk_menu_shell_append (GTK_MENU_SHELL (wmenu), tearoff);
2441 g_signal_connect (G_OBJECT (tearoff), "activate",
2442 G_CALLBACK (tearoff_activate), 0);
2445 for (item = data; item; item = item->next)
2447 GtkWidget *w;
2449 if (pop_up_p && !item->contents && !item->call_data
2450 && !menu_separator_name_p (item->name))
2452 char *utf8_label;
2453 /* A title for a popup. We do the same as GTK does when
2454 creating titles, but it does not look good. */
2455 group = NULL;
2456 utf8_label = get_utf8_string (item->name);
2458 gtk_menu_set_title (GTK_MENU (wmenu), utf8_label);
2459 w = gtk_menu_item_new_with_label (utf8_label);
2460 gtk_widget_set_sensitive (w, FALSE);
2461 if (utf8_label) g_free (utf8_label);
2463 else if (menu_separator_name_p (item->name))
2465 group = NULL;
2466 /* GTK only have one separator type. */
2467 w = gtk_separator_menu_item_new ();
2469 else
2471 w = xg_create_one_menuitem (item,
2473 item->contents ? 0 : select_cb,
2474 highlight_cb,
2475 cl_data,
2476 &group);
2478 /* Create a possibly empty submenu for menu bar items, since some
2479 themes don't highlight items correctly without it. */
2480 if (item->contents || menu_bar_p)
2482 GtkWidget *submenu = create_menus (item->contents,
2484 select_cb,
2485 deactivate_cb,
2486 highlight_cb,
2489 add_tearoff_p,
2491 cl_data,
2493 gtk_menu_item_set_submenu (GTK_MENU_ITEM (w), submenu);
2497 gtk_menu_shell_append (GTK_MENU_SHELL (wmenu), w);
2498 gtk_widget_set_name (w, MENU_ITEM_NAME);
2501 return wmenu;
2504 /* Create a menubar, popup menu or dialog, depending on the TYPE argument.
2505 TYPE can be "menubar", "popup" for popup menu, or "dialog" for a dialog
2506 with some text and buttons.
2507 F is the frame the created item belongs to.
2508 NAME is the name to use for the top widget.
2509 VAL is a widget_value structure describing items to be created.
2510 SELECT_CB is the callback to use when a menu item is selected or
2511 a dialog button is pressed.
2512 DEACTIVATE_CB is the callback to use when an item is deactivated.
2513 For a menu, when a sub menu is not shown anymore, for a dialog it is
2514 called when the dialog is popped down.
2515 HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
2517 Returns the widget created. */
2519 GtkWidget *
2520 xg_create_widget (const char *type, const char *name, FRAME_PTR f, widget_value *val,
2521 GCallback select_cb, GCallback deactivate_cb,
2522 GCallback highlight_cb)
2524 GtkWidget *w = 0;
2525 int menu_bar_p = strcmp (type, "menubar") == 0;
2526 int pop_up_p = strcmp (type, "popup") == 0;
2528 if (strcmp (type, "dialog") == 0)
2530 w = create_dialog (val, select_cb, deactivate_cb);
2531 xg_set_screen (w, f);
2532 gtk_window_set_transient_for (GTK_WINDOW (w),
2533 GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)));
2534 gtk_window_set_destroy_with_parent (GTK_WINDOW (w), TRUE);
2535 gtk_widget_set_name (w, "emacs-dialog");
2536 gtk_window_set_modal (GTK_WINDOW (w), TRUE);
2538 else if (menu_bar_p || pop_up_p)
2540 w = create_menus (val->contents,
2542 select_cb,
2543 deactivate_cb,
2544 highlight_cb,
2545 pop_up_p,
2546 menu_bar_p,
2547 menu_bar_p,
2550 name);
2552 /* Set the cursor to an arrow for popup menus when they are mapped.
2553 This is done by default for menu bar menus. */
2554 if (pop_up_p)
2556 /* Must realize so the GdkWindow inside the widget is created. */
2557 gtk_widget_realize (w);
2558 xg_set_cursor (w, FRAME_X_DISPLAY_INFO (f)->xg_cursor);
2561 else
2563 fprintf (stderr, "bad type in xg_create_widget: %s, doing nothing\n",
2564 type);
2567 return w;
2570 /* Return the label for menu item WITEM. */
2572 static const char *
2573 xg_get_menu_item_label (GtkMenuItem *witem)
2575 GtkLabel *wlabel = GTK_LABEL (XG_BIN_CHILD (witem));
2576 return gtk_label_get_label (wlabel);
2579 /* Return non-zero if the menu item WITEM has the text LABEL. */
2581 static int
2582 xg_item_label_same_p (GtkMenuItem *witem, const char *label)
2584 int is_same = 0;
2585 char *utf8_label = get_utf8_string (label);
2586 const char *old_label = witem ? xg_get_menu_item_label (witem) : 0;
2588 if (! old_label && ! utf8_label)
2589 is_same = 1;
2590 else if (old_label && utf8_label)
2591 is_same = strcmp (utf8_label, old_label) == 0;
2593 if (utf8_label) g_free (utf8_label);
2595 return is_same;
2598 /* Destroy widgets in LIST. */
2600 static void
2601 xg_destroy_widgets (GList *list)
2603 GList *iter;
2605 for (iter = list; iter; iter = g_list_next (iter))
2607 GtkWidget *w = GTK_WIDGET (iter->data);
2609 /* Destroying the widget will remove it from the container it is in. */
2610 gtk_widget_destroy (w);
2614 /* Update the top level names in MENUBAR (i.e. not submenus).
2615 F is the frame the menu bar belongs to.
2616 *LIST is a list with the current menu bar names (menu item widgets).
2617 ITER is the item within *LIST that shall be updated.
2618 POS is the numerical position, starting at 0, of ITER in *LIST.
2619 VAL describes what the menu bar shall look like after the update.
2620 SELECT_CB is the callback to use when a menu item is selected.
2621 HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
2622 CL_DATA points to the callback data to be used for this menu bar.
2624 This function calls itself to walk through the menu bar names. */
2626 static void
2627 xg_update_menubar (GtkWidget *menubar,
2628 FRAME_PTR f,
2629 GList **list,
2630 GList *iter,
2631 int pos,
2632 widget_value *val,
2633 GCallback select_cb,
2634 GCallback deactivate_cb,
2635 GCallback highlight_cb,
2636 xg_menu_cb_data *cl_data)
2638 if (! iter && ! val)
2639 return;
2640 else if (iter && ! val)
2642 /* Item(s) have been removed. Remove all remaining items. */
2643 xg_destroy_widgets (iter);
2645 /* Add a blank entry so the menubar doesn't collapse to nothing. */
2646 gtk_menu_shell_insert (GTK_MENU_SHELL (menubar),
2647 gtk_menu_item_new_with_label (""),
2649 /* All updated. */
2650 val = 0;
2651 iter = 0;
2653 else if (! iter && val)
2655 /* Item(s) added. Add all new items in one call. */
2656 create_menus (val, f, select_cb, deactivate_cb, highlight_cb,
2657 0, 1, 0, menubar, cl_data, 0);
2659 /* All updated. */
2660 val = 0;
2661 iter = 0;
2663 /* Below this neither iter or val is NULL */
2664 else if (xg_item_label_same_p (GTK_MENU_ITEM (iter->data), val->name))
2666 /* This item is still the same, check next item. */
2667 val = val->next;
2668 iter = g_list_next (iter);
2669 ++pos;
2671 else /* This item is changed. */
2673 GtkMenuItem *witem = GTK_MENU_ITEM (iter->data);
2674 GtkMenuItem *witem2 = 0;
2675 int val_in_menubar = 0;
2676 int iter_in_new_menubar = 0;
2677 GList *iter2;
2678 widget_value *cur;
2680 /* See if the changed entry (val) is present later in the menu bar */
2681 for (iter2 = iter;
2682 iter2 && ! val_in_menubar;
2683 iter2 = g_list_next (iter2))
2685 witem2 = GTK_MENU_ITEM (iter2->data);
2686 val_in_menubar = xg_item_label_same_p (witem2, val->name);
2689 /* See if the current entry (iter) is present later in the
2690 specification for the new menu bar. */
2691 for (cur = val; cur && ! iter_in_new_menubar; cur = cur->next)
2692 iter_in_new_menubar = xg_item_label_same_p (witem, cur->name);
2694 if (val_in_menubar && ! iter_in_new_menubar)
2696 int nr = pos;
2698 /* This corresponds to:
2699 Current: A B C
2700 New: A C
2701 Remove B. */
2703 g_object_ref (G_OBJECT (witem));
2704 gtk_container_remove (GTK_CONTAINER (menubar), GTK_WIDGET (witem));
2705 gtk_widget_destroy (GTK_WIDGET (witem));
2707 /* Must get new list since the old changed. */
2708 g_list_free (*list);
2709 *list = iter = gtk_container_get_children (GTK_CONTAINER (menubar));
2710 while (nr-- > 0) iter = g_list_next (iter);
2712 else if (! val_in_menubar && ! iter_in_new_menubar)
2714 /* This corresponds to:
2715 Current: A B C
2716 New: A X C
2717 Rename B to X. This might seem to be a strange thing to do,
2718 since if there is a menu under B it will be totally wrong for X.
2719 But consider editing a C file. Then there is a C-mode menu
2720 (corresponds to B above).
2721 If then doing C-x C-f the minibuf menu (X above) replaces the
2722 C-mode menu. When returning from the minibuffer, we get
2723 back the C-mode menu. Thus we do:
2724 Rename B to X (C-mode to minibuf menu)
2725 Rename X to B (minibuf to C-mode menu).
2726 If the X menu hasn't been invoked, the menu under B
2727 is up to date when leaving the minibuffer. */
2728 GtkLabel *wlabel = GTK_LABEL (XG_BIN_CHILD (witem));
2729 char *utf8_label = get_utf8_string (val->name);
2730 GtkWidget *submenu = gtk_menu_item_get_submenu (witem);
2732 gtk_label_set_text (wlabel, utf8_label);
2734 /* If this item has a submenu that has been detached, change
2735 the title in the WM decorations also. */
2736 if (submenu && gtk_menu_get_tearoff_state (GTK_MENU (submenu)))
2737 /* Set the title of the detached window. */
2738 gtk_menu_set_title (GTK_MENU (submenu), utf8_label);
2740 if (utf8_label) g_free (utf8_label);
2741 iter = g_list_next (iter);
2742 val = val->next;
2743 ++pos;
2745 else if (! val_in_menubar && iter_in_new_menubar)
2747 /* This corresponds to:
2748 Current: A B C
2749 New: A X B C
2750 Insert X. */
2752 int nr = pos;
2753 GSList *group = 0;
2754 GtkWidget *w = xg_create_one_menuitem (val,
2756 select_cb,
2757 highlight_cb,
2758 cl_data,
2759 &group);
2761 /* Create a possibly empty submenu for menu bar items, since some
2762 themes don't highlight items correctly without it. */
2763 GtkWidget *submenu = create_menus (NULL, f,
2764 select_cb, deactivate_cb,
2765 highlight_cb,
2766 0, 0, 0, 0, cl_data, 0);
2767 gtk_widget_set_name (w, MENU_ITEM_NAME);
2768 gtk_menu_shell_insert (GTK_MENU_SHELL (menubar), w, pos);
2769 gtk_menu_item_set_submenu (GTK_MENU_ITEM (w), submenu);
2771 g_list_free (*list);
2772 *list = iter = gtk_container_get_children (GTK_CONTAINER (menubar));
2773 while (nr-- > 0) iter = g_list_next (iter);
2774 iter = g_list_next (iter);
2775 val = val->next;
2776 ++pos;
2778 else /* if (val_in_menubar && iter_in_new_menubar) */
2780 int nr = pos;
2781 /* This corresponds to:
2782 Current: A B C
2783 New: A C B
2784 Move C before B */
2786 g_object_ref (G_OBJECT (witem2));
2787 gtk_container_remove (GTK_CONTAINER (menubar), GTK_WIDGET (witem2));
2788 gtk_menu_shell_insert (GTK_MENU_SHELL (menubar),
2789 GTK_WIDGET (witem2), pos);
2790 g_object_unref (G_OBJECT (witem2));
2792 g_list_free (*list);
2793 *list = iter = gtk_container_get_children (GTK_CONTAINER (menubar));
2794 while (nr-- > 0) iter = g_list_next (iter);
2795 if (iter) iter = g_list_next (iter);
2796 val = val->next;
2797 ++pos;
2801 /* Update the rest of the menu bar. */
2802 xg_update_menubar (menubar, f, list, iter, pos, val,
2803 select_cb, deactivate_cb, highlight_cb, cl_data);
2806 /* Update the menu item W so it corresponds to VAL.
2807 SELECT_CB is the callback to use when a menu item is selected.
2808 HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
2809 CL_DATA is the data to set in the widget for menu invocation. */
2811 static void
2812 xg_update_menu_item (widget_value *val,
2813 GtkWidget *w,
2814 GCallback select_cb,
2815 GCallback highlight_cb,
2816 xg_menu_cb_data *cl_data)
2818 GtkWidget *wchild;
2819 GtkLabel *wlbl = 0;
2820 GtkLabel *wkey = 0;
2821 char *utf8_label;
2822 char *utf8_key;
2823 const char *old_label = 0;
2824 const char *old_key = 0;
2825 xg_menu_item_cb_data *cb_data;
2827 wchild = XG_BIN_CHILD (w);
2828 utf8_label = get_utf8_string (val->name);
2829 utf8_key = get_utf8_string (val->key);
2831 /* See if W is a menu item with a key. See make_menu_item above. */
2832 if (GTK_IS_HBOX (wchild))
2834 GList *list = gtk_container_get_children (GTK_CONTAINER (wchild));
2836 wlbl = GTK_LABEL (list->data);
2837 wkey = GTK_LABEL (list->next->data);
2838 g_list_free (list);
2840 if (! utf8_key)
2842 /* Remove the key and keep just the label. */
2843 g_object_ref (G_OBJECT (wlbl));
2844 gtk_container_remove (GTK_CONTAINER (w), wchild);
2845 gtk_container_add (GTK_CONTAINER (w), GTK_WIDGET (wlbl));
2846 g_object_unref (G_OBJECT (wlbl));
2847 wkey = 0;
2851 else /* Just a label. */
2853 wlbl = GTK_LABEL (wchild);
2855 /* Check if there is now a key. */
2856 if (utf8_key)
2858 GtkWidget *wtoadd = make_widget_for_menu_item (utf8_label, utf8_key);
2859 GList *list = gtk_container_get_children (GTK_CONTAINER (wtoadd));
2861 wlbl = GTK_LABEL (list->data);
2862 wkey = GTK_LABEL (list->next->data);
2863 g_list_free (list);
2865 gtk_container_remove (GTK_CONTAINER (w), wchild);
2866 gtk_container_add (GTK_CONTAINER (w), wtoadd);
2871 if (wkey) old_key = gtk_label_get_label (wkey);
2872 if (wlbl) old_label = gtk_label_get_label (wlbl);
2874 if (wkey && utf8_key && (! old_key || strcmp (utf8_key, old_key) != 0))
2875 gtk_label_set_text (wkey, utf8_key);
2877 if (! old_label || strcmp (utf8_label, old_label) != 0)
2878 gtk_label_set_text (wlbl, utf8_label);
2880 if (utf8_key) g_free (utf8_key);
2881 if (utf8_label) g_free (utf8_label);
2883 if (! val->enabled && gtk_widget_get_sensitive (w))
2884 gtk_widget_set_sensitive (w, FALSE);
2885 else if (val->enabled && ! gtk_widget_get_sensitive (w))
2886 gtk_widget_set_sensitive (w, TRUE);
2888 cb_data = (xg_menu_item_cb_data*) g_object_get_data (G_OBJECT (w),
2889 XG_ITEM_DATA);
2890 if (cb_data)
2892 cb_data->call_data = val->call_data;
2893 cb_data->help = val->help;
2894 cb_data->cl_data = cl_data;
2896 /* We assume the callback functions don't change. */
2897 if (val->call_data && ! val->contents)
2899 /* This item shall have a select callback. */
2900 if (! cb_data->select_id)
2901 cb_data->select_id
2902 = g_signal_connect (G_OBJECT (w), "activate",
2903 select_cb, cb_data);
2905 else if (cb_data->select_id)
2907 g_signal_handler_disconnect (w, cb_data->select_id);
2908 cb_data->select_id = 0;
2913 /* Update the toggle menu item W so it corresponds to VAL. */
2915 static void
2916 xg_update_toggle_item (widget_value *val, GtkWidget *w)
2918 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w), val->selected);
2921 /* Update the radio menu item W so it corresponds to VAL. */
2923 static void
2924 xg_update_radio_item (widget_value *val, GtkWidget *w)
2926 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w), val->selected);
2929 /* Update the sub menu SUBMENU and all its children so it corresponds to VAL.
2930 SUBMENU may be NULL, in that case a new menu is created.
2931 F is the frame the menu bar belongs to.
2932 VAL describes the contents of the menu bar.
2933 SELECT_CB is the callback to use when a menu item is selected.
2934 DEACTIVATE_CB is the callback to use when a sub menu is not shown anymore.
2935 HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
2936 CL_DATA is the call back data to use for any newly created items.
2938 Returns the updated submenu widget, that is SUBMENU unless SUBMENU
2939 was NULL. */
2941 static GtkWidget *
2942 xg_update_submenu (GtkWidget *submenu,
2943 FRAME_PTR f,
2944 widget_value *val,
2945 GCallback select_cb,
2946 GCallback deactivate_cb,
2947 GCallback highlight_cb,
2948 xg_menu_cb_data *cl_data)
2950 GtkWidget *newsub = submenu;
2951 GList *list = 0;
2952 GList *iter;
2953 widget_value *cur;
2954 int has_tearoff_p = 0;
2955 GList *first_radio = 0;
2957 if (submenu)
2958 list = gtk_container_get_children (GTK_CONTAINER (submenu));
2960 for (cur = val, iter = list;
2961 cur && iter;
2962 iter = g_list_next (iter), cur = cur->next)
2964 GtkWidget *w = GTK_WIDGET (iter->data);
2966 /* Skip tearoff items, they have no counterpart in val. */
2967 if (GTK_IS_TEAROFF_MENU_ITEM (w))
2969 has_tearoff_p = 1;
2970 iter = g_list_next (iter);
2971 if (iter) w = GTK_WIDGET (iter->data);
2972 else break;
2975 /* Remember first radio button in a group. If we get a mismatch in
2976 a radio group we must rebuild the whole group so that the connections
2977 in GTK becomes correct. */
2978 if (cur->button_type == BUTTON_TYPE_RADIO && ! first_radio)
2979 first_radio = iter;
2980 else if (cur->button_type != BUTTON_TYPE_RADIO
2981 && ! GTK_IS_RADIO_MENU_ITEM (w))
2982 first_radio = 0;
2984 if (GTK_IS_SEPARATOR_MENU_ITEM (w))
2986 if (! menu_separator_name_p (cur->name))
2987 break;
2989 else if (GTK_IS_CHECK_MENU_ITEM (w))
2991 if (cur->button_type != BUTTON_TYPE_TOGGLE)
2992 break;
2993 xg_update_toggle_item (cur, w);
2994 xg_update_menu_item (cur, w, select_cb, highlight_cb, cl_data);
2996 else if (GTK_IS_RADIO_MENU_ITEM (w))
2998 if (cur->button_type != BUTTON_TYPE_RADIO)
2999 break;
3000 xg_update_radio_item (cur, w);
3001 xg_update_menu_item (cur, w, select_cb, highlight_cb, cl_data);
3003 else if (GTK_IS_MENU_ITEM (w))
3005 GtkMenuItem *witem = GTK_MENU_ITEM (w);
3006 GtkWidget *sub;
3008 if (cur->button_type != BUTTON_TYPE_NONE ||
3009 menu_separator_name_p (cur->name))
3010 break;
3012 xg_update_menu_item (cur, w, select_cb, highlight_cb, cl_data);
3014 sub = gtk_menu_item_get_submenu (witem);
3015 if (sub && ! cur->contents)
3017 /* Not a submenu anymore. */
3018 g_object_ref (G_OBJECT (sub));
3019 remove_submenu (witem);
3020 gtk_widget_destroy (sub);
3022 else if (cur->contents)
3024 GtkWidget *nsub;
3026 nsub = xg_update_submenu (sub, f, cur->contents,
3027 select_cb, deactivate_cb,
3028 highlight_cb, cl_data);
3030 /* If this item just became a submenu, we must set it. */
3031 if (nsub != sub)
3032 gtk_menu_item_set_submenu (witem, nsub);
3035 else
3037 /* Structural difference. Remove everything from here and down
3038 in SUBMENU. */
3039 break;
3043 /* Remove widgets from first structual change. */
3044 if (iter)
3046 /* If we are adding new menu items below, we must remove from
3047 first radio button so that radio groups become correct. */
3048 if (cur && first_radio) xg_destroy_widgets (first_radio);
3049 else xg_destroy_widgets (iter);
3052 if (cur)
3054 /* More items added. Create them. */
3055 newsub = create_menus (cur,
3057 select_cb,
3058 deactivate_cb,
3059 highlight_cb,
3062 ! has_tearoff_p,
3063 submenu,
3064 cl_data,
3068 if (list) g_list_free (list);
3070 return newsub;
3073 /* Update the MENUBAR.
3074 F is the frame the menu bar belongs to.
3075 VAL describes the contents of the menu bar.
3076 If DEEP_P is non-zero, rebuild all but the top level menu names in
3077 the MENUBAR. If DEEP_P is zero, just rebuild the names in the menubar.
3078 SELECT_CB is the callback to use when a menu item is selected.
3079 DEACTIVATE_CB is the callback to use when a sub menu is not shown anymore.
3080 HIGHLIGHT_CB is the callback to call when entering/leaving menu items. */
3082 void
3083 xg_modify_menubar_widgets (GtkWidget *menubar, FRAME_PTR f, widget_value *val,
3084 int deep_p,
3085 GCallback select_cb, GCallback deactivate_cb,
3086 GCallback highlight_cb)
3088 xg_menu_cb_data *cl_data;
3089 GList *list = gtk_container_get_children (GTK_CONTAINER (menubar));
3091 if (! list) return;
3093 cl_data = (xg_menu_cb_data*) g_object_get_data (G_OBJECT (menubar),
3094 XG_FRAME_DATA);
3096 xg_update_menubar (menubar, f, &list, list, 0, val->contents,
3097 select_cb, deactivate_cb, highlight_cb, cl_data);
3099 if (deep_p)
3101 widget_value *cur;
3103 /* Update all sub menus.
3104 We must keep the submenus (GTK menu item widgets) since the
3105 X Window in the XEvent that activates the menu are those widgets. */
3107 /* Update cl_data, menu_item things in F may have changed. */
3108 update_cl_data (cl_data, f, highlight_cb);
3110 for (cur = val->contents; cur; cur = cur->next)
3112 GList *iter;
3113 GtkWidget *sub = 0;
3114 GtkWidget *newsub;
3115 GtkMenuItem *witem = 0;
3117 /* Find sub menu that corresponds to val and update it. */
3118 for (iter = list ; iter; iter = g_list_next (iter))
3120 witem = GTK_MENU_ITEM (iter->data);
3121 if (xg_item_label_same_p (witem, cur->name))
3123 sub = gtk_menu_item_get_submenu (witem);
3124 break;
3128 newsub = xg_update_submenu (sub,
3130 cur->contents,
3131 select_cb,
3132 deactivate_cb,
3133 highlight_cb,
3134 cl_data);
3135 /* sub may still be NULL. If we just updated non deep and added
3136 a new menu bar item, it has no sub menu yet. So we set the
3137 newly created sub menu under witem. */
3138 if (newsub != sub && witem != 0)
3140 xg_set_screen (newsub, f);
3141 gtk_menu_item_set_submenu (witem, newsub);
3146 g_list_free (list);
3147 gtk_widget_show_all (menubar);
3150 /* Callback called when the menu bar W is mapped.
3151 Used to find the height of the menu bar if we didn't get it
3152 after showing the widget. */
3154 static void
3155 menubar_map_cb (GtkWidget *w, gpointer user_data)
3157 GtkRequisition req;
3158 FRAME_PTR f = (FRAME_PTR) user_data;
3159 gtk_widget_get_preferred_size (w, NULL, &req);
3160 if (FRAME_MENUBAR_HEIGHT (f) != req.height)
3162 FRAME_MENUBAR_HEIGHT (f) = req.height;
3163 xg_height_or_width_changed (f);
3167 /* Recompute all the widgets of frame F, when the menu bar has been
3168 changed. Value is non-zero if widgets were updated. */
3171 xg_update_frame_menubar (FRAME_PTR f)
3173 struct x_output *x = f->output_data.x;
3174 GtkRequisition req;
3176 if (!x->menubar_widget || gtk_widget_get_mapped (x->menubar_widget))
3177 return 0;
3179 if (x->menubar_widget && gtk_widget_get_parent (x->menubar_widget))
3180 return 0; /* Already done this, happens for frames created invisible. */
3182 BLOCK_INPUT;
3184 gtk_box_pack_start (GTK_BOX (x->vbox_widget), x->menubar_widget,
3185 FALSE, FALSE, 0);
3186 gtk_box_reorder_child (GTK_BOX (x->vbox_widget), x->menubar_widget, 0);
3188 g_signal_connect (x->menubar_widget, "map", G_CALLBACK (menubar_map_cb), f);
3189 gtk_widget_show_all (x->menubar_widget);
3190 gtk_widget_get_preferred_size (x->menubar_widget, NULL, &req);
3192 /* If menu bar doesn't know its height yet, cheat a little so the frame
3193 doesn't jump so much when resized later in menubar_map_cb. */
3194 if (req.height == 0)
3195 req.height = 23;
3197 if (FRAME_MENUBAR_HEIGHT (f) != req.height)
3199 FRAME_MENUBAR_HEIGHT (f) = req.height;
3200 xg_height_or_width_changed (f);
3202 UNBLOCK_INPUT;
3204 return 1;
3207 /* Get rid of the menu bar of frame F, and free its storage.
3208 This is used when deleting a frame, and when turning off the menu bar. */
3210 void
3211 free_frame_menubar (FRAME_PTR f)
3213 struct x_output *x = f->output_data.x;
3215 if (x->menubar_widget)
3217 BLOCK_INPUT;
3219 gtk_container_remove (GTK_CONTAINER (x->vbox_widget), x->menubar_widget);
3220 /* The menubar and its children shall be deleted when removed from
3221 the container. */
3222 x->menubar_widget = 0;
3223 FRAME_MENUBAR_HEIGHT (f) = 0;
3224 xg_height_or_width_changed (f);
3225 UNBLOCK_INPUT;
3230 xg_event_is_for_menubar (FRAME_PTR f, XEvent *event)
3232 struct x_output *x = f->output_data.x;
3233 GList *iter;
3234 GdkRectangle rec;
3235 GList *list;
3236 GdkDisplay *gdpy;
3237 GdkWindow *gw;
3238 GdkEvent gevent;
3239 GtkWidget *gwdesc;
3241 if (! x->menubar_widget) return 0;
3243 if (! (event->xbutton.x >= 0
3244 && event->xbutton.x < FRAME_PIXEL_WIDTH (f)
3245 && event->xbutton.y >= 0
3246 && event->xbutton.y < f->output_data.x->menubar_height
3247 && event->xbutton.same_screen))
3248 return 0;
3250 gdpy = gdk_x11_lookup_xdisplay (FRAME_X_DISPLAY (f));
3251 gw = gdk_x11_window_lookup_for_display (gdpy, event->xbutton.window);
3252 if (! gw) return 0;
3253 gevent.any.window = gw;
3254 gwdesc = gtk_get_event_widget (&gevent);
3255 if (! gwdesc) return 0;
3256 if (! GTK_IS_MENU_BAR (gwdesc)
3257 && ! GTK_IS_MENU_ITEM (gwdesc)
3258 && ! gtk_widget_is_ancestor (x->menubar_widget, gwdesc))
3259 return 0;
3261 list = gtk_container_get_children (GTK_CONTAINER (x->menubar_widget));
3262 if (! list) return 0;
3263 rec.x = event->xbutton.x;
3264 rec.y = event->xbutton.y;
3265 rec.width = 1;
3266 rec.height = 1;
3268 for (iter = list ; iter; iter = g_list_next (iter))
3270 GtkWidget *w = GTK_WIDGET (iter->data);
3271 if (gtk_widget_get_mapped (w) && gtk_widget_intersect (w, &rec, NULL))
3272 break;
3274 g_list_free (list);
3275 return iter == 0 ? 0 : 1;
3280 /***********************************************************************
3281 Scroll bar functions
3282 ***********************************************************************/
3285 /* Setting scroll bar values invokes the callback. Use this variable
3286 to indicate that callback should do nothing. */
3288 int xg_ignore_gtk_scrollbar;
3290 /* The width of the scroll bar for the current theme. */
3292 static int scroll_bar_width_for_theme;
3294 /* Xlib's `Window' fits in 32 bits. But we want to store pointers, and they
3295 may be larger than 32 bits. Keep a mapping from integer index to widget
3296 pointers to get around the 32 bit limitation. */
3298 static struct
3300 GtkWidget **widgets;
3301 int max_size;
3302 int used;
3303 } id_to_widget;
3305 /* Grow this much every time we need to allocate more */
3307 #define ID_TO_WIDGET_INCR 32
3309 /* Store the widget pointer W in id_to_widget and return the integer index. */
3311 static int
3312 xg_store_widget_in_map (GtkWidget *w)
3314 int i;
3316 if (id_to_widget.max_size == id_to_widget.used)
3318 int new_size = id_to_widget.max_size + ID_TO_WIDGET_INCR;
3320 id_to_widget.widgets = xrealloc (id_to_widget.widgets,
3321 sizeof (GtkWidget *)*new_size);
3323 for (i = id_to_widget.max_size; i < new_size; ++i)
3324 id_to_widget.widgets[i] = 0;
3325 id_to_widget.max_size = new_size;
3328 /* Just loop over the array and find a free place. After all,
3329 how many scroll bars are we creating? Should be a small number.
3330 The check above guarantees we will find a free place. */
3331 for (i = 0; i < id_to_widget.max_size; ++i)
3333 if (! id_to_widget.widgets[i])
3335 id_to_widget.widgets[i] = w;
3336 ++id_to_widget.used;
3338 return i;
3342 /* Should never end up here */
3343 abort ();
3346 /* Remove pointer at IDX from id_to_widget.
3347 Called when scroll bar is destroyed. */
3349 static void
3350 xg_remove_widget_from_map (int idx)
3352 if (idx < id_to_widget.max_size && id_to_widget.widgets[idx] != 0)
3354 id_to_widget.widgets[idx] = 0;
3355 --id_to_widget.used;
3359 /* Get the widget pointer at IDX from id_to_widget. */
3361 static GtkWidget *
3362 xg_get_widget_from_map (int idx)
3364 if (idx < id_to_widget.max_size && id_to_widget.widgets[idx] != 0)
3365 return id_to_widget.widgets[idx];
3367 return 0;
3370 static void
3371 update_theme_scrollbar_width (void)
3373 #ifdef HAVE_GTK3
3374 GtkAdjustment *vadj;
3375 #else
3376 GtkObject *vadj;
3377 #endif
3378 GtkWidget *wscroll;
3379 int w = 0, b = 0;
3381 vadj = gtk_adjustment_new (XG_SB_MIN, XG_SB_MIN, XG_SB_MAX, 0.1, 0.1, 0.1);
3382 wscroll = gtk_vscrollbar_new (GTK_ADJUSTMENT (vadj));
3383 g_object_ref_sink (G_OBJECT (wscroll));
3384 gtk_widget_style_get (wscroll, "slider-width", &w, "trough-border", &b, NULL);
3385 gtk_widget_destroy (wscroll);
3386 g_object_unref (G_OBJECT (wscroll));
3387 w += 2*b;
3388 if (w < 16) w = 16;
3389 scroll_bar_width_for_theme = w;
3393 xg_get_default_scrollbar_width (void)
3395 return scroll_bar_width_for_theme;
3398 /* Return the scrollbar id for X Window WID on display DPY.
3399 Return -1 if WID not in id_to_widget. */
3402 xg_get_scroll_id_for_window (Display *dpy, Window wid)
3404 int idx;
3405 GtkWidget *w;
3407 w = xg_win_to_widget (dpy, wid);
3409 if (w)
3411 for (idx = 0; idx < id_to_widget.max_size; ++idx)
3412 if (id_to_widget.widgets[idx] == w)
3413 return idx;
3416 return -1;
3419 /* Callback invoked when scroll bar WIDGET is destroyed.
3420 DATA is the index into id_to_widget for WIDGET.
3421 We free pointer to last scroll bar values here and remove the index. */
3423 static void
3424 xg_gtk_scroll_destroy (GtkWidget *widget, gpointer data)
3426 int id = (intptr_t) data;
3427 xg_remove_widget_from_map (id);
3430 /* Create a scroll bar widget for frame F. Store the scroll bar
3431 in BAR.
3432 SCROLL_CALLBACK is the callback to invoke when the value of the
3433 bar changes.
3434 END_CALLBACK is the callback to invoke when scrolling ends.
3435 SCROLL_BAR_NAME is the name we use for the scroll bar. Can be used
3436 to set resources for the widget. */
3438 void
3439 xg_create_scroll_bar (FRAME_PTR f,
3440 struct scroll_bar *bar,
3441 GCallback scroll_callback,
3442 GCallback end_callback,
3443 const char *scroll_bar_name)
3445 GtkWidget *wscroll;
3446 GtkWidget *webox;
3447 intptr_t scroll_id;
3448 #ifdef HAVE_GTK3
3449 GtkAdjustment *vadj;
3450 #else
3451 GtkObject *vadj;
3452 #endif
3454 /* Page, step increment values are not so important here, they
3455 will be corrected in x_set_toolkit_scroll_bar_thumb. */
3456 vadj = gtk_adjustment_new (XG_SB_MIN, XG_SB_MIN, XG_SB_MAX,
3457 0.1, 0.1, 0.1);
3459 wscroll = gtk_vscrollbar_new (GTK_ADJUSTMENT (vadj));
3460 webox = gtk_event_box_new ();
3461 gtk_widget_set_name (wscroll, scroll_bar_name);
3462 #ifndef HAVE_GTK3
3463 gtk_range_set_update_policy (GTK_RANGE (wscroll), GTK_UPDATE_CONTINUOUS);
3464 #endif
3465 g_object_set_data (G_OBJECT (wscroll), XG_FRAME_DATA, (gpointer)f);
3467 scroll_id = xg_store_widget_in_map (wscroll);
3469 g_signal_connect (G_OBJECT (wscroll),
3470 "destroy",
3471 G_CALLBACK (xg_gtk_scroll_destroy),
3472 (gpointer) scroll_id);
3473 g_signal_connect (G_OBJECT (wscroll),
3474 "change-value",
3475 scroll_callback,
3476 (gpointer) bar);
3477 g_signal_connect (G_OBJECT (wscroll),
3478 "button-release-event",
3479 end_callback,
3480 (gpointer) bar);
3482 /* The scroll bar widget does not draw on a window of its own. Instead
3483 it draws on the parent window, in this case the edit widget. So
3484 whenever the edit widget is cleared, the scroll bar needs to redraw
3485 also, which causes flicker. Put an event box between the edit widget
3486 and the scroll bar, so the scroll bar instead draws itself on the
3487 event box window. */
3488 gtk_fixed_put (GTK_FIXED (f->output_data.x->edit_widget), webox, -1, -1);
3489 gtk_container_add (GTK_CONTAINER (webox), wscroll);
3492 /* Set the cursor to an arrow. */
3493 xg_set_cursor (webox, FRAME_X_DISPLAY_INFO (f)->xg_cursor);
3495 bar->x_window = scroll_id;
3498 /* Remove the scroll bar represented by SCROLLBAR_ID from the frame F. */
3500 void
3501 xg_remove_scroll_bar (FRAME_PTR f, int scrollbar_id)
3503 GtkWidget *w = xg_get_widget_from_map (scrollbar_id);
3504 if (w)
3506 GtkWidget *wparent = gtk_widget_get_parent (w);
3507 gtk_widget_destroy (w);
3508 gtk_widget_destroy (wparent);
3509 SET_FRAME_GARBAGED (f);
3513 /* Update the position of the vertical scroll bar represented by SCROLLBAR_ID
3514 in frame F.
3515 TOP/LEFT are the new pixel positions where the bar shall appear.
3516 WIDTH, HEIGHT is the size in pixels the bar shall have. */
3518 void
3519 xg_update_scrollbar_pos (FRAME_PTR f,
3520 int scrollbar_id,
3521 int top,
3522 int left,
3523 int width,
3524 int height)
3527 GtkWidget *wscroll = xg_get_widget_from_map (scrollbar_id);
3529 if (wscroll)
3531 GtkWidget *wfixed = f->output_data.x->edit_widget;
3532 GtkWidget *wparent = gtk_widget_get_parent (wscroll);
3533 gint msl;
3535 /* Clear out old position. */
3536 int oldx = -1, oldy = -1, oldw, oldh;
3537 if (gtk_widget_get_parent (wparent) == wfixed)
3539 gtk_container_child_get (GTK_CONTAINER (wfixed), wparent,
3540 "x", &oldx, "y", &oldy, NULL);
3541 gtk_widget_get_size_request (wscroll, &oldw, &oldh);
3544 /* Move and resize to new values. */
3545 gtk_fixed_move (GTK_FIXED (wfixed), wparent, left, top);
3546 gtk_widget_style_get (wscroll, "min-slider-length", &msl, NULL);
3547 if (msl > height)
3549 /* No room. Hide scroll bar as some themes output a warning if
3550 the height is less than the min size. */
3551 gtk_widget_hide (wparent);
3552 gtk_widget_hide (wscroll);
3554 else
3556 gtk_widget_show_all (wparent);
3557 gtk_widget_set_size_request (wscroll, width, height);
3559 gtk_widget_queue_draw (wfixed);
3560 gdk_window_process_all_updates ();
3561 if (oldx != -1 && oldw > 0 && oldh > 0)
3563 /* Clear under old scroll bar position. This must be done after
3564 the gtk_widget_queue_draw and gdk_window_process_all_updates
3565 above. */
3566 x_clear_area (FRAME_X_DISPLAY (f),
3567 FRAME_X_WINDOW (f),
3568 oldx, oldy, oldw, oldh, 0);
3571 /* GTK does not redraw until the main loop is entered again, but
3572 if there are no X events pending we will not enter it. So we sync
3573 here to get some events. */
3575 x_sync (f);
3576 SET_FRAME_GARBAGED (f);
3577 cancel_mouse_face (f);
3581 /* Get the current value of the range, truncated to an integer. */
3583 static int
3584 int_gtk_range_get_value (GtkRange *range)
3586 return gtk_range_get_value (range);
3590 /* Set the thumb size and position of scroll bar BAR. We are currently
3591 displaying PORTION out of a whole WHOLE, and our position POSITION. */
3593 void
3594 xg_set_toolkit_scroll_bar_thumb (struct scroll_bar *bar,
3595 int portion,
3596 int position,
3597 int whole)
3599 GtkWidget *wscroll = xg_get_widget_from_map (bar->x_window);
3601 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
3603 if (wscroll && NILP (bar->dragging))
3605 GtkAdjustment *adj;
3606 gdouble shown;
3607 gdouble top;
3608 int size, value;
3609 int old_size;
3610 int new_step;
3611 int changed = 0;
3613 adj = gtk_range_get_adjustment (GTK_RANGE (wscroll));
3615 /* We do the same as for MOTIF in xterm.c, assume 30 chars per line
3616 rather than the real portion value. This makes the thumb less likely
3617 to resize and that looks better. */
3618 portion = WINDOW_TOTAL_LINES (XWINDOW (bar->window)) * 30;
3619 /* When the thumb is at the bottom, position == whole.
3620 So we need to increase `whole' to make space for the thumb. */
3621 whole += portion;
3623 if (whole <= 0)
3624 top = 0, shown = 1;
3625 else
3627 top = (gdouble) position / whole;
3628 shown = (gdouble) portion / whole;
3631 size = shown * XG_SB_RANGE;
3632 size = min (size, XG_SB_RANGE);
3633 size = max (size, 1);
3635 value = top * XG_SB_RANGE;
3636 value = min (value, XG_SB_MAX - size);
3637 value = max (value, XG_SB_MIN);
3639 /* Assume all lines are of equal size. */
3640 new_step = size / max (1, FRAME_LINES (f));
3642 old_size = gtk_adjustment_get_page_size (adj);
3643 if (old_size != size)
3645 int old_step = gtk_adjustment_get_step_increment (adj);
3646 if (old_step != new_step)
3648 gtk_adjustment_set_page_size (adj, size);
3649 gtk_adjustment_set_step_increment (adj, new_step);
3650 /* Assume a page increment is about 95% of the page size */
3651 gtk_adjustment_set_page_increment (adj,(int) (0.95*size));
3652 changed = 1;
3656 if (changed || int_gtk_range_get_value (GTK_RANGE (wscroll)) != value)
3658 BLOCK_INPUT;
3660 /* gtk_range_set_value invokes the callback. Set
3661 ignore_gtk_scrollbar to make the callback do nothing */
3662 xg_ignore_gtk_scrollbar = 1;
3664 if (int_gtk_range_get_value (GTK_RANGE (wscroll)) != value)
3665 gtk_range_set_value (GTK_RANGE (wscroll), (gdouble)value);
3666 else if (changed)
3667 gtk_adjustment_changed (adj);
3669 xg_ignore_gtk_scrollbar = 0;
3671 UNBLOCK_INPUT;
3676 /* Return non-zero if EVENT is for a scroll bar in frame F.
3677 When the same X window is used for several Gtk+ widgets, we cannot
3678 say for sure based on the X window alone if an event is for the
3679 frame. This function does additional checks.
3681 Return non-zero if the event is for a scroll bar, zero otherwise. */
3684 xg_event_is_for_scrollbar (FRAME_PTR f, XEvent *event)
3686 int retval = 0;
3688 if (f && event->type == ButtonPress && event->xbutton.button < 4)
3690 /* Check if press occurred outside the edit widget. */
3691 GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (FRAME_X_DISPLAY (f));
3692 retval = gdk_display_get_window_at_pointer (gdpy, NULL, NULL)
3693 != gtk_widget_get_window (f->output_data.x->edit_widget);
3695 else if (f
3696 && ((event->type == ButtonRelease && event->xbutton.button < 4)
3697 || event->type == MotionNotify))
3699 /* If we are releasing or moving the scroll bar, it has the grab. */
3700 GtkWidget *w = gtk_grab_get_current ();
3701 retval = w != 0 && GTK_IS_SCROLLBAR (w);
3704 return retval;
3709 /***********************************************************************
3710 Tool bar functions
3711 ***********************************************************************/
3712 /* The key for the data we put in the GtkImage widgets. The data is
3713 the image used by Emacs. We use this to see if we need to update
3714 the GtkImage with a new image. */
3715 #define XG_TOOL_BAR_IMAGE_DATA "emacs-tool-bar-image"
3717 /* The key for storing the latest modifiers so the activate callback can
3718 get them. */
3719 #define XG_TOOL_BAR_LAST_MODIFIER "emacs-tool-bar-modifier"
3721 /* The key for storing the button widget in its proxy menu item. */
3722 #define XG_TOOL_BAR_PROXY_BUTTON "emacs-tool-bar-proxy-button"
3724 /* The key for the data we put in the GtkImage widgets. The data is
3725 the stock name used by Emacs. We use this to see if we need to update
3726 the GtkImage with a new image. */
3727 #define XG_TOOL_BAR_STOCK_NAME "emacs-tool-bar-stock-name"
3729 /* As above, but this is used for named theme widgets, as opposed to
3730 stock items. */
3731 #define XG_TOOL_BAR_ICON_NAME "emacs-tool-bar-icon-name"
3733 /* Callback function invoked when a tool bar item is pressed.
3734 W is the button widget in the tool bar that got pressed,
3735 CLIENT_DATA is an integer that is the index of the button in the
3736 tool bar. 0 is the first button. */
3738 static gboolean
3739 xg_tool_bar_button_cb (GtkWidget *widget,
3740 GdkEventButton *event,
3741 gpointer user_data)
3743 intptr_t state = event->state;
3744 gpointer ptr = (gpointer) state;
3745 g_object_set_data (G_OBJECT (widget), XG_TOOL_BAR_LAST_MODIFIER, ptr);
3746 return FALSE;
3750 /* Callback function invoked when a tool bar item is pressed.
3751 W is the button widget in the tool bar that got pressed,
3752 CLIENT_DATA is an integer that is the index of the button in the
3753 tool bar. 0 is the first button. */
3755 static void
3756 xg_tool_bar_callback (GtkWidget *w, gpointer client_data)
3758 intptr_t idx = (intptr_t) client_data;
3759 gpointer gmod = g_object_get_data (G_OBJECT (w), XG_TOOL_BAR_LAST_MODIFIER);
3760 intptr_t mod = (intptr_t) gmod;
3762 FRAME_PTR f = (FRAME_PTR) g_object_get_data (G_OBJECT (w), XG_FRAME_DATA);
3763 Lisp_Object key, frame;
3764 struct input_event event;
3765 EVENT_INIT (event);
3767 if (! f || ! f->n_tool_bar_items || NILP (f->tool_bar_items))
3768 return;
3770 idx *= TOOL_BAR_ITEM_NSLOTS;
3772 key = AREF (f->tool_bar_items, idx + TOOL_BAR_ITEM_KEY);
3773 XSETFRAME (frame, f);
3775 /* We generate two events here. The first one is to set the prefix
3776 to `(tool_bar)', see keyboard.c. */
3777 event.kind = TOOL_BAR_EVENT;
3778 event.frame_or_window = frame;
3779 event.arg = frame;
3780 kbd_buffer_store_event (&event);
3782 event.kind = TOOL_BAR_EVENT;
3783 event.frame_or_window = frame;
3784 event.arg = key;
3785 /* Convert between the modifier bits GDK uses and the modifier bits
3786 Emacs uses. This assumes GDK and X masks are the same, which they are when
3787 this is written. */
3788 event.modifiers = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f), mod);
3789 kbd_buffer_store_event (&event);
3791 /* Return focus to the frame after we have clicked on a detached
3792 tool bar button. */
3793 Fx_focus_frame (frame);
3796 /* Callback function invoked when a tool bar item is pressed in a detached
3797 tool bar or the overflow drop down menu.
3798 We just call xg_tool_bar_callback.
3799 W is the menu item widget that got pressed,
3800 CLIENT_DATA is an integer that is the index of the button in the
3801 tool bar. 0 is the first button. */
3803 static void
3804 xg_tool_bar_proxy_callback (GtkWidget *w, gpointer client_data)
3806 GtkWidget *wbutton = GTK_WIDGET (g_object_get_data (G_OBJECT (w),
3807 XG_TOOL_BAR_PROXY_BUTTON));
3808 xg_tool_bar_callback (wbutton, client_data);
3812 static gboolean
3813 xg_tool_bar_help_callback (GtkWidget *w,
3814 GdkEventCrossing *event,
3815 gpointer client_data);
3817 /* This callback is called when a help is to be shown for an item in
3818 the detached tool bar when the detached tool bar it is not expanded. */
3820 static gboolean
3821 xg_tool_bar_proxy_help_callback (GtkWidget *w,
3822 GdkEventCrossing *event,
3823 gpointer client_data)
3825 GtkWidget *wbutton = GTK_WIDGET (g_object_get_data (G_OBJECT (w),
3826 XG_TOOL_BAR_PROXY_BUTTON));
3828 return xg_tool_bar_help_callback (wbutton, event, client_data);
3831 static GtkWidget *
3832 xg_get_tool_bar_widgets (GtkWidget *vb, GtkWidget **wimage)
3834 GList *clist = gtk_container_get_children (GTK_CONTAINER (vb));
3835 GtkWidget *c1 = (GtkWidget *) clist->data;
3836 GtkWidget *c2 = clist->next ? (GtkWidget *) clist->next->data : NULL;
3838 *wimage = GTK_IS_IMAGE (c1) ? c1 : c2;
3839 g_list_free (clist);
3840 return GTK_IS_LABEL (c1) ? c1 : c2;
3844 /* This callback is called when a tool item should create a proxy item,
3845 such as for the overflow menu. Also called when the tool bar is detached.
3846 If we don't create a proxy menu item, the detached tool bar will be
3847 blank. */
3849 static gboolean
3850 xg_tool_bar_menu_proxy (GtkToolItem *toolitem, gpointer user_data)
3852 GtkButton *wbutton = GTK_BUTTON (XG_BIN_CHILD (XG_BIN_CHILD (toolitem)));
3853 GtkWidget *vb = XG_BIN_CHILD (wbutton);
3854 GtkWidget *c1;
3855 GtkLabel *wlbl = GTK_LABEL (xg_get_tool_bar_widgets (vb, &c1));
3856 GtkImage *wimage = GTK_IMAGE (c1);
3857 GtkWidget *wmenuitem = gtk_image_menu_item_new_with_label
3858 (wlbl ? gtk_label_get_text (wlbl) : "");
3859 GtkWidget *wmenuimage;
3862 if (gtk_button_get_use_stock (wbutton))
3863 wmenuimage = gtk_image_new_from_stock (gtk_button_get_label (wbutton),
3864 GTK_ICON_SIZE_MENU);
3865 else
3867 GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (wbutton));
3868 GtkImageType store_type = gtk_image_get_storage_type (wimage);
3870 g_object_set (G_OBJECT (settings), "gtk-menu-images", TRUE, NULL);
3872 if (store_type == GTK_IMAGE_STOCK)
3874 gchar *stock_id;
3875 gtk_image_get_stock (wimage, &stock_id, NULL);
3876 wmenuimage = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_MENU);
3878 else if (store_type == GTK_IMAGE_ICON_SET)
3880 GtkIconSet *icon_set;
3881 gtk_image_get_icon_set (wimage, &icon_set, NULL);
3882 wmenuimage = gtk_image_new_from_icon_set (icon_set,
3883 GTK_ICON_SIZE_MENU);
3885 else if (store_type == GTK_IMAGE_PIXBUF)
3887 gint width, height;
3889 if (settings &&
3890 gtk_icon_size_lookup_for_settings (settings, GTK_ICON_SIZE_MENU,
3891 &width, &height))
3893 GdkPixbuf *src_pixbuf, *dest_pixbuf;
3895 src_pixbuf = gtk_image_get_pixbuf (wimage);
3896 dest_pixbuf = gdk_pixbuf_scale_simple (src_pixbuf, width, height,
3897 GDK_INTERP_BILINEAR);
3899 wmenuimage = gtk_image_new_from_pixbuf (dest_pixbuf);
3901 else
3903 fprintf (stderr, "internal error: GTK_IMAGE_PIXBUF failed\n");
3904 abort ();
3907 else if (store_type == GTK_IMAGE_ICON_NAME)
3909 const gchar *icon_name;
3910 GtkIconSize icon_size;
3912 gtk_image_get_icon_name (wimage, &icon_name, &icon_size);
3913 wmenuimage = gtk_image_new_from_icon_name (icon_name,
3914 GTK_ICON_SIZE_MENU);
3916 else
3918 fprintf (stderr, "internal error: store_type is %d\n", store_type);
3919 abort ();
3922 if (wmenuimage)
3923 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (wmenuitem), wmenuimage);
3925 g_signal_connect (G_OBJECT (wmenuitem),
3926 "activate",
3927 G_CALLBACK (xg_tool_bar_proxy_callback),
3928 user_data);
3931 g_object_set_data (G_OBJECT (wmenuitem), XG_TOOL_BAR_PROXY_BUTTON,
3932 (gpointer) wbutton);
3933 gtk_tool_item_set_proxy_menu_item (toolitem, "Emacs toolbar item", wmenuitem);
3934 gtk_widget_set_sensitive (wmenuitem,
3935 gtk_widget_get_sensitive (GTK_WIDGET (wbutton)));
3937 /* Use enter/leave notify to show help. We use the events
3938 rather than the GtkButton specific signals "enter" and
3939 "leave", so we can have only one callback. The event
3940 will tell us what kind of event it is. */
3941 g_signal_connect (G_OBJECT (wmenuitem),
3942 "enter-notify-event",
3943 G_CALLBACK (xg_tool_bar_proxy_help_callback),
3944 user_data);
3945 g_signal_connect (G_OBJECT (wmenuitem),
3946 "leave-notify-event",
3947 G_CALLBACK (xg_tool_bar_proxy_help_callback),
3948 user_data);
3950 return TRUE;
3953 /* This callback is called when a tool bar is detached. We must set
3954 the height of the tool bar to zero when this happens so frame sizes
3955 are correctly calculated.
3956 WBOX is the handle box widget that enables detach/attach of the tool bar.
3957 W is the tool bar widget.
3958 CLIENT_DATA is a pointer to the frame the tool bar belongs to. */
3960 static void
3961 xg_tool_bar_detach_callback (GtkHandleBox *wbox,
3962 GtkWidget *w,
3963 gpointer client_data)
3965 FRAME_PTR f = (FRAME_PTR) client_data;
3967 g_object_set (G_OBJECT (w), "show-arrow", !x_gtk_whole_detached_tool_bar,
3968 NULL);
3970 if (f)
3972 GtkRequisition req, req2;
3973 FRAME_X_OUTPUT (f)->toolbar_detached = 1;
3974 gtk_widget_get_preferred_size (GTK_WIDGET (wbox), NULL, &req);
3975 gtk_widget_get_preferred_size (w, NULL, &req2);
3976 req.width -= req2.width;
3977 req.height -= req2.height;
3978 if (FRAME_TOOLBAR_TOP_HEIGHT (f) != 0)
3979 FRAME_TOOLBAR_TOP_HEIGHT (f) = req.height;
3980 else if (FRAME_TOOLBAR_BOTTOM_HEIGHT (f) != 0)
3981 FRAME_TOOLBAR_BOTTOM_HEIGHT (f) = req.height;
3982 else if (FRAME_TOOLBAR_RIGHT_WIDTH (f) != 0)
3983 FRAME_TOOLBAR_RIGHT_WIDTH (f) = req.width;
3984 else if (FRAME_TOOLBAR_LEFT_WIDTH (f) != 0)
3985 FRAME_TOOLBAR_LEFT_WIDTH (f) = req.width;
3986 xg_height_or_width_changed (f);
3990 /* This callback is called when a tool bar is reattached. We must set
3991 the height of the tool bar when this happens so frame sizes
3992 are correctly calculated.
3993 WBOX is the handle box widget that enables detach/attach of the tool bar.
3994 W is the tool bar widget.
3995 CLIENT_DATA is a pointer to the frame the tool bar belongs to. */
3997 static void
3998 xg_tool_bar_attach_callback (GtkHandleBox *wbox,
3999 GtkWidget *w,
4000 gpointer client_data)
4002 FRAME_PTR f = (FRAME_PTR) client_data;
4003 g_object_set (G_OBJECT (w), "show-arrow", TRUE, NULL);
4005 if (f)
4007 GtkRequisition req, req2;
4008 FRAME_X_OUTPUT (f)->toolbar_detached = 0;
4009 gtk_widget_get_preferred_size (GTK_WIDGET (wbox), NULL, &req);
4010 gtk_widget_get_preferred_size (w, NULL, &req2);
4011 req.width += req2.width;
4012 req.height += req2.height;
4013 if (FRAME_TOOLBAR_TOP_HEIGHT (f) != 0)
4014 FRAME_TOOLBAR_TOP_HEIGHT (f) = req.height;
4015 else if (FRAME_TOOLBAR_BOTTOM_HEIGHT (f) != 0)
4016 FRAME_TOOLBAR_BOTTOM_HEIGHT (f) = req.height;
4017 else if (FRAME_TOOLBAR_RIGHT_WIDTH (f) != 0)
4018 FRAME_TOOLBAR_RIGHT_WIDTH (f) = req.width;
4019 else if (FRAME_TOOLBAR_LEFT_WIDTH (f) != 0)
4020 FRAME_TOOLBAR_LEFT_WIDTH (f) = req.width;
4021 xg_height_or_width_changed (f);
4025 /* This callback is called when the mouse enters or leaves a tool bar item.
4026 It is used for displaying and hiding the help text.
4027 W is the tool bar item, a button.
4028 EVENT is either an enter event or leave event.
4029 CLIENT_DATA is an integer that is the index of the button in the
4030 tool bar. 0 is the first button.
4032 Returns FALSE to tell GTK to keep processing this event. */
4034 static gboolean
4035 xg_tool_bar_help_callback (GtkWidget *w,
4036 GdkEventCrossing *event,
4037 gpointer client_data)
4039 intptr_t idx = (intptr_t) client_data;
4040 FRAME_PTR f = (FRAME_PTR) g_object_get_data (G_OBJECT (w), XG_FRAME_DATA);
4041 Lisp_Object help, frame;
4043 if (! f || ! f->n_tool_bar_items || NILP (f->tool_bar_items))
4044 return FALSE;
4046 if (event->type == GDK_ENTER_NOTIFY)
4048 idx *= TOOL_BAR_ITEM_NSLOTS;
4049 help = AREF (f->tool_bar_items, idx + TOOL_BAR_ITEM_HELP);
4051 if (NILP (help))
4052 help = AREF (f->tool_bar_items, idx + TOOL_BAR_ITEM_CAPTION);
4054 else
4055 help = Qnil;
4057 XSETFRAME (frame, f);
4058 kbd_buffer_store_help_event (frame, help);
4060 return FALSE;
4064 /* This callback is called when a tool bar item shall be redrawn.
4065 It modifies the expose event so that the GtkImage widget redraws the
4066 whole image. This to overcome a bug that makes GtkImage draw the image
4067 in the wrong place when it tries to redraw just a part of the image.
4068 W is the GtkImage to be redrawn.
4069 EVENT is the expose event for W.
4070 CLIENT_DATA is unused.
4072 Returns FALSE to tell GTK to keep processing this event. */
4074 #ifndef HAVE_GTK3
4075 static gboolean
4076 xg_tool_bar_item_expose_callback (GtkWidget *w,
4077 GdkEventExpose *event,
4078 gpointer client_data)
4080 gint width, height;
4082 gdk_drawable_get_size (event->window, &width, &height);
4083 event->area.x -= width > event->area.width ? width-event->area.width : 0;
4084 event->area.y -= height > event->area.height ? height-event->area.height : 0;
4086 event->area.x = max (0, event->area.x);
4087 event->area.y = max (0, event->area.y);
4089 event->area.width = max (width, event->area.width);
4090 event->area.height = max (height, event->area.height);
4092 return FALSE;
4094 #endif
4096 #ifdef HAVE_GTK_ORIENTABLE_SET_ORIENTATION
4097 #define toolbar_set_orientation(w, o) \
4098 gtk_orientable_set_orientation (GTK_ORIENTABLE (w), o)
4099 #else
4100 #define toolbar_set_orientation(w, o) \
4101 gtk_toolbar_set_orientation (GTK_TOOLBAR (w), o)
4102 #endif
4104 /* Attach a tool bar to frame F. */
4106 static void
4107 xg_pack_tool_bar (FRAME_PTR f, Lisp_Object pos)
4109 struct x_output *x = f->output_data.x;
4110 int into_hbox = EQ (pos, Qleft) || EQ (pos, Qright);
4112 toolbar_set_orientation (x->toolbar_widget,
4113 into_hbox
4114 ? GTK_ORIENTATION_VERTICAL
4115 : GTK_ORIENTATION_HORIZONTAL);
4116 if (!x->handlebox_widget)
4118 x->handlebox_widget = gtk_handle_box_new ();
4119 g_signal_connect (G_OBJECT (x->handlebox_widget), "child-detached",
4120 G_CALLBACK (xg_tool_bar_detach_callback), f);
4121 g_signal_connect (G_OBJECT (x->handlebox_widget), "child-attached",
4122 G_CALLBACK (xg_tool_bar_attach_callback), f);
4123 gtk_container_add (GTK_CONTAINER (x->handlebox_widget),
4124 x->toolbar_widget);
4127 if (into_hbox)
4129 gtk_handle_box_set_handle_position (GTK_HANDLE_BOX (x->handlebox_widget),
4130 GTK_POS_TOP);
4131 gtk_box_pack_start (GTK_BOX (x->hbox_widget), x->handlebox_widget,
4132 FALSE, FALSE, 0);
4134 if (EQ (pos, Qleft))
4135 gtk_box_reorder_child (GTK_BOX (x->hbox_widget),
4136 x->handlebox_widget,
4138 x->toolbar_in_hbox = 1;
4140 else
4142 int vbox_pos = x->menubar_widget ? 1 : 0;
4143 gtk_handle_box_set_handle_position (GTK_HANDLE_BOX (x->handlebox_widget),
4144 GTK_POS_LEFT);
4145 gtk_box_pack_start (GTK_BOX (x->vbox_widget), x->handlebox_widget,
4146 FALSE, FALSE, 0);
4148 if (EQ (pos, Qtop))
4149 gtk_box_reorder_child (GTK_BOX (x->vbox_widget),
4150 x->handlebox_widget,
4151 vbox_pos);
4152 x->toolbar_in_hbox = 0;
4156 /* Create a tool bar for frame F. */
4158 static void
4159 xg_create_tool_bar (FRAME_PTR f)
4161 struct x_output *x = f->output_data.x;
4163 x->toolbar_widget = gtk_toolbar_new ();
4164 x->toolbar_detached = 0;
4166 gtk_widget_set_name (x->toolbar_widget, "emacs-toolbar");
4168 gtk_toolbar_set_style (GTK_TOOLBAR (x->toolbar_widget), GTK_TOOLBAR_ICONS);
4169 toolbar_set_orientation (x->toolbar_widget, GTK_ORIENTATION_HORIZONTAL);
4173 #define PROP(IDX) AREF (f->tool_bar_items, i * TOOL_BAR_ITEM_NSLOTS + (IDX))
4175 /* Find the right-to-left image named by RTL in the tool bar images for F.
4176 Returns IMAGE if RTL is not found. */
4178 static Lisp_Object
4179 find_rtl_image (FRAME_PTR f, Lisp_Object image, Lisp_Object rtl)
4181 int i;
4182 Lisp_Object file, rtl_name;
4183 struct gcpro gcpro1, gcpro2;
4184 GCPRO2 (file, rtl_name);
4186 rtl_name = Ffile_name_nondirectory (rtl);
4188 for (i = 0; i < f->n_tool_bar_items; ++i)
4190 Lisp_Object rtl_image = PROP (TOOL_BAR_ITEM_IMAGES);
4191 if (!NILP (file = file_for_image (rtl_image)))
4193 file = call1 (intern ("file-name-sans-extension"),
4194 Ffile_name_nondirectory (file));
4195 if (EQ (Fequal (file, rtl_name), Qt))
4197 image = rtl_image;
4198 break;
4203 return image;
4206 static GtkToolItem *
4207 xg_make_tool_item (FRAME_PTR f,
4208 GtkWidget *wimage,
4209 GtkWidget **wbutton,
4210 const char *label,
4211 int i, int horiz, int text_image)
4213 GtkToolItem *ti = gtk_tool_item_new ();
4214 GtkWidget *vb = horiz ? gtk_hbox_new (FALSE, 0) : gtk_vbox_new (FALSE, 0);
4215 GtkWidget *wb = gtk_button_new ();
4216 GtkWidget *weventbox = gtk_event_box_new ();
4218 if (wimage && !text_image)
4219 gtk_box_pack_start (GTK_BOX (vb), wimage, TRUE, TRUE, 0);
4220 if (label)
4221 gtk_box_pack_start (GTK_BOX (vb), gtk_label_new (label), TRUE, TRUE, 0);
4222 if (wimage && text_image)
4223 gtk_box_pack_start (GTK_BOX (vb), wimage, TRUE, TRUE, 0);
4225 gtk_button_set_focus_on_click (GTK_BUTTON (wb), FALSE);
4226 gtk_button_set_relief (GTK_BUTTON (wb), GTK_RELIEF_NONE);
4227 gtk_container_add (GTK_CONTAINER (wb), vb);
4228 gtk_container_add (GTK_CONTAINER (weventbox), wb);
4229 gtk_container_add (GTK_CONTAINER (ti), weventbox);
4231 if (wimage)
4233 intptr_t ii = i;
4234 gpointer gi = (gpointer) ii;
4236 g_signal_connect (G_OBJECT (ti), "create-menu-proxy",
4237 G_CALLBACK (xg_tool_bar_menu_proxy),
4238 gi);
4240 g_signal_connect (G_OBJECT (wb), "clicked",
4241 G_CALLBACK (xg_tool_bar_callback),
4242 gi);
4244 g_object_set_data (G_OBJECT (weventbox), XG_FRAME_DATA, (gpointer)f);
4246 #ifndef HAVE_GTK3
4247 /* Catch expose events to overcome an annoying redraw bug, see
4248 comment for xg_tool_bar_item_expose_callback. */
4249 g_signal_connect (G_OBJECT (ti),
4250 "expose-event",
4251 G_CALLBACK (xg_tool_bar_item_expose_callback),
4253 #endif
4254 gtk_tool_item_set_homogeneous (ti, FALSE);
4256 /* Callback to save modifyer mask (Shift/Control, etc). GTK makes
4257 no distinction based on modifiers in the activate callback,
4258 so we have to do it ourselves. */
4259 g_signal_connect (wb, "button-release-event",
4260 G_CALLBACK (xg_tool_bar_button_cb),
4261 NULL);
4263 g_object_set_data (G_OBJECT (wb), XG_FRAME_DATA, (gpointer)f);
4265 /* Use enter/leave notify to show help. We use the events
4266 rather than the GtkButton specific signals "enter" and
4267 "leave", so we can have only one callback. The event
4268 will tell us what kind of event it is. */
4269 /* The EMACS_INT cast avoids a warning. */
4270 g_signal_connect (G_OBJECT (weventbox),
4271 "enter-notify-event",
4272 G_CALLBACK (xg_tool_bar_help_callback),
4273 gi);
4274 g_signal_connect (G_OBJECT (weventbox),
4275 "leave-notify-event",
4276 G_CALLBACK (xg_tool_bar_help_callback),
4277 gi);
4280 if (wbutton) *wbutton = wb;
4282 return ti;
4285 static int
4286 xg_tool_item_stale_p (GtkWidget *wbutton, const char *stock_name,
4287 const char *icon_name, const struct image *img,
4288 const char *label, int horiz)
4290 gpointer old;
4291 GtkWidget *wimage;
4292 GtkWidget *vb = XG_BIN_CHILD (wbutton);
4293 GtkWidget *wlbl = xg_get_tool_bar_widgets (vb, &wimage);
4295 /* Check if the tool icon matches. */
4296 if (stock_name)
4298 old = g_object_get_data (G_OBJECT (wimage),
4299 XG_TOOL_BAR_STOCK_NAME);
4300 if (!old || strcmp (old, stock_name))
4301 return 1;
4303 else if (icon_name)
4305 old = g_object_get_data (G_OBJECT (wimage),
4306 XG_TOOL_BAR_ICON_NAME);
4307 if (!old || strcmp (old, icon_name))
4308 return 1;
4310 else
4312 gpointer gold_img = g_object_get_data (G_OBJECT (wimage),
4313 XG_TOOL_BAR_IMAGE_DATA);
4314 Pixmap old_img = (Pixmap) gold_img;
4315 if (old_img != img->pixmap)
4316 return 1;
4319 /* Check button configuration and label. */
4320 if ((horiz ? GTK_IS_VBOX (vb) : GTK_IS_HBOX (vb))
4321 || (label ? (wlbl == NULL) : (wlbl != NULL)))
4322 return 1;
4324 /* Ensure label is correct. */
4325 if (label)
4326 gtk_label_set_text (GTK_LABEL (wlbl), label);
4327 return 0;
4330 static int
4331 xg_update_tool_bar_sizes (FRAME_PTR f)
4333 struct x_output *x = f->output_data.x;
4334 GtkRequisition req;
4335 int nl = 0, nr = 0, nt = 0, nb = 0;
4337 gtk_widget_get_preferred_size (GTK_WIDGET (x->handlebox_widget), NULL, &req);
4338 if (x->toolbar_in_hbox)
4340 int pos;
4341 gtk_container_child_get (GTK_CONTAINER (x->hbox_widget),
4342 x->handlebox_widget,
4343 "position", &pos, NULL);
4344 if (pos == 0) nl = req.width;
4345 else nr = req.width;
4347 else
4349 int pos;
4350 gtk_container_child_get (GTK_CONTAINER (x->vbox_widget),
4351 x->handlebox_widget,
4352 "position", &pos, NULL);
4353 if (pos == 0 || (pos == 1 && x->menubar_widget)) nt = req.height;
4354 else nb = req.height;
4357 if (nl != FRAME_TOOLBAR_LEFT_WIDTH (f)
4358 || nr != FRAME_TOOLBAR_RIGHT_WIDTH (f)
4359 || nt != FRAME_TOOLBAR_TOP_HEIGHT (f)
4360 || nb != FRAME_TOOLBAR_BOTTOM_HEIGHT (f))
4362 FRAME_TOOLBAR_RIGHT_WIDTH (f) = FRAME_TOOLBAR_LEFT_WIDTH (f)
4363 = FRAME_TOOLBAR_TOP_HEIGHT (f) = FRAME_TOOLBAR_BOTTOM_HEIGHT (f) = 0;
4364 FRAME_TOOLBAR_LEFT_WIDTH (f) = nl;
4365 FRAME_TOOLBAR_RIGHT_WIDTH (f) = nr;
4366 FRAME_TOOLBAR_TOP_HEIGHT (f) = nt;
4367 FRAME_TOOLBAR_BOTTOM_HEIGHT (f) = nb;
4368 return 1;
4371 return 0;
4375 /* Update the tool bar for frame F. Add new buttons and remove old. */
4377 void
4378 update_frame_tool_bar (FRAME_PTR f)
4380 int i, j;
4381 struct x_output *x = f->output_data.x;
4382 int hmargin = 0, vmargin = 0;
4383 GtkToolbar *wtoolbar;
4384 GtkToolItem *ti;
4385 GtkTextDirection dir;
4386 int pack_tool_bar = x->handlebox_widget == NULL;
4387 Lisp_Object style;
4388 int text_image, horiz;
4390 if (! FRAME_GTK_WIDGET (f))
4391 return;
4393 BLOCK_INPUT;
4395 if (INTEGERP (Vtool_bar_button_margin)
4396 && XINT (Vtool_bar_button_margin) > 0)
4398 hmargin = XFASTINT (Vtool_bar_button_margin);
4399 vmargin = XFASTINT (Vtool_bar_button_margin);
4401 else if (CONSP (Vtool_bar_button_margin))
4403 if (INTEGERP (XCAR (Vtool_bar_button_margin))
4404 && XINT (XCAR (Vtool_bar_button_margin)) > 0)
4405 hmargin = XFASTINT (XCAR (Vtool_bar_button_margin));
4407 if (INTEGERP (XCDR (Vtool_bar_button_margin))
4408 && XINT (XCDR (Vtool_bar_button_margin)) > 0)
4409 vmargin = XFASTINT (XCDR (Vtool_bar_button_margin));
4412 /* The natural size (i.e. when GTK uses 0 as margin) looks best,
4413 so take DEFAULT_TOOL_BAR_BUTTON_MARGIN to mean "default for GTK",
4414 i.e. zero. This means that margins less than
4415 DEFAULT_TOOL_BAR_BUTTON_MARGIN has no effect. */
4416 hmargin = max (0, hmargin - DEFAULT_TOOL_BAR_BUTTON_MARGIN);
4417 vmargin = max (0, vmargin - DEFAULT_TOOL_BAR_BUTTON_MARGIN);
4419 if (! x->toolbar_widget)
4420 xg_create_tool_bar (f);
4422 wtoolbar = GTK_TOOLBAR (x->toolbar_widget);
4423 dir = gtk_widget_get_direction (GTK_WIDGET (wtoolbar));
4425 style = Ftool_bar_get_system_style ();
4426 text_image = EQ (style, Qtext_image_horiz);
4427 horiz = EQ (style, Qboth_horiz) || text_image;
4429 for (i = j = 0; i < f->n_tool_bar_items; ++i)
4431 int enabled_p = !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P));
4432 int selected_p = !NILP (PROP (TOOL_BAR_ITEM_SELECTED_P));
4433 int idx;
4434 int img_id;
4435 int icon_size = 0;
4436 struct image *img = NULL;
4437 Lisp_Object image;
4438 Lisp_Object stock = Qnil;
4439 GtkStockItem stock_item;
4440 char *stock_name = NULL;
4441 char *icon_name = NULL;
4442 Lisp_Object rtl;
4443 GtkWidget *wbutton = NULL;
4444 Lisp_Object specified_file;
4445 int vert_only = ! NILP (PROP (TOOL_BAR_ITEM_VERT_ONLY));
4446 const char *label
4447 = (EQ (style, Qimage) || (vert_only && horiz)) ? NULL
4448 : STRINGP (PROP (TOOL_BAR_ITEM_LABEL))
4449 ? SSDATA (PROP (TOOL_BAR_ITEM_LABEL))
4450 : "";
4452 ti = gtk_toolbar_get_nth_item (GTK_TOOLBAR (wtoolbar), j);
4454 /* If this is a separator, use a gtk separator item. */
4455 if (EQ (PROP (TOOL_BAR_ITEM_TYPE), Qt))
4457 if (ti == NULL || !GTK_IS_SEPARATOR_TOOL_ITEM (ti))
4459 if (ti)
4460 gtk_container_remove (GTK_CONTAINER (wtoolbar),
4461 GTK_WIDGET (ti));
4462 ti = gtk_separator_tool_item_new ();
4463 gtk_toolbar_insert (GTK_TOOLBAR (wtoolbar), ti, j);
4465 j++;
4466 continue;
4469 /* Otherwise, the tool-bar item is an ordinary button. */
4471 if (ti && GTK_IS_SEPARATOR_TOOL_ITEM (ti))
4473 gtk_container_remove (GTK_CONTAINER (wtoolbar), GTK_WIDGET (ti));
4474 ti = NULL;
4477 if (ti) wbutton = XG_BIN_CHILD (XG_BIN_CHILD (ti));
4479 /* Ignore invalid image specifications. */
4480 image = PROP (TOOL_BAR_ITEM_IMAGES);
4481 if (!valid_image_p (image))
4483 if (ti)
4484 gtk_container_remove (GTK_CONTAINER (wtoolbar),
4485 GTK_WIDGET (ti));
4486 continue;
4489 specified_file = file_for_image (image);
4490 if (!NILP (specified_file) && !NILP (Ffboundp (Qx_gtk_map_stock)))
4491 stock = call1 (Qx_gtk_map_stock, specified_file);
4493 if (STRINGP (stock))
4495 stock_name = SSDATA (stock);
4496 if (stock_name[0] == 'n' && stock_name[1] == ':')
4498 GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (wtoolbar));
4499 GtkIconTheme *icon_theme = gtk_icon_theme_get_for_screen (screen);
4501 icon_name = stock_name + 2;
4502 stock_name = NULL;
4503 stock = Qnil;
4505 if (! gtk_icon_theme_has_icon (icon_theme, icon_name))
4506 icon_name = NULL;
4507 else
4508 icon_size = gtk_toolbar_get_icon_size (wtoolbar);
4510 else if (gtk_stock_lookup (SSDATA (stock), &stock_item))
4511 icon_size = gtk_toolbar_get_icon_size (wtoolbar);
4512 else
4514 stock = Qnil;
4515 stock_name = NULL;
4519 if (stock_name == NULL && icon_name == NULL)
4521 /* No stock image, or stock item not known. Try regular
4522 image. If image is a vector, choose it according to the
4523 button state. */
4524 if (dir == GTK_TEXT_DIR_RTL
4525 && !NILP (rtl = PROP (TOOL_BAR_ITEM_RTL_IMAGE))
4526 && STRINGP (rtl))
4527 image = find_rtl_image (f, image, rtl);
4529 if (VECTORP (image))
4531 if (enabled_p)
4532 idx = (selected_p
4533 ? TOOL_BAR_IMAGE_ENABLED_SELECTED
4534 : TOOL_BAR_IMAGE_ENABLED_DESELECTED);
4535 else
4536 idx = (selected_p
4537 ? TOOL_BAR_IMAGE_DISABLED_SELECTED
4538 : TOOL_BAR_IMAGE_DISABLED_DESELECTED);
4540 xassert (ASIZE (image) >= idx);
4541 image = AREF (image, idx);
4543 else
4544 idx = -1;
4546 img_id = lookup_image (f, image);
4547 img = IMAGE_FROM_ID (f, img_id);
4548 prepare_image_for_display (f, img);
4550 if (img->load_failed_p || img->pixmap == None)
4552 if (ti)
4553 gtk_container_remove (GTK_CONTAINER (wtoolbar),
4554 GTK_WIDGET (ti));
4555 continue;
4559 /* If there is an existing widget, check if it's stale; if so,
4560 remove it and make a new tool item from scratch. */
4561 if (ti && xg_tool_item_stale_p (wbutton, stock_name, icon_name,
4562 img, label, horiz))
4564 gtk_container_remove (GTK_CONTAINER (wtoolbar),
4565 GTK_WIDGET (ti));
4566 ti = NULL;
4569 if (ti == NULL)
4571 GtkWidget *w;
4573 /* Save the image so we can see if an update is needed the
4574 next time we call xg_tool_item_match_p. */
4575 if (EQ (style, Qtext))
4576 w = NULL;
4577 else if (stock_name)
4579 w = gtk_image_new_from_stock (stock_name, icon_size);
4580 g_object_set_data_full (G_OBJECT (w), XG_TOOL_BAR_STOCK_NAME,
4581 (gpointer) xstrdup (stock_name),
4582 (GDestroyNotify) xfree);
4584 else if (icon_name)
4586 w = gtk_image_new_from_icon_name (icon_name, icon_size);
4587 g_object_set_data_full (G_OBJECT (w), XG_TOOL_BAR_ICON_NAME,
4588 (gpointer) xstrdup (icon_name),
4589 (GDestroyNotify) xfree);
4591 else
4593 w = xg_get_image_for_pixmap (f, img, x->widget, NULL);
4594 g_object_set_data (G_OBJECT (w), XG_TOOL_BAR_IMAGE_DATA,
4595 (gpointer)img->pixmap);
4598 if (w) gtk_misc_set_padding (GTK_MISC (w), hmargin, vmargin);
4599 ti = xg_make_tool_item (f, w, &wbutton, label, i, horiz, text_image);
4600 gtk_toolbar_insert (GTK_TOOLBAR (wtoolbar), ti, j);
4603 #undef PROP
4605 gtk_widget_set_sensitive (wbutton, enabled_p);
4606 j++;
4609 /* Remove buttons not longer needed. */
4612 ti = gtk_toolbar_get_nth_item (GTK_TOOLBAR (wtoolbar), j);
4613 if (ti)
4614 gtk_container_remove (GTK_CONTAINER (wtoolbar), GTK_WIDGET (ti));
4615 } while (ti != NULL);
4617 if (f->n_tool_bar_items != 0)
4619 if (pack_tool_bar)
4620 xg_pack_tool_bar (f, f->tool_bar_position);
4621 gtk_widget_show_all (GTK_WIDGET (x->handlebox_widget));
4622 if (xg_update_tool_bar_sizes (f))
4623 xg_height_or_width_changed (f);
4626 UNBLOCK_INPUT;
4629 /* Deallocate all resources for the tool bar on frame F.
4630 Remove the tool bar. */
4632 void
4633 free_frame_tool_bar (FRAME_PTR f)
4635 struct x_output *x = f->output_data.x;
4637 if (x->toolbar_widget)
4639 int is_packed = x->handlebox_widget != 0;
4640 BLOCK_INPUT;
4641 /* We may have created the toolbar_widget in xg_create_tool_bar, but
4642 not the x->handlebox_widget which is created in xg_pack_tool_bar. */
4643 if (is_packed)
4645 if (x->toolbar_in_hbox)
4646 gtk_container_remove (GTK_CONTAINER (x->hbox_widget),
4647 x->handlebox_widget);
4648 else
4649 gtk_container_remove (GTK_CONTAINER (x->vbox_widget),
4650 x->handlebox_widget);
4652 else
4653 gtk_widget_destroy (x->toolbar_widget);
4655 x->toolbar_widget = 0;
4656 x->handlebox_widget = 0;
4657 FRAME_TOOLBAR_TOP_HEIGHT (f) = FRAME_TOOLBAR_BOTTOM_HEIGHT (f) = 0;
4658 FRAME_TOOLBAR_LEFT_WIDTH (f) = FRAME_TOOLBAR_RIGHT_WIDTH (f) = 0;
4660 xg_height_or_width_changed (f);
4662 UNBLOCK_INPUT;
4667 xg_change_toolbar_position (FRAME_PTR f, Lisp_Object pos)
4669 struct x_output *x = f->output_data.x;
4671 if (! x->toolbar_widget || ! x->handlebox_widget)
4672 return 1;
4674 BLOCK_INPUT;
4675 g_object_ref (x->handlebox_widget);
4676 if (x->toolbar_in_hbox)
4677 gtk_container_remove (GTK_CONTAINER (x->hbox_widget),
4678 x->handlebox_widget);
4679 else
4680 gtk_container_remove (GTK_CONTAINER (x->vbox_widget),
4681 x->handlebox_widget);
4682 xg_pack_tool_bar (f, pos);
4683 g_object_unref (x->handlebox_widget);
4684 if (xg_update_tool_bar_sizes (f))
4685 xg_height_or_width_changed (f);
4687 UNBLOCK_INPUT;
4688 return 1;
4693 /***********************************************************************
4694 Initializing
4695 ***********************************************************************/
4696 void
4697 xg_initialize (void)
4699 GtkBindingSet *binding_set;
4701 #if HAVE_XFT
4702 /* Work around a bug with corrupted data if libXft gets unloaded. This way
4703 we keep it permanently linked in. */
4704 XftInit (0);
4705 #endif
4707 gdpy_def = NULL;
4708 xg_ignore_gtk_scrollbar = 0;
4709 xg_detached_menus = 0;
4710 xg_menu_cb_list.prev = xg_menu_cb_list.next =
4711 xg_menu_item_cb_list.prev = xg_menu_item_cb_list.next = 0;
4713 id_to_widget.max_size = id_to_widget.used = 0;
4714 id_to_widget.widgets = 0;
4716 /* Remove F10 as a menu accelerator, it does not mix well with Emacs key
4717 bindings. It doesn't seem to be any way to remove properties,
4718 so we set it to VoidSymbol which in X means "no key". */
4719 gtk_settings_set_string_property (gtk_settings_get_default (),
4720 "gtk-menu-bar-accel",
4721 "VoidSymbol",
4722 EMACS_CLASS);
4724 /* Make GTK text input widgets use Emacs style keybindings. This is
4725 Emacs after all. */
4726 gtk_settings_set_string_property (gtk_settings_get_default (),
4727 "gtk-key-theme-name",
4728 "Emacs",
4729 EMACS_CLASS);
4731 /* Make dialogs close on C-g. Since file dialog inherits from
4732 dialog, this works for them also. */
4733 binding_set = gtk_binding_set_by_class (g_type_class_ref (GTK_TYPE_DIALOG));
4734 gtk_binding_entry_add_signal (binding_set, GDK_KEY_g, GDK_CONTROL_MASK,
4735 "close", 0);
4737 /* Make menus close on C-g. */
4738 binding_set = gtk_binding_set_by_class (g_type_class_ref
4739 (GTK_TYPE_MENU_SHELL));
4740 gtk_binding_entry_add_signal (binding_set, GDK_KEY_g, GDK_CONTROL_MASK,
4741 "cancel", 0);
4742 update_theme_scrollbar_width ();
4745 #endif /* USE_GTK */