gtkutil.c (xg_update_frame_menubar): Do nothing if menubar already has a parent.
[emacs.git] / src / gtkutil.c
blobb182b52e6a7802d04a65d8f17026a36e208135b9
1 /* Functions for creating and updating GTK widgets.
2 Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009
3 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
20 #include <config.h>
22 #ifdef USE_GTK
23 #include <string.h>
24 #include <signal.h>
25 #include <stdio.h>
26 #include <setjmp.h>
27 #include "lisp.h"
28 #include "xterm.h"
29 #include "blockinput.h"
30 #include "syssignal.h"
31 #include "window.h"
32 #include "atimer.h"
33 #include "gtkutil.h"
34 #include "termhooks.h"
35 #include "keyboard.h"
36 #include "charset.h"
37 #include "coding.h"
38 #include <gdk/gdkkeysyms.h>
40 #ifdef HAVE_XFT
41 #include <X11/Xft/Xft.h>
42 #endif
44 #define FRAME_TOTAL_PIXEL_HEIGHT(f) \
45 (FRAME_PIXEL_HEIGHT (f) + FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f))
47 /* Avoid "differ in sign" warnings */
48 #define SSDATA(x) ((char *) SDATA (x))
51 /***********************************************************************
52 Display handling functions
53 ***********************************************************************/
55 #ifdef HAVE_GTK_MULTIDISPLAY
57 /* Keep track of the default display, or NULL if there is none. Emacs
58 may close all its displays. */
60 static GdkDisplay *gdpy_def;
62 /* Return the GdkDisplay that corresponds to the X display DPY. */
64 static GdkDisplay *
65 xg_get_gdk_display (dpy)
66 Display *dpy;
68 return gdk_x11_lookup_xdisplay (dpy);
71 /* When the GTK widget W is to be created on a display for F that
72 is not the default display, set the display for W.
73 W can be a GtkMenu or a GtkWindow widget. */
75 static void
76 xg_set_screen (w, f)
77 GtkWidget *w;
78 FRAME_PTR f;
80 if (FRAME_X_DISPLAY (f) != GDK_DISPLAY ())
82 GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (FRAME_X_DISPLAY (f));
83 GdkScreen *gscreen = gdk_display_get_default_screen (gdpy);
85 if (GTK_IS_MENU (w))
86 gtk_menu_set_screen (GTK_MENU (w), gscreen);
87 else
88 gtk_window_set_screen (GTK_WINDOW (w), gscreen);
93 #else /* not HAVE_GTK_MULTIDISPLAY */
95 /* Make some defines so we can use the GTK 2.2 functions when
96 compiling with GTK 2.0. */
98 #define xg_set_screen(w, f)
99 #define gdk_xid_table_lookup_for_display(dpy, w) gdk_xid_table_lookup (w)
100 #define gdk_pixmap_foreign_new_for_display(dpy, p) gdk_pixmap_foreign_new (p)
101 #define gdk_cursor_new_for_display(dpy, c) gdk_cursor_new (c)
102 #define gdk_x11_lookup_xdisplay(dpy) 0
103 #define GdkDisplay void
105 #endif /* not HAVE_GTK_MULTIDISPLAY */
107 /* Open a display named by DISPLAY_NAME. The display is returned in *DPY.
108 *DPY is set to NULL if the display can't be opened.
110 Returns non-zero if display could be opened, zero if display could not
111 be opened, and less than zero if the GTK version doesn't support
112 multipe displays. */
115 xg_display_open (display_name, dpy)
116 char *display_name;
117 Display **dpy;
119 #ifdef HAVE_GTK_MULTIDISPLAY
120 GdkDisplay *gdpy;
122 gdpy = gdk_display_open (display_name);
123 if (!gdpy_def && gdpy)
125 gdpy_def = gdpy;
126 gdk_display_manager_set_default_display (gdk_display_manager_get (),
127 gdpy);
130 *dpy = gdpy ? GDK_DISPLAY_XDISPLAY (gdpy) : NULL;
131 return gdpy != NULL;
133 #else /* not HAVE_GTK_MULTIDISPLAY */
135 return -1;
136 #endif /* not HAVE_GTK_MULTIDISPLAY */
140 /* Close display DPY. */
142 void
143 xg_display_close (Display *dpy)
145 #ifdef HAVE_GTK_MULTIDISPLAY
146 GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (dpy);
148 /* If this is the default display, try to change it before closing.
149 If there is no other display to use, gdpy_def is set to NULL, and
150 the next call to xg_display_open resets the default display. */
151 if (gdk_display_get_default () == gdpy)
153 struct x_display_info *dpyinfo;
154 GdkDisplay *gdpy_new = NULL;
156 /* Find another display. */
157 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
158 if (dpyinfo->display != dpy)
160 gdpy_new = gdk_x11_lookup_xdisplay (dpyinfo->display);
161 gdk_display_manager_set_default_display (gdk_display_manager_get (),
162 gdpy_new);
163 break;
165 gdpy_def = gdpy_new;
168 #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 10
169 /* GTK 2.2-2.8 has a bug that makes gdk_display_close crash (bug
170 http://bugzilla.gnome.org/show_bug.cgi?id=85715). This way we
171 can continue running, but there will be memory leaks. */
172 g_object_run_dispose (G_OBJECT (gdpy));
173 #else
174 /* This seems to be fixed in GTK 2.10. */
175 gdk_display_close (gdpy);
176 #endif
177 #endif /* HAVE_GTK_MULTIDISPLAY */
181 /***********************************************************************
182 Utility functions
183 ***********************************************************************/
184 /* The timer for scroll bar repetition and menu bar timeouts.
185 NULL if no timer is started. */
186 static struct atimer *xg_timer;
189 /* The next two variables and functions are taken from lwlib. */
190 static widget_value *widget_value_free_list;
191 static int malloc_cpt;
193 /* Allocate a widget_value structure, either by taking one from the
194 widget_value_free_list or by malloc:ing a new one.
196 Return a pointer to the allocated structure. */
198 widget_value *
199 malloc_widget_value ()
201 widget_value *wv;
202 if (widget_value_free_list)
204 wv = widget_value_free_list;
205 widget_value_free_list = wv->free_list;
206 wv->free_list = 0;
208 else
210 wv = (widget_value *) xmalloc (sizeof (widget_value));
211 malloc_cpt++;
213 memset (wv, 0, sizeof (widget_value));
214 return wv;
217 /* This is analogous to free. It frees only what was allocated
218 by malloc_widget_value, and no substructures. */
220 void
221 free_widget_value (wv)
222 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 (dpy)
247 Display *dpy;
249 GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (dpy);
250 return gdk_cursor_new_for_display (gdpy, GDK_LEFT_PTR);
253 /* Apply GMASK to GPIX and return a GdkPixbuf with an alpha channel. */
255 static GdkPixbuf *
256 xg_get_pixbuf_from_pix_and_mask (gpix, gmask, cmap)
257 GdkPixmap *gpix;
258 GdkPixmap *gmask;
259 GdkColormap *cmap;
261 int x, y, width, height, rowstride, mask_rowstride;
262 GdkPixbuf *icon_buf, *tmp_buf;
263 guchar *pixels;
264 guchar *mask_pixels;
266 gdk_drawable_get_size (gpix, &width, &height);
267 tmp_buf = gdk_pixbuf_get_from_drawable (NULL, gpix, cmap,
268 0, 0, 0, 0, width, height);
269 icon_buf = gdk_pixbuf_add_alpha (tmp_buf, FALSE, 0, 0, 0);
270 g_object_unref (G_OBJECT (tmp_buf));
272 if (gmask)
274 GdkPixbuf *mask_buf = gdk_pixbuf_get_from_drawable (NULL,
275 gmask,
276 NULL,
277 0, 0, 0, 0,
278 width, height);
279 guchar *pixels = gdk_pixbuf_get_pixels (icon_buf);
280 guchar *mask_pixels = gdk_pixbuf_get_pixels (mask_buf);
281 int rowstride = gdk_pixbuf_get_rowstride (icon_buf);
282 int mask_rowstride = gdk_pixbuf_get_rowstride (mask_buf);
283 int y;
285 for (y = 0; y < height; ++y)
287 guchar *iconptr, *maskptr;
288 int x;
290 iconptr = pixels + y * rowstride;
291 maskptr = mask_pixels + y * mask_rowstride;
293 for (x = 0; x < width; ++x)
295 /* In a bitmap, RGB is either 255/255/255 or 0/0/0. Checking
296 just R is sufficient. */
297 if (maskptr[0] == 0)
298 iconptr[3] = 0; /* 0, 1, 2 is R, G, B. 3 is alpha. */
300 iconptr += rowstride/width;
301 maskptr += mask_rowstride/width;
305 g_object_unref (G_OBJECT (mask_buf));
308 return icon_buf;
311 static Lisp_Object
312 file_for_image (image)
313 Lisp_Object image;
315 Lisp_Object specified_file = Qnil;
316 Lisp_Object tail;
317 extern Lisp_Object QCfile;
319 for (tail = XCDR (image);
320 NILP (specified_file) && CONSP (tail) && CONSP (XCDR (tail));
321 tail = XCDR (XCDR (tail)))
322 if (EQ (XCAR (tail), QCfile))
323 specified_file = XCAR (XCDR (tail));
325 return specified_file;
328 /* For the image defined in IMG, make and return a GtkImage. For displays with
329 8 planes or less we must make a GdkPixbuf and apply the mask manually.
330 Otherwise the highlightning and dimming the tool bar code in GTK does
331 will look bad. For display with more than 8 planes we just use the
332 pixmap and mask directly. For monochrome displays, GTK doesn't seem
333 able to use external pixmaps, it looks bad whatever we do.
334 The image is defined on the display where frame F is.
335 WIDGET is used to find the GdkColormap to use for the GdkPixbuf.
336 If OLD_WIDGET is NULL, a new widget is constructed and returned.
337 If OLD_WIDGET is not NULL, that widget is modified. */
339 static GtkWidget *
340 xg_get_image_for_pixmap (f, img, widget, old_widget)
341 FRAME_PTR f;
342 struct image *img;
343 GtkWidget *widget;
344 GtkImage *old_widget;
346 GdkPixmap *gpix;
347 GdkPixmap *gmask;
348 GdkDisplay *gdpy;
349 GdkColormap *cmap;
350 GdkPixbuf *icon_buf;
352 /* If we have a file, let GTK do all the image handling.
353 This seems to be the only way to make insensitive and activated icons
354 look good in all cases. */
355 Lisp_Object specified_file = file_for_image (img->spec);
356 Lisp_Object file;
358 /* We already loaded the image once before calling this
359 function, so this only fails if the image file has been removed.
360 In that case, use the pixmap already loaded. */
362 if (STRINGP (specified_file)
363 && STRINGP (file = x_find_image_file (specified_file)))
365 if (! old_widget)
366 old_widget = GTK_IMAGE (gtk_image_new_from_file (SSDATA (file)));
367 else
368 gtk_image_set_from_file (old_widget, SSDATA (file));
370 return GTK_WIDGET (old_widget);
373 /* No file, do the image handling ourselves. This will look very bad
374 on a monochrome display, and sometimes bad on all displays with
375 certain themes. */
377 gdpy = gdk_x11_lookup_xdisplay (FRAME_X_DISPLAY (f));
378 gpix = gdk_pixmap_foreign_new_for_display (gdpy, img->pixmap);
379 gmask = img->mask ? gdk_pixmap_foreign_new_for_display (gdpy, img->mask) : 0;
381 /* This is a workaround to make icons look good on pseudo color
382 displays. Apparently GTK expects the images to have an alpha
383 channel. If they don't, insensitive and activated icons will
384 look bad. This workaround does not work on monochrome displays,
385 and is strictly not needed on true color/static color displays (i.e.
386 16 bits and higher). But we do it anyway so we get a pixbuf that is
387 not associated with the img->pixmap. The img->pixmap may be removed
388 by clearing the image cache and then the tool bar redraw fails, since
389 Gtk+ assumes the pixmap is always there. */
390 cmap = gtk_widget_get_colormap (widget);
391 icon_buf = xg_get_pixbuf_from_pix_and_mask (gpix, gmask, cmap);
393 if (! old_widget)
394 old_widget = GTK_IMAGE (gtk_image_new_from_pixbuf (icon_buf));
395 else
396 gtk_image_set_from_pixbuf (old_widget, icon_buf);
398 g_object_unref (G_OBJECT (icon_buf));
400 g_object_unref (G_OBJECT (gpix));
401 if (gmask) g_object_unref (G_OBJECT (gmask));
403 return GTK_WIDGET (old_widget);
407 /* Set CURSOR on W and all widgets W contain. We must do like this
408 for scroll bars and menu because they create widgets internally,
409 and it is those widgets that are visible. */
411 static void
412 xg_set_cursor (w, cursor)
413 GtkWidget *w;
414 GdkCursor *cursor;
416 GList *children = gdk_window_peek_children (w->window);
418 gdk_window_set_cursor (w->window, cursor);
420 /* The scroll bar widget has more than one GDK window (had to look at
421 the source to figure this out), and there is no way to set cursor
422 on widgets in GTK. So we must set the cursor for all GDK windows.
423 Ditto for menus. */
425 for ( ; children; children = g_list_next (children))
426 gdk_window_set_cursor (GDK_WINDOW (children->data), cursor);
429 /* Timer function called when a timeout occurs for xg_timer.
430 This function processes all GTK events in a recursive event loop.
431 This is done because GTK timer events are not seen by Emacs event
432 detection, Emacs only looks for X events. When a scroll bar has the
433 pointer (detected by button press/release events below) an Emacs
434 timer is started, and this function can then check if the GTK timer
435 has expired by calling the GTK event loop.
436 Also, when a menu is active, it has a small timeout before it
437 pops down the sub menu under it. */
439 static void
440 xg_process_timeouts (timer)
441 struct atimer *timer;
443 BLOCK_INPUT;
444 /* Ideally we would like to just handle timer events, like the Xt version
445 of this does in xterm.c, but there is no such feature in GTK. */
446 while (gtk_events_pending ())
447 gtk_main_iteration ();
448 UNBLOCK_INPUT;
451 /* Start the xg_timer with an interval of 0.1 seconds, if not already started.
452 xg_process_timeouts is called when the timer expires. The timer
453 started is continuous, i.e. runs until xg_stop_timer is called. */
455 static void
456 xg_start_timer ()
458 if (! xg_timer)
460 EMACS_TIME interval;
461 EMACS_SET_SECS_USECS (interval, 0, 100000);
462 xg_timer = start_atimer (ATIMER_CONTINUOUS,
463 interval,
464 xg_process_timeouts,
469 /* Stop the xg_timer if started. */
471 static void
472 xg_stop_timer ()
474 if (xg_timer)
476 cancel_atimer (xg_timer);
477 xg_timer = 0;
481 /* Insert NODE into linked LIST. */
483 static void
484 xg_list_insert (xg_list_node *list, xg_list_node *node)
486 xg_list_node *list_start = list->next;
488 if (list_start) list_start->prev = node;
489 node->next = list_start;
490 node->prev = 0;
491 list->next = node;
494 /* Remove NODE from linked LIST. */
496 static void
497 xg_list_remove (xg_list_node *list, xg_list_node *node)
499 xg_list_node *list_start = list->next;
500 if (node == list_start)
502 list->next = node->next;
503 if (list->next) list->next->prev = 0;
505 else
507 node->prev->next = node->next;
508 if (node->next) node->next->prev = node->prev;
512 /* Allocate and return a utf8 version of STR. If STR is already
513 utf8 or NULL, just return STR.
514 If not, a new string is allocated and the caller must free the result
515 with g_free. */
517 static char *
518 get_utf8_string (str)
519 char *str;
521 char *utf8_str = str;
523 if (!str) return NULL;
525 /* If not UTF-8, try current locale. */
526 if (!g_utf8_validate (str, -1, NULL))
527 utf8_str = g_locale_to_utf8 (str, -1, 0, 0, 0);
529 if (!utf8_str)
531 /* Probably some control characters in str. Escape them. */
532 size_t nr_bad = 0;
533 gsize bytes_read;
534 gsize bytes_written;
535 unsigned char *p = (unsigned char *)str;
536 char *cp, *up;
537 GError *error = NULL;
539 while (! (cp = g_locale_to_utf8 ((char *)p, -1, &bytes_read,
540 &bytes_written, &error))
541 && error->code == G_CONVERT_ERROR_ILLEGAL_SEQUENCE)
543 ++nr_bad;
544 p += bytes_written+1;
545 g_error_free (error);
546 error = NULL;
549 if (error)
551 g_error_free (error);
552 error = NULL;
554 if (cp) g_free (cp);
556 up = utf8_str = xmalloc (strlen (str) + nr_bad * 4 + 1);
557 p = (unsigned char *)str;
559 while (! (cp = g_locale_to_utf8 ((char *)p, -1, &bytes_read,
560 &bytes_written, &error))
561 && error->code == G_CONVERT_ERROR_ILLEGAL_SEQUENCE)
563 strncpy (up, (char *)p, bytes_written);
564 sprintf (up + bytes_written, "\\%03o", p[bytes_written]);
565 up[bytes_written+4] = '\0';
566 up += bytes_written+4;
567 p += bytes_written+1;
568 g_error_free (error);
569 error = NULL;
572 if (cp)
574 strcat (utf8_str, cp);
575 g_free (cp);
577 if (error)
579 g_error_free (error);
580 error = NULL;
583 return utf8_str;
588 /***********************************************************************
589 General functions for creating widgets, resizing, events, e.t.c.
590 ***********************************************************************/
592 /* Make a geometry string and pass that to GTK. It seems this is the
593 only way to get geometry position right if the user explicitly
594 asked for a position when starting Emacs.
595 F is the frame we shall set geometry for. */
597 static void
598 xg_set_geometry (f)
599 FRAME_PTR f;
601 if (f->size_hint_flags & USPosition)
603 int left = f->left_pos;
604 int xneg = f->size_hint_flags & XNegative;
605 int top = f->top_pos;
606 int yneg = f->size_hint_flags & YNegative;
607 char geom_str[32];
609 if (xneg)
610 left = -left;
611 if (yneg)
612 top = -top;
614 sprintf (geom_str, "=%dx%d%c%d%c%d",
615 FRAME_PIXEL_WIDTH (f),
616 FRAME_TOTAL_PIXEL_HEIGHT (f),
617 (xneg ? '-' : '+'), left,
618 (yneg ? '-' : '+'), top);
620 if (!gtk_window_parse_geometry (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
621 geom_str))
622 fprintf (stderr, "Failed to parse: '%s'\n", geom_str);
624 else if (f->size_hint_flags & PPosition)
625 gtk_window_move (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
626 f->left_pos, f->top_pos);
629 /* Function to handle resize of our frame. As we have a Gtk+ tool bar
630 and a Gtk+ menu bar, we get resize events for the edit part of the
631 frame only. We let Gtk+ deal with the Gtk+ parts.
632 F is the frame to resize.
633 PIXELWIDTH, PIXELHEIGHT is the new size in pixels. */
635 void
636 xg_frame_resized (f, pixelwidth, pixelheight)
637 FRAME_PTR f;
638 int pixelwidth, pixelheight;
640 int rows, columns;
642 if (pixelwidth == -1 && pixelheight == -1)
644 if (FRAME_GTK_WIDGET (f) && GTK_WIDGET_MAPPED (FRAME_GTK_WIDGET (f)))
645 gdk_window_get_geometry(FRAME_GTK_WIDGET (f)->window, 0, 0,
646 &pixelwidth, &pixelheight, 0);
647 else return;
651 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, pixelheight);
652 columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, pixelwidth);
654 if (columns != FRAME_COLS (f)
655 || rows != FRAME_LINES (f)
656 || pixelwidth != FRAME_PIXEL_WIDTH (f)
657 || pixelheight != FRAME_PIXEL_HEIGHT (f))
659 FRAME_PIXEL_WIDTH (f) = pixelwidth;
660 FRAME_PIXEL_HEIGHT (f) = pixelheight;
662 change_frame_size (f, rows, columns, 0, 1, 0);
663 SET_FRAME_GARBAGED (f);
664 cancel_mouse_face (f);
668 /* Resize the outer window of frame F after chainging the height.
669 COLUMNS/ROWS is the size the edit area shall have after the resize. */
671 void
672 xg_frame_set_char_size (f, cols, rows)
673 FRAME_PTR f;
674 int cols;
675 int rows;
677 int pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows)
678 + FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f);
679 int pixelwidth;
681 if (FRAME_PIXEL_HEIGHT (f) == 0)
682 return;
684 /* Take into account the size of the scroll bar. Always use the
685 number of columns occupied by the scroll bar here otherwise we
686 might end up with a frame width that is not a multiple of the
687 frame's character width which is bad for vertically split
688 windows. */
689 f->scroll_bar_actual_width
690 = FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f);
692 compute_fringe_widths (f, 0);
694 /* FRAME_TEXT_COLS_TO_PIXEL_WIDTH uses scroll_bar_actual_width, so call it
695 after calculating that value. */
696 pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, cols);
698 /* Must resize our top level widget. Font size may have changed,
699 but not rows/cols. */
700 gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
701 pixelwidth, pixelheight);
702 x_wm_set_size_hint (f, 0, 0);
704 SET_FRAME_GARBAGED (f);
705 cancel_mouse_face (f);
707 /* We can not call change_frame_size for a mapped frame,
708 we can not set pixel width/height either. The window manager may
709 override our resize request, XMonad does this all the time.
710 The best we can do is try to sync, so lisp code sees the updated
711 size as fast as possible.
712 For unmapped windows, we can set rows/cols. When
713 the frame is mapped again we will (hopefully) get the correct size. */
714 if (f->async_visible)
716 /* Must call this to flush out events */
717 (void)gtk_events_pending ();
718 gdk_flush ();
719 x_wait_for_event (f, ConfigureNotify);
721 else
723 change_frame_size (f, rows, cols, 0, 1, 0);
724 FRAME_PIXEL_WIDTH (f) = pixelwidth;
725 FRAME_PIXEL_HEIGHT (f) = pixelheight;
729 /* Handle height changes (i.e. add/remove menu/toolbar).
730 The policy is to keep the number of editable lines. */
732 static void
733 xg_height_changed (f)
734 FRAME_PTR f;
736 gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
737 FRAME_PIXEL_WIDTH (f), FRAME_TOTAL_PIXEL_HEIGHT (f));
738 f->output_data.x->hint_flags = 0;
739 x_wm_set_size_hint (f, 0, 0);
742 /* Convert an X Window WSESC on display DPY to its corresponding GtkWidget.
743 Must be done like this, because GtkWidget:s can have "hidden"
744 X Window that aren't accessible.
746 Return 0 if no widget match WDESC. */
748 GtkWidget *
749 xg_win_to_widget (dpy, wdesc)
750 Display *dpy;
751 Window wdesc;
753 gpointer gdkwin;
754 GtkWidget *gwdesc = 0;
756 BLOCK_INPUT;
758 gdkwin = gdk_xid_table_lookup_for_display (gdk_x11_lookup_xdisplay (dpy),
759 wdesc);
760 if (gdkwin)
762 GdkEvent event;
763 event.any.window = gdkwin;
764 gwdesc = gtk_get_event_widget (&event);
767 UNBLOCK_INPUT;
768 return gwdesc;
771 /* Fill in the GdkColor C so that it represents PIXEL.
772 W is the widget that color will be used for. Used to find colormap. */
774 static void
775 xg_pix_to_gcolor (w, pixel, c)
776 GtkWidget *w;
777 unsigned long pixel;
778 GdkColor *c;
780 GdkColormap *map = gtk_widget_get_colormap (w);
781 gdk_colormap_query_color (map, pixel, c);
784 /* Create and set up the GTK widgets for frame F.
785 Return 0 if creation failed, non-zero otherwise. */
788 xg_create_frame_widgets (f)
789 FRAME_PTR f;
791 GtkWidget *wtop;
792 GtkWidget *wvbox;
793 GtkWidget *wfixed;
794 GdkColor bg;
795 GtkRcStyle *style;
796 int i;
797 char *title = 0;
799 BLOCK_INPUT;
801 if (FRAME_X_EMBEDDED_P (f))
802 wtop = gtk_plug_new (f->output_data.x->parent_desc);
803 else
804 wtop = gtk_window_new (GTK_WINDOW_TOPLEVEL);
806 xg_set_screen (wtop, f);
808 wvbox = gtk_vbox_new (FALSE, 0);
809 wfixed = gtk_fixed_new (); /* Must have this to place scroll bars */
811 if (! wtop || ! wvbox || ! wfixed)
813 if (wtop) gtk_widget_destroy (wtop);
814 if (wvbox) gtk_widget_destroy (wvbox);
815 if (wfixed) gtk_widget_destroy (wfixed);
817 UNBLOCK_INPUT;
818 return 0;
821 /* Use same names as the Xt port does. I.e. Emacs.pane.emacs by default */
822 gtk_widget_set_name (wtop, EMACS_CLASS);
823 gtk_widget_set_name (wvbox, "pane");
824 gtk_widget_set_name (wfixed, SSDATA (Vx_resource_name));
826 /* If this frame has a title or name, set it in the title bar. */
827 if (! NILP (f->title)) title = SSDATA (ENCODE_UTF_8 (f->title));
828 else if (! NILP (f->name)) title = SSDATA (ENCODE_UTF_8 (f->name));
830 if (title) gtk_window_set_title (GTK_WINDOW (wtop), title);
832 FRAME_GTK_OUTER_WIDGET (f) = wtop;
833 FRAME_GTK_WIDGET (f) = wfixed;
834 f->output_data.x->vbox_widget = wvbox;
836 gtk_fixed_set_has_window (GTK_FIXED (wfixed), TRUE);
838 gtk_container_add (GTK_CONTAINER (wtop), wvbox);
839 gtk_box_pack_end (GTK_BOX (wvbox), wfixed, TRUE, TRUE, 0);
841 if (FRAME_EXTERNAL_TOOL_BAR (f))
842 update_frame_tool_bar (f);
844 /* We don't want this widget double buffered, because we draw on it
845 with regular X drawing primitives, so from a GTK/GDK point of
846 view, the widget is totally blank. When an expose comes, this
847 will make the widget blank, and then Emacs redraws it. This flickers
848 a lot, so we turn off double buffering. */
849 gtk_widget_set_double_buffered (wfixed, FALSE);
851 gtk_window_set_wmclass (GTK_WINDOW (wtop),
852 SSDATA (Vx_resource_name),
853 SSDATA (Vx_resource_class));
855 /* Add callback to do nothing on WM_DELETE_WINDOW. The default in
856 GTK is to destroy the widget. We want Emacs to do that instead. */
857 g_signal_connect (G_OBJECT (wtop), "delete-event",
858 G_CALLBACK (gtk_true), 0);
860 /* Convert our geometry parameters into a geometry string
861 and specify it.
862 GTK will itself handle calculating the real position this way. */
863 xg_set_geometry (f);
864 int grav = gtk_window_get_gravity (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)));
865 f->win_gravity = grav;
867 gtk_widget_add_events (wfixed,
868 GDK_POINTER_MOTION_MASK
869 | GDK_EXPOSURE_MASK
870 | GDK_BUTTON_PRESS_MASK
871 | GDK_BUTTON_RELEASE_MASK
872 | GDK_KEY_PRESS_MASK
873 | GDK_ENTER_NOTIFY_MASK
874 | GDK_LEAVE_NOTIFY_MASK
875 | GDK_FOCUS_CHANGE_MASK
876 | GDK_STRUCTURE_MASK
877 | GDK_VISIBILITY_NOTIFY_MASK);
879 /* Must realize the windows so the X window gets created. It is used
880 by callers of this function. */
881 gtk_widget_realize (wfixed);
882 FRAME_X_WINDOW (f) = GTK_WIDGET_TO_X_WIN (wfixed);
884 /* Since GTK clears its window by filling with the background color,
885 we must keep X and GTK background in sync. */
886 xg_pix_to_gcolor (wfixed, FRAME_BACKGROUND_PIXEL (f), &bg);
887 gtk_widget_modify_bg (wfixed, GTK_STATE_NORMAL, &bg);
889 /* Also, do not let any background pixmap to be set, this looks very
890 bad as Emacs overwrites the background pixmap with its own idea
891 of background color. */
892 style = gtk_widget_get_modifier_style (wfixed);
894 /* Must use g_strdup because gtk_widget_modify_style does g_free. */
895 style->bg_pixmap_name[GTK_STATE_NORMAL] = g_strdup ("<none>");
896 gtk_widget_modify_style (wfixed, style);
898 /* GTK does not set any border, and they look bad with GTK. */
899 /* That they look bad is no excuse for imposing this here. --Stef
900 It should be done by providing the proper default in Fx_create_Frame.
901 f->border_width = 0;
902 f->internal_border_width = 0; */
904 UNBLOCK_INPUT;
906 return 1;
909 /* Set the normal size hints for the window manager, for frame F.
910 FLAGS is the flags word to use--or 0 meaning preserve the flags
911 that the window now has.
912 If USER_POSITION is nonzero, we set the User Position
913 flag (this is useful when FLAGS is 0). */
915 void
916 x_wm_set_size_hint (f, flags, user_position)
917 FRAME_PTR f;
918 long flags;
919 int user_position;
921 /* Don't set size hints during initialization; that apparently leads
922 to a race condition. See the thread at
923 http://lists.gnu.org/archive/html/emacs-devel/2008-10/msg00033.html */
924 if (NILP (Vafter_init_time) || !FRAME_GTK_OUTER_WIDGET (f))
925 return;
927 /* Must use GTK routines here, otherwise GTK resets the size hints
928 to its own defaults. */
929 GdkGeometry size_hints;
930 gint hint_flags = 0;
931 int base_width, base_height;
932 int min_rows = 0, min_cols = 0;
933 int win_gravity = f->win_gravity;
935 if (flags)
937 memset (&size_hints, 0, sizeof (size_hints));
938 f->output_data.x->size_hints = size_hints;
939 f->output_data.x->hint_flags = hint_flags;
941 else
942 flags = f->size_hint_flags;
944 size_hints = f->output_data.x->size_hints;
945 hint_flags = f->output_data.x->hint_flags;
947 hint_flags |= GDK_HINT_RESIZE_INC | GDK_HINT_MIN_SIZE;
948 size_hints.width_inc = FRAME_COLUMN_WIDTH (f);
949 size_hints.height_inc = FRAME_LINE_HEIGHT (f);
951 hint_flags |= GDK_HINT_BASE_SIZE;
952 base_width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, 0);
953 base_height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, 0)
954 + FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f);
956 check_frame_size (f, &min_rows, &min_cols);
958 size_hints.base_width = base_width;
959 size_hints.base_height = base_height;
960 size_hints.min_width = base_width + min_cols * size_hints.width_inc;
961 size_hints.min_height = base_height + min_rows * size_hints.height_inc;
963 /* These currently have a one to one mapping with the X values, but I
964 don't think we should rely on that. */
965 hint_flags |= GDK_HINT_WIN_GRAVITY;
966 size_hints.win_gravity = 0;
967 if (win_gravity == NorthWestGravity)
968 size_hints.win_gravity = GDK_GRAVITY_NORTH_WEST;
969 else if (win_gravity == NorthGravity)
970 size_hints.win_gravity = GDK_GRAVITY_NORTH;
971 else if (win_gravity == NorthEastGravity)
972 size_hints.win_gravity = GDK_GRAVITY_NORTH_EAST;
973 else if (win_gravity == WestGravity)
974 size_hints.win_gravity = GDK_GRAVITY_WEST;
975 else if (win_gravity == CenterGravity)
976 size_hints.win_gravity = GDK_GRAVITY_CENTER;
977 else if (win_gravity == EastGravity)
978 size_hints.win_gravity = GDK_GRAVITY_EAST;
979 else if (win_gravity == SouthWestGravity)
980 size_hints.win_gravity = GDK_GRAVITY_SOUTH_WEST;
981 else if (win_gravity == SouthGravity)
982 size_hints.win_gravity = GDK_GRAVITY_SOUTH;
983 else if (win_gravity == SouthEastGravity)
984 size_hints.win_gravity = GDK_GRAVITY_SOUTH_EAST;
985 else if (win_gravity == StaticGravity)
986 size_hints.win_gravity = GDK_GRAVITY_STATIC;
988 if (flags & PPosition) hint_flags |= GDK_HINT_POS;
989 if (flags & USPosition) hint_flags |= GDK_HINT_USER_POS;
990 if (flags & USSize) hint_flags |= GDK_HINT_USER_SIZE;
992 if (user_position)
994 hint_flags &= ~GDK_HINT_POS;
995 hint_flags |= GDK_HINT_USER_POS;
998 if (hint_flags != f->output_data.x->hint_flags
999 || memcmp (&size_hints,
1000 &f->output_data.x->size_hints,
1001 sizeof (size_hints)) != 0)
1003 BLOCK_INPUT;
1004 gtk_window_set_geometry_hints (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
1005 NULL, &size_hints, hint_flags);
1006 f->output_data.x->size_hints = size_hints;
1007 f->output_data.x->hint_flags = hint_flags;
1008 UNBLOCK_INPUT;
1012 /* Change background color of a frame.
1013 Since GTK uses the background color to clear the window, we must
1014 keep the GTK and X colors in sync.
1015 F is the frame to change,
1016 BG is the pixel value to change to. */
1018 void
1019 xg_set_background_color (f, bg)
1020 FRAME_PTR f;
1021 unsigned long bg;
1023 if (FRAME_GTK_WIDGET (f))
1025 GdkColor gdk_bg;
1027 BLOCK_INPUT;
1028 xg_pix_to_gcolor (FRAME_GTK_WIDGET (f), bg, &gdk_bg);
1029 gtk_widget_modify_bg (FRAME_GTK_WIDGET (f), GTK_STATE_NORMAL, &gdk_bg);
1030 UNBLOCK_INPUT;
1035 /* Set the frame icon to ICON_PIXMAP/MASK. This must be done with GTK
1036 functions so GTK does not overwrite the icon. */
1038 void
1039 xg_set_frame_icon (f, icon_pixmap, icon_mask)
1040 FRAME_PTR f;
1041 Pixmap icon_pixmap;
1042 Pixmap icon_mask;
1044 GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (FRAME_X_DISPLAY (f));
1045 GdkPixmap *gpix = gdk_pixmap_foreign_new_for_display (gdpy, icon_pixmap);
1046 GdkPixmap *gmask = gdk_pixmap_foreign_new_for_display (gdpy, icon_mask);
1047 GdkPixbuf *gp = xg_get_pixbuf_from_pix_and_mask (gpix, gmask, NULL);
1049 gtk_window_set_icon (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), gp);
1054 /***********************************************************************
1055 Dialog functions
1056 ***********************************************************************/
1057 /* Return the dialog title to use for a dialog of type KEY.
1058 This is the encoding used by lwlib. We use the same for GTK. */
1060 static char *
1061 get_dialog_title (char key)
1063 char *title = "";
1065 switch (key) {
1066 case 'E': case 'e':
1067 title = "Error";
1068 break;
1070 case 'I': case 'i':
1071 title = "Information";
1072 break;
1074 case 'L': case 'l':
1075 title = "Prompt";
1076 break;
1078 case 'P': case 'p':
1079 title = "Prompt";
1080 break;
1082 case 'Q': case 'q':
1083 title = "Question";
1084 break;
1087 return title;
1090 /* Callback for dialogs that get WM_DELETE_WINDOW. We pop down
1091 the dialog, but return TRUE so the event does not propagate further
1092 in GTK. This prevents GTK from destroying the dialog widget automatically
1093 and we can always destrou the widget manually, regardles of how
1094 it was popped down (button press or WM_DELETE_WINDOW).
1095 W is the dialog widget.
1096 EVENT is the GdkEvent that represents WM_DELETE_WINDOW (not used).
1097 user_data is NULL (not used).
1099 Returns TRUE to end propagation of event. */
1101 static gboolean
1102 dialog_delete_callback (w, event, user_data)
1103 GtkWidget *w;
1104 GdkEvent *event;
1105 gpointer user_data;
1107 gtk_widget_unmap (w);
1108 return TRUE;
1111 /* Create a popup dialog window. See also xg_create_widget below.
1112 WV is a widget_value describing the dialog.
1113 SELECT_CB is the callback to use when a button has been pressed.
1114 DEACTIVATE_CB is the callback to use when the dialog pops down.
1116 Returns the GTK dialog widget. */
1118 static GtkWidget *
1119 create_dialog (wv, select_cb, deactivate_cb)
1120 widget_value *wv;
1121 GCallback select_cb;
1122 GCallback deactivate_cb;
1124 char *title = get_dialog_title (wv->name[0]);
1125 int total_buttons = wv->name[1] - '0';
1126 int right_buttons = wv->name[4] - '0';
1127 int left_buttons;
1128 int button_nr = 0;
1129 int button_spacing = 10;
1130 GtkWidget *wdialog = gtk_dialog_new ();
1131 widget_value *item;
1132 GtkBox *cur_box;
1133 GtkWidget *wvbox;
1134 GtkWidget *whbox_up;
1135 GtkWidget *whbox_down;
1137 /* If the number of buttons is greater than 4, make two rows of buttons
1138 instead. This looks better. */
1139 int make_two_rows = total_buttons > 4;
1141 if (right_buttons == 0) right_buttons = total_buttons/2;
1142 left_buttons = total_buttons - right_buttons;
1144 gtk_window_set_title (GTK_WINDOW (wdialog), title);
1145 gtk_widget_set_name (wdialog, "emacs-dialog");
1147 cur_box = GTK_BOX (GTK_DIALOG (wdialog)->action_area);
1149 if (make_two_rows)
1151 wvbox = gtk_vbox_new (TRUE, button_spacing);
1152 whbox_up = gtk_hbox_new (FALSE, 0);
1153 whbox_down = gtk_hbox_new (FALSE, 0);
1155 gtk_box_pack_start (cur_box, wvbox, FALSE, FALSE, 0);
1156 gtk_box_pack_start (GTK_BOX (wvbox), whbox_up, FALSE, FALSE, 0);
1157 gtk_box_pack_start (GTK_BOX (wvbox), whbox_down, FALSE, FALSE, 0);
1159 cur_box = GTK_BOX (whbox_up);
1162 g_signal_connect (G_OBJECT (wdialog), "delete-event",
1163 G_CALLBACK (dialog_delete_callback), 0);
1165 if (deactivate_cb)
1167 g_signal_connect (G_OBJECT (wdialog), "close", deactivate_cb, 0);
1168 g_signal_connect (G_OBJECT (wdialog), "response", deactivate_cb, 0);
1171 for (item = wv->contents; item; item = item->next)
1173 char *utf8_label = get_utf8_string (item->value);
1174 GtkWidget *w;
1175 GtkRequisition req;
1177 if (item->name && strcmp (item->name, "message") == 0)
1179 /* This is the text part of the dialog. */
1180 w = gtk_label_new (utf8_label);
1181 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (wdialog)->vbox),
1182 gtk_label_new (""),
1183 FALSE, FALSE, 0);
1184 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (wdialog)->vbox), w,
1185 TRUE, TRUE, 0);
1186 gtk_misc_set_alignment (GTK_MISC (w), 0.1, 0.5);
1188 /* Try to make dialog look better. Must realize first so
1189 the widget can calculate the size it needs. */
1190 gtk_widget_realize (w);
1191 gtk_widget_size_request (w, &req);
1192 gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (wdialog)->vbox),
1193 req.height);
1194 if (item->value && strlen (item->value) > 0)
1195 button_spacing = 2*req.width/strlen (item->value);
1197 else
1199 /* This is one button to add to the dialog. */
1200 w = gtk_button_new_with_label (utf8_label);
1201 if (! item->enabled)
1202 gtk_widget_set_sensitive (w, FALSE);
1203 if (select_cb)
1204 g_signal_connect (G_OBJECT (w), "clicked",
1205 select_cb, item->call_data);
1207 gtk_box_pack_start (cur_box, w, TRUE, TRUE, button_spacing);
1208 if (++button_nr == left_buttons)
1210 if (make_two_rows)
1211 cur_box = GTK_BOX (whbox_down);
1212 else
1213 gtk_box_pack_start (cur_box,
1214 gtk_label_new (""),
1215 TRUE, TRUE,
1216 button_spacing);
1220 if (utf8_label && utf8_label != item->value)
1221 g_free (utf8_label);
1224 return wdialog;
1227 struct xg_dialog_data
1229 GMainLoop *loop;
1230 int response;
1231 GtkWidget *w;
1232 guint timerid;
1235 /* Function that is called when the file or font dialogs pop down.
1236 W is the dialog widget, RESPONSE is the response code.
1237 USER_DATA is what we passed in to g_signal_connect. */
1239 static void
1240 xg_dialog_response_cb (w,
1241 response,
1242 user_data)
1243 GtkDialog *w;
1244 gint response;
1245 gpointer user_data;
1247 struct xg_dialog_data *dd = (struct xg_dialog_data *)user_data;
1248 dd->response = response;
1249 g_main_loop_quit (dd->loop);
1253 /* Destroy the dialog. This makes it pop down. */
1255 static Lisp_Object
1256 pop_down_dialog (arg)
1257 Lisp_Object arg;
1259 struct Lisp_Save_Value *p = XSAVE_VALUE (arg);
1260 struct xg_dialog_data *dd = (struct xg_dialog_data *) p->pointer;
1262 BLOCK_INPUT;
1263 if (dd->w) gtk_widget_destroy (dd->w);
1264 if (dd->timerid != 0) g_source_remove (dd->timerid);
1266 g_main_loop_quit (dd->loop);
1267 g_main_loop_unref (dd->loop);
1269 UNBLOCK_INPUT;
1271 return Qnil;
1274 /* If there are any emacs timers pending, add a timeout to main loop in DATA.
1275 We pass in DATA as gpointer* so we can use this as a callback. */
1277 static gboolean
1278 xg_maybe_add_timer (data)
1279 gpointer data;
1281 struct xg_dialog_data *dd = (struct xg_dialog_data *) data;
1282 EMACS_TIME next_time = timer_check (1);
1283 long secs = EMACS_SECS (next_time);
1284 long usecs = EMACS_USECS (next_time);
1286 dd->timerid = 0;
1288 if (secs >= 0 && usecs >= 0 && secs < ((guint)-1)/1000)
1290 dd->timerid = g_timeout_add (secs * 1000 + usecs/1000,
1291 xg_maybe_add_timer,
1292 dd);
1294 return FALSE;
1298 /* Pops up a modal dialog W and waits for response.
1299 We don't use gtk_dialog_run because we want to process emacs timers.
1300 The dialog W is not destroyed when this function returns. */
1302 static int
1303 xg_dialog_run (f, w)
1304 FRAME_PTR f;
1305 GtkWidget *w;
1308 int count = SPECPDL_INDEX ();
1309 struct xg_dialog_data dd;
1311 xg_set_screen (w, f);
1312 gtk_window_set_transient_for (GTK_WINDOW (w),
1313 GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)));
1314 gtk_window_set_destroy_with_parent (GTK_WINDOW (w), TRUE);
1315 gtk_window_set_modal (GTK_WINDOW (w), TRUE);
1317 dd.loop = g_main_loop_new (NULL, FALSE);
1318 dd.response = GTK_RESPONSE_CANCEL;
1319 dd.w = w;
1320 dd.timerid = 0;
1322 g_signal_connect (G_OBJECT (w),
1323 "response",
1324 G_CALLBACK (xg_dialog_response_cb),
1325 &dd);
1326 /* Don't destroy the widget if closed by the window manager close button. */
1327 g_signal_connect (G_OBJECT (w), "delete-event", G_CALLBACK (gtk_true), NULL);
1328 gtk_widget_show (w);
1330 record_unwind_protect (pop_down_dialog, make_save_value (&dd, 0));
1332 (void) xg_maybe_add_timer (&dd);
1333 g_main_loop_run (dd.loop);
1335 dd.w = 0;
1336 unbind_to (count, Qnil);
1338 return dd.response;
1342 /***********************************************************************
1343 File dialog functions
1344 ***********************************************************************/
1345 /* Return non-zero if the old file selection dialog is being used.
1346 Return zero if not. */
1349 xg_uses_old_file_dialog ()
1351 #ifdef HAVE_GTK_FILE_BOTH
1352 extern int x_gtk_use_old_file_dialog;
1353 return x_gtk_use_old_file_dialog;
1354 #else /* ! HAVE_GTK_FILE_BOTH */
1356 #ifdef HAVE_GTK_FILE_SELECTION_NEW
1357 return 1;
1358 #else
1359 return 0;
1360 #endif
1362 #endif /* ! HAVE_GTK_FILE_BOTH */
1366 typedef char * (*xg_get_file_func) P_ ((GtkWidget *));
1368 #ifdef HAVE_GTK_FILE_CHOOSER_DIALOG_NEW
1370 /* Return the selected file for file chooser dialog W.
1371 The returned string must be free:d. */
1373 static char *
1374 xg_get_file_name_from_chooser (w)
1375 GtkWidget *w;
1377 return gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (w));
1380 /* Callback called when the "Show hidden files" toggle is pressed.
1381 WIDGET is the toggle widget, DATA is the file chooser dialog. */
1383 static void
1384 xg_toggle_visibility_cb (widget, data)
1385 GtkWidget *widget;
1386 gpointer data;
1388 GtkFileChooser *dialog = GTK_FILE_CHOOSER (data);
1389 gboolean visible;
1390 g_object_get (G_OBJECT (dialog), "show-hidden", &visible, NULL);
1391 g_object_set (G_OBJECT (dialog), "show-hidden", !visible, NULL);
1395 /* Callback called when a property changes in a file chooser.
1396 GOBJECT is the file chooser dialog, ARG1 describes the property.
1397 USER_DATA is the toggle widget in the file chooser dialog.
1398 We use this to update the "Show hidden files" toggle when the user
1399 changes that property by right clicking in the file list. */
1401 static void
1402 xg_toggle_notify_cb (gobject, arg1, user_data)
1403 GObject *gobject;
1404 GParamSpec *arg1;
1405 gpointer user_data;
1407 extern int x_gtk_show_hidden_files;
1409 if (strcmp (arg1->name, "show-hidden") == 0)
1411 GtkFileChooser *dialog = GTK_FILE_CHOOSER (gobject);
1412 GtkWidget *wtoggle = GTK_WIDGET (user_data);
1413 gboolean visible, toggle_on;
1415 g_object_get (G_OBJECT (gobject), "show-hidden", &visible, NULL);
1416 toggle_on = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (wtoggle));
1418 if (!!visible != !!toggle_on)
1420 g_signal_handlers_block_by_func (G_OBJECT (wtoggle),
1421 G_CALLBACK (xg_toggle_visibility_cb),
1422 gobject);
1423 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wtoggle), visible);
1424 g_signal_handlers_unblock_by_func
1425 (G_OBJECT (wtoggle),
1426 G_CALLBACK (xg_toggle_visibility_cb),
1427 gobject);
1429 x_gtk_show_hidden_files = visible;
1433 /* Read a file name from the user using a file chooser dialog.
1434 F is the current frame.
1435 PROMPT is a prompt to show to the user. May not be NULL.
1436 DEFAULT_FILENAME is a default selection to be displayed. May be NULL.
1437 If MUSTMATCH_P is non-zero, the returned file name must be an existing
1438 file. *FUNC is set to a function that can be used to retrieve the
1439 selected file name from the returned widget.
1441 Returns the created widget. */
1443 static GtkWidget *
1444 xg_get_file_with_chooser (f, prompt, default_filename,
1445 mustmatch_p, only_dir_p, func)
1446 FRAME_PTR f;
1447 char *prompt;
1448 char *default_filename;
1449 int mustmatch_p, only_dir_p;
1450 xg_get_file_func *func;
1452 char message[1024];
1454 GtkWidget *filewin, *wtoggle, *wbox, *wmessage;
1455 GtkWindow *gwin = GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f));
1456 GtkFileChooserAction action = (mustmatch_p ?
1457 GTK_FILE_CHOOSER_ACTION_OPEN :
1458 GTK_FILE_CHOOSER_ACTION_SAVE);
1459 extern int x_gtk_show_hidden_files;
1460 extern int x_gtk_file_dialog_help_text;
1463 if (only_dir_p)
1464 action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
1466 filewin = gtk_file_chooser_dialog_new (prompt, gwin, action,
1467 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1468 (mustmatch_p || only_dir_p ?
1469 GTK_STOCK_OPEN : GTK_STOCK_OK),
1470 GTK_RESPONSE_OK,
1471 NULL);
1472 gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (filewin), TRUE);
1474 wbox = gtk_vbox_new (FALSE, 0);
1475 gtk_widget_show (wbox);
1476 wtoggle = gtk_check_button_new_with_label ("Show hidden files.");
1478 if (x_gtk_show_hidden_files)
1480 g_object_set (G_OBJECT (filewin), "show-hidden", TRUE, NULL);
1481 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wtoggle), TRUE);
1483 gtk_widget_show (wtoggle);
1484 g_signal_connect (G_OBJECT (wtoggle), "clicked",
1485 G_CALLBACK (xg_toggle_visibility_cb), filewin);
1486 g_signal_connect (G_OBJECT (filewin), "notify",
1487 G_CALLBACK (xg_toggle_notify_cb), wtoggle);
1489 if (x_gtk_file_dialog_help_text)
1491 message[0] = '\0';
1492 /* Gtk+ 2.10 has the file name text entry box integrated in the dialog.
1493 Show the C-l help text only for versions < 2.10. */
1494 if (gtk_check_version (2, 10, 0) && action != GTK_FILE_CHOOSER_ACTION_SAVE)
1495 strcat (message, "\nType C-l to display a file name text entry box.\n");
1496 strcat (message, "\nIf you don't like this file selector, use the "
1497 "corresponding\nkey binding or customize "
1498 "use-file-dialog to turn it off.");
1500 wmessage = gtk_label_new (message);
1501 gtk_widget_show (wmessage);
1504 gtk_box_pack_start (GTK_BOX (wbox), wtoggle, FALSE, FALSE, 0);
1505 if (x_gtk_file_dialog_help_text)
1506 gtk_box_pack_start (GTK_BOX (wbox), wmessage, FALSE, FALSE, 0);
1507 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (filewin), wbox);
1509 if (default_filename)
1511 Lisp_Object file;
1512 struct gcpro gcpro1;
1513 char *utf8_filename;
1514 GCPRO1 (file);
1516 file = build_string (default_filename);
1518 /* File chooser does not understand ~/... in the file name. It must be
1519 an absolute name starting with /. */
1520 if (default_filename[0] != '/')
1521 file = Fexpand_file_name (file, Qnil);
1523 utf8_filename = SSDATA (ENCODE_UTF_8 (file));
1524 if (! NILP (Ffile_directory_p (file)))
1525 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (filewin),
1526 utf8_filename);
1527 else
1529 gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (filewin),
1530 utf8_filename);
1531 if (action == GTK_FILE_CHOOSER_ACTION_SAVE)
1533 char *cp = strrchr (utf8_filename, '/');
1534 if (cp) ++cp;
1535 else cp = utf8_filename;
1536 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (filewin), cp);
1540 UNGCPRO;
1543 *func = xg_get_file_name_from_chooser;
1544 return filewin;
1546 #endif /* HAVE_GTK_FILE_CHOOSER_DIALOG_NEW */
1548 #ifdef HAVE_GTK_FILE_SELECTION_NEW
1550 /* Return the selected file for file selector dialog W.
1551 The returned string must be free:d. */
1553 static char *
1554 xg_get_file_name_from_selector (w)
1555 GtkWidget *w;
1557 GtkFileSelection *filesel = GTK_FILE_SELECTION (w);
1558 return xstrdup ((char*) gtk_file_selection_get_filename (filesel));
1561 /* Create a file selection dialog.
1562 F is the current frame.
1563 PROMPT is a prompt to show to the user. May not be NULL.
1564 DEFAULT_FILENAME is a default selection to be displayed. May be NULL.
1565 If MUSTMATCH_P is non-zero, the returned file name must be an existing
1566 file. *FUNC is set to a function that can be used to retrieve the
1567 selected file name from the returned widget.
1569 Returns the created widget. */
1571 static GtkWidget *
1572 xg_get_file_with_selection (f, prompt, default_filename,
1573 mustmatch_p, only_dir_p, func)
1574 FRAME_PTR f;
1575 char *prompt;
1576 char *default_filename;
1577 int mustmatch_p, only_dir_p;
1578 xg_get_file_func *func;
1580 GtkWidget *filewin;
1581 GtkFileSelection *filesel;
1583 filewin = gtk_file_selection_new (prompt);
1584 filesel = GTK_FILE_SELECTION (filewin);
1586 if (default_filename)
1587 gtk_file_selection_set_filename (filesel, default_filename);
1589 if (mustmatch_p)
1591 /* The selection_entry part of filesel is not documented. */
1592 gtk_widget_set_sensitive (filesel->selection_entry, FALSE);
1593 gtk_file_selection_hide_fileop_buttons (filesel);
1596 *func = xg_get_file_name_from_selector;
1598 return filewin;
1600 #endif /* HAVE_GTK_FILE_SELECTION_NEW */
1602 /* Read a file name from the user using a file dialog, either the old
1603 file selection dialog, or the new file chooser dialog. Which to use
1604 depends on what the GTK version used has, and what the value of
1605 gtk-use-old-file-dialog.
1606 F is the current frame.
1607 PROMPT is a prompt to show to the user. May not be NULL.
1608 DEFAULT_FILENAME is a default selection to be displayed. May be NULL.
1609 If MUSTMATCH_P is non-zero, the returned file name must be an existing
1610 file.
1612 Returns a file name or NULL if no file was selected.
1613 The returned string must be freed by the caller. */
1615 char *
1616 xg_get_file_name (f, prompt, default_filename, mustmatch_p, only_dir_p)
1617 FRAME_PTR f;
1618 char *prompt;
1619 char *default_filename;
1620 int mustmatch_p, only_dir_p;
1622 GtkWidget *w = 0;
1623 char *fn = 0;
1624 int filesel_done = 0;
1625 xg_get_file_func func;
1627 #if defined (HAVE_GTK_AND_PTHREAD) && defined (__SIGRTMIN)
1628 /* I really don't know why this is needed, but without this the GLIBC add on
1629 library linuxthreads hangs when the Gnome file chooser backend creates
1630 threads. */
1631 sigblock (sigmask (__SIGRTMIN));
1632 #endif /* HAVE_GTK_AND_PTHREAD */
1634 #ifdef HAVE_GTK_FILE_BOTH
1636 if (xg_uses_old_file_dialog ())
1637 w = xg_get_file_with_selection (f, prompt, default_filename,
1638 mustmatch_p, only_dir_p, &func);
1639 else
1640 w = xg_get_file_with_chooser (f, prompt, default_filename,
1641 mustmatch_p, only_dir_p, &func);
1643 #else /* not HAVE_GTK_FILE_BOTH */
1645 #ifdef HAVE_GTK_FILE_SELECTION_NEW
1646 w = xg_get_file_with_selection (f, prompt, default_filename,
1647 mustmatch_p, only_dir_p, &func);
1648 #endif
1649 #ifdef HAVE_GTK_FILE_CHOOSER_DIALOG_NEW
1650 w = xg_get_file_with_chooser (f, prompt, default_filename,
1651 mustmatch_p, only_dir_p, &func);
1652 #endif
1654 #endif /* HAVE_GTK_FILE_BOTH */
1656 gtk_widget_set_name (w, "emacs-filedialog");
1658 filesel_done = xg_dialog_run (f, w);
1660 #if defined (HAVE_GTK_AND_PTHREAD) && defined (__SIGRTMIN)
1661 sigunblock (sigmask (__SIGRTMIN));
1662 #endif
1664 if (filesel_done == GTK_RESPONSE_OK)
1665 fn = (*func) (w);
1667 gtk_widget_destroy (w);
1668 return fn;
1671 #ifdef HAVE_FREETYPE
1672 /* Pop up a GTK font selector and return the name of the font the user
1673 selects, as a C string. The returned font name follows GTK's own
1674 format:
1676 `FAMILY [VALUE1 VALUE2] SIZE'
1678 This can be parsed using font_parse_fcname in font.c.
1679 DEFAULT_NAME, if non-zero, is the default font name. */
1681 char *
1682 xg_get_font_name (f, default_name)
1683 FRAME_PTR f;
1684 char *default_name;
1686 GtkWidget *w;
1687 char *fontname = NULL;
1688 int done = 0;
1690 #if defined (HAVE_GTK_AND_PTHREAD) && defined (__SIGRTMIN)
1691 sigblock (sigmask (__SIGRTMIN));
1692 #endif /* HAVE_GTK_AND_PTHREAD */
1694 w = gtk_font_selection_dialog_new ("Pick a font");
1695 if (!default_name)
1696 default_name = "Monospace 10";
1697 gtk_font_selection_dialog_set_font_name (GTK_FONT_SELECTION_DIALOG (w),
1698 default_name);
1700 gtk_widget_set_name (w, "emacs-fontdialog");
1702 done = xg_dialog_run (f, w);
1704 #if defined (HAVE_GTK_AND_PTHREAD) && defined (__SIGRTMIN)
1705 sigunblock (sigmask (__SIGRTMIN));
1706 #endif
1708 if (done == GTK_RESPONSE_OK)
1709 fontname = gtk_font_selection_dialog_get_font_name
1710 (GTK_FONT_SELECTION_DIALOG (w));
1712 gtk_widget_destroy (w);
1713 return fontname;
1715 #endif /* HAVE_FREETYPE */
1719 /***********************************************************************
1720 Menu functions.
1721 ***********************************************************************/
1723 /* The name of menu items that can be used for customization. Since GTK
1724 RC files are very crude and primitive, we have to set this on all
1725 menu item names so a user can easily customize menu items. */
1727 #define MENU_ITEM_NAME "emacs-menuitem"
1730 /* Linked list of all allocated struct xg_menu_cb_data. Used for marking
1731 during GC. The next member points to the items. */
1732 static xg_list_node xg_menu_cb_list;
1734 /* Linked list of all allocated struct xg_menu_item_cb_data. Used for marking
1735 during GC. The next member points to the items. */
1736 static xg_list_node xg_menu_item_cb_list;
1738 /* Allocate and initialize CL_DATA if NULL, otherwise increase ref_count.
1739 F is the frame CL_DATA will be initialized for.
1740 HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
1742 The menu bar and all sub menus under the menu bar in a frame
1743 share the same structure, hence the reference count.
1745 Returns CL_DATA if CL_DATA is not NULL, or a pointer to a newly
1746 allocated xg_menu_cb_data if CL_DATA is NULL. */
1748 static xg_menu_cb_data *
1749 make_cl_data (cl_data, f, highlight_cb)
1750 xg_menu_cb_data *cl_data;
1751 FRAME_PTR f;
1752 GCallback highlight_cb;
1754 if (! cl_data)
1756 cl_data = (xg_menu_cb_data*) xmalloc (sizeof (*cl_data));
1757 cl_data->f = f;
1758 cl_data->menu_bar_vector = f->menu_bar_vector;
1759 cl_data->menu_bar_items_used = f->menu_bar_items_used;
1760 cl_data->highlight_cb = highlight_cb;
1761 cl_data->ref_count = 0;
1763 xg_list_insert (&xg_menu_cb_list, &cl_data->ptrs);
1766 cl_data->ref_count++;
1768 return cl_data;
1771 /* Update CL_DATA with values from frame F and with HIGHLIGHT_CB.
1772 HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
1774 When the menu bar is updated, menu items may have been added and/or
1775 removed, so menu_bar_vector and menu_bar_items_used change. We must
1776 then update CL_DATA since it is used to determine which menu
1777 item that is invoked in the menu.
1778 HIGHLIGHT_CB could change, there is no check that the same
1779 function is given when modifying a menu bar as was given when
1780 creating the menu bar. */
1782 static void
1783 update_cl_data (cl_data, f, highlight_cb)
1784 xg_menu_cb_data *cl_data;
1785 FRAME_PTR f;
1786 GCallback highlight_cb;
1788 if (cl_data)
1790 cl_data->f = f;
1791 cl_data->menu_bar_vector = f->menu_bar_vector;
1792 cl_data->menu_bar_items_used = f->menu_bar_items_used;
1793 cl_data->highlight_cb = highlight_cb;
1797 /* Decrease reference count for CL_DATA.
1798 If reference count is zero, free CL_DATA. */
1800 static void
1801 unref_cl_data (cl_data)
1802 xg_menu_cb_data *cl_data;
1804 if (cl_data && cl_data->ref_count > 0)
1806 cl_data->ref_count--;
1807 if (cl_data->ref_count == 0)
1809 xg_list_remove (&xg_menu_cb_list, &cl_data->ptrs);
1810 xfree (cl_data);
1815 /* Function that marks all lisp data during GC. */
1817 void
1818 xg_mark_data ()
1820 xg_list_node *iter;
1822 for (iter = xg_menu_cb_list.next; iter; iter = iter->next)
1823 mark_object (((xg_menu_cb_data *) iter)->menu_bar_vector);
1825 for (iter = xg_menu_item_cb_list.next; iter; iter = iter->next)
1827 xg_menu_item_cb_data *cb_data = (xg_menu_item_cb_data *) iter;
1829 if (! NILP (cb_data->help))
1830 mark_object (cb_data->help);
1835 /* Callback called when a menu item is destroyed. Used to free data.
1836 W is the widget that is being destroyed (not used).
1837 CLIENT_DATA points to the xg_menu_item_cb_data associated with the W. */
1839 static void
1840 menuitem_destroy_callback (w, client_data)
1841 GtkWidget *w;
1842 gpointer client_data;
1844 if (client_data)
1846 xg_menu_item_cb_data *data = (xg_menu_item_cb_data*) client_data;
1847 xg_list_remove (&xg_menu_item_cb_list, &data->ptrs);
1848 xfree (data);
1852 /* Callback called when the pointer enters/leaves a menu item.
1853 W is the parent of the menu item.
1854 EVENT is either an enter event or leave event.
1855 CLIENT_DATA is not used.
1857 Returns FALSE to tell GTK to keep processing this event. */
1859 static gboolean
1860 menuitem_highlight_callback (w, event, client_data)
1861 GtkWidget *w;
1862 GdkEventCrossing *event;
1863 gpointer client_data;
1865 GdkEvent ev;
1866 GtkWidget *subwidget;
1867 xg_menu_item_cb_data *data;
1869 ev.crossing = *event;
1870 subwidget = gtk_get_event_widget (&ev);
1871 data = (xg_menu_item_cb_data *) g_object_get_data (G_OBJECT (subwidget),
1872 XG_ITEM_DATA);
1873 if (data)
1875 if (! NILP (data->help) && data->cl_data->highlight_cb)
1877 gpointer call_data = event->type == GDK_LEAVE_NOTIFY ? 0 : data;
1878 GtkCallback func = (GtkCallback) data->cl_data->highlight_cb;
1879 (*func) (subwidget, call_data);
1883 return FALSE;
1886 /* Callback called when a menu is destroyed. Used to free data.
1887 W is the widget that is being destroyed (not used).
1888 CLIENT_DATA points to the xg_menu_cb_data associated with W. */
1890 static void
1891 menu_destroy_callback (w, client_data)
1892 GtkWidget *w;
1893 gpointer client_data;
1895 unref_cl_data ((xg_menu_cb_data*) client_data);
1898 /* Callback called when a menu does a grab or ungrab. That means the
1899 menu has been activated or deactivated.
1900 Used to start a timer so the small timeout the menus in GTK uses before
1901 popping down a menu is seen by Emacs (see xg_process_timeouts above).
1902 W is the widget that does the grab (not used).
1903 UNGRAB_P is TRUE if this is an ungrab, FALSE if it is a grab.
1904 CLIENT_DATA is NULL (not used). */
1906 /* Keep track of total number of grabs. */
1907 static int menu_grab_callback_cnt;
1909 static void
1910 menu_grab_callback (GtkWidget *widget,
1911 gboolean ungrab_p,
1912 gpointer client_data)
1914 if (ungrab_p) menu_grab_callback_cnt--;
1915 else menu_grab_callback_cnt++;
1917 if (menu_grab_callback_cnt > 0 && ! xg_timer) xg_start_timer ();
1918 else if (menu_grab_callback_cnt == 0 && xg_timer) xg_stop_timer ();
1921 /* Make a GTK widget that contains both UTF8_LABEL and UTF8_KEY (both
1922 must be non-NULL) and can be inserted into a menu item.
1924 Returns the GtkHBox. */
1926 static GtkWidget *
1927 make_widget_for_menu_item (utf8_label, utf8_key)
1928 char *utf8_label;
1929 char *utf8_key;
1931 GtkWidget *wlbl;
1932 GtkWidget *wkey;
1933 GtkWidget *wbox;
1935 wbox = gtk_hbox_new (FALSE, 0);
1936 wlbl = gtk_label_new (utf8_label);
1937 wkey = gtk_label_new (utf8_key);
1939 gtk_misc_set_alignment (GTK_MISC (wlbl), 0.0, 0.5);
1940 gtk_misc_set_alignment (GTK_MISC (wkey), 0.0, 0.5);
1942 gtk_box_pack_start (GTK_BOX (wbox), wlbl, TRUE, TRUE, 0);
1943 gtk_box_pack_start (GTK_BOX (wbox), wkey, FALSE, FALSE, 0);
1945 gtk_widget_set_name (wlbl, MENU_ITEM_NAME);
1946 gtk_widget_set_name (wkey, MENU_ITEM_NAME);
1947 gtk_widget_set_name (wbox, MENU_ITEM_NAME);
1949 return wbox;
1952 /* Make and return a menu item widget with the key to the right.
1953 UTF8_LABEL is the text for the menu item (GTK uses UTF8 internally).
1954 UTF8_KEY is the text representing the key binding.
1955 ITEM is the widget_value describing the menu item.
1957 GROUP is an in/out parameter. If the menu item to be created is not
1958 part of any radio menu group, *GROUP contains NULL on entry and exit.
1959 If the menu item to be created is part of a radio menu group, on entry
1960 *GROUP contains the group to use, or NULL if this is the first item
1961 in the group. On exit, *GROUP contains the radio item group.
1963 Unfortunately, keys don't line up as nicely as in Motif,
1964 but the MacOS X version doesn't either, so I guess that is OK. */
1966 static GtkWidget *
1967 make_menu_item (utf8_label, utf8_key, item, group)
1968 char *utf8_label;
1969 char *utf8_key;
1970 widget_value *item;
1971 GSList **group;
1973 GtkWidget *w;
1974 GtkWidget *wtoadd = 0;
1976 /* It has been observed that some menu items have a NULL name field.
1977 This will lead to this function being called with a NULL utf8_label.
1978 GTK crashes on that so we set a blank label. Why there is a NULL
1979 name remains to be investigated. */
1980 if (! utf8_label) utf8_label = " ";
1982 if (utf8_key)
1983 wtoadd = make_widget_for_menu_item (utf8_label, utf8_key);
1985 if (item->button_type == BUTTON_TYPE_TOGGLE)
1987 *group = NULL;
1988 if (utf8_key) w = gtk_check_menu_item_new ();
1989 else w = gtk_check_menu_item_new_with_label (utf8_label);
1990 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w), item->selected);
1992 else if (item->button_type == BUTTON_TYPE_RADIO)
1994 if (utf8_key) w = gtk_radio_menu_item_new (*group);
1995 else w = gtk_radio_menu_item_new_with_label (*group, utf8_label);
1996 *group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (w));
1997 if (item->selected)
1998 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w), TRUE);
2000 else
2002 *group = NULL;
2003 if (utf8_key) w = gtk_menu_item_new ();
2004 else w = gtk_menu_item_new_with_label (utf8_label);
2007 if (wtoadd) gtk_container_add (GTK_CONTAINER (w), wtoadd);
2008 if (! item->enabled) gtk_widget_set_sensitive (w, FALSE);
2010 return w;
2013 /* Return non-zero if LABEL specifies a separator (GTK only has one
2014 separator type) */
2016 static const char* separator_names[] = {
2017 "space",
2018 "no-line",
2019 "single-line",
2020 "double-line",
2021 "single-dashed-line",
2022 "double-dashed-line",
2023 "shadow-etched-in",
2024 "shadow-etched-out",
2025 "shadow-etched-in-dash",
2026 "shadow-etched-out-dash",
2027 "shadow-double-etched-in",
2028 "shadow-double-etched-out",
2029 "shadow-double-etched-in-dash",
2030 "shadow-double-etched-out-dash",
2034 static int
2035 xg_separator_p (char *label)
2037 if (! label) return 0;
2038 else if (strlen (label) > 3
2039 && strncmp (label, "--", 2) == 0
2040 && label[2] != '-')
2042 int i;
2044 label += 2;
2045 for (i = 0; separator_names[i]; ++i)
2046 if (strcmp (label, separator_names[i]) == 0)
2047 return 1;
2049 else
2051 /* Old-style separator, maybe. It's a separator if it contains
2052 only dashes. */
2053 while (*label == '-')
2054 ++label;
2055 if (*label == 0) return 1;
2058 return 0;
2061 static int xg_detached_menus;
2063 /* Returns non-zero if there are detached menus. */
2066 xg_have_tear_offs ()
2068 return xg_detached_menus > 0;
2071 /* Callback invoked when a detached menu window is removed. Here we
2072 decrease the xg_detached_menus count.
2073 WIDGET is the top level window that is removed (the parent of the menu).
2074 CLIENT_DATA is not used. */
2076 static void
2077 tearoff_remove (widget, client_data)
2078 GtkWidget *widget;
2079 gpointer client_data;
2081 if (xg_detached_menus > 0) --xg_detached_menus;
2084 /* Callback invoked when a menu is detached. It increases the
2085 xg_detached_menus count.
2086 WIDGET is the GtkTearoffMenuItem.
2087 CLIENT_DATA is not used. */
2089 static void
2090 tearoff_activate (widget, client_data)
2091 GtkWidget *widget;
2092 gpointer client_data;
2094 GtkWidget *menu = gtk_widget_get_parent (widget);
2095 if (gtk_menu_get_tearoff_state (GTK_MENU (menu)))
2097 ++xg_detached_menus;
2098 g_signal_connect (G_OBJECT (gtk_widget_get_toplevel (widget)),
2099 "destroy",
2100 G_CALLBACK (tearoff_remove), 0);
2105 /* Create a menu item widget, and connect the callbacks.
2106 ITEM decribes the menu item.
2107 F is the frame the created menu belongs to.
2108 SELECT_CB is the callback to use when a menu item is selected.
2109 HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
2110 CL_DATA points to the callback data to be used for this menu.
2111 GROUP is an in/out parameter. If the menu item to be created is not
2112 part of any radio menu group, *GROUP contains NULL on entry and exit.
2113 If the menu item to be created is part of a radio menu group, on entry
2114 *GROUP contains the group to use, or NULL if this is the first item
2115 in the group. On exit, *GROUP contains the radio item group.
2117 Returns the created GtkWidget. */
2119 static GtkWidget *
2120 xg_create_one_menuitem (item, f, select_cb, highlight_cb, cl_data, group)
2121 widget_value *item;
2122 FRAME_PTR f;
2123 GCallback select_cb;
2124 GCallback highlight_cb;
2125 xg_menu_cb_data *cl_data;
2126 GSList **group;
2128 char *utf8_label;
2129 char *utf8_key;
2130 GtkWidget *w;
2131 xg_menu_item_cb_data *cb_data;
2133 utf8_label = get_utf8_string (item->name);
2134 utf8_key = get_utf8_string (item->key);
2136 w = make_menu_item (utf8_label, utf8_key, item, group);
2138 if (utf8_label && utf8_label != item->name) g_free (utf8_label);
2139 if (utf8_key && utf8_key != item->key) g_free (utf8_key);
2141 cb_data = xmalloc (sizeof (xg_menu_item_cb_data));
2143 xg_list_insert (&xg_menu_item_cb_list, &cb_data->ptrs);
2145 cb_data->select_id = 0;
2146 cb_data->help = item->help;
2147 cb_data->cl_data = cl_data;
2148 cb_data->call_data = item->call_data;
2150 g_signal_connect (G_OBJECT (w),
2151 "destroy",
2152 G_CALLBACK (menuitem_destroy_callback),
2153 cb_data);
2155 /* Put cb_data in widget, so we can get at it when modifying menubar */
2156 g_object_set_data (G_OBJECT (w), XG_ITEM_DATA, cb_data);
2158 /* final item, not a submenu */
2159 if (item->call_data && ! item->contents)
2161 if (select_cb)
2162 cb_data->select_id
2163 = g_signal_connect (G_OBJECT (w), "activate", select_cb, cb_data);
2166 return w;
2169 static GtkWidget *create_menus P_ ((widget_value *, FRAME_PTR, GCallback,
2170 GCallback, GCallback, int, int, int,
2171 GtkWidget *, xg_menu_cb_data *, char *));
2173 /* Create a full menu tree specified by DATA.
2174 F is the frame the created menu belongs to.
2175 SELECT_CB is the callback to use when a menu item is selected.
2176 DEACTIVATE_CB is the callback to use when a sub menu is not shown anymore.
2177 HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
2178 POP_UP_P is non-zero if we shall create a popup menu.
2179 MENU_BAR_P is non-zero if we shall create a menu bar.
2180 ADD_TEAROFF_P is non-zero if we shall add a teroff menu item. Ignored
2181 if MENU_BAR_P is non-zero.
2182 TOPMENU is the topmost GtkWidget that others shall be placed under.
2183 It may be NULL, in that case we create the appropriate widget
2184 (menu bar or menu item depending on POP_UP_P and MENU_BAR_P)
2185 CL_DATA is the callback data we shall use for this menu, or NULL
2186 if we haven't set the first callback yet.
2187 NAME is the name to give to the top level menu if this function
2188 creates it. May be NULL to not set any name.
2190 Returns the top level GtkWidget. This is TOPLEVEL if TOPLEVEL is
2191 not NULL.
2193 This function calls itself to create submenus. */
2195 static GtkWidget *
2196 create_menus (data, f, select_cb, deactivate_cb, highlight_cb,
2197 pop_up_p, menu_bar_p, add_tearoff_p, topmenu, cl_data, name)
2198 widget_value *data;
2199 FRAME_PTR f;
2200 GCallback select_cb;
2201 GCallback deactivate_cb;
2202 GCallback highlight_cb;
2203 int pop_up_p;
2204 int menu_bar_p;
2205 int add_tearoff_p;
2206 GtkWidget *topmenu;
2207 xg_menu_cb_data *cl_data;
2208 char *name;
2210 widget_value *item;
2211 GtkWidget *wmenu = topmenu;
2212 GSList *group = NULL;
2214 if (! topmenu)
2216 if (! menu_bar_p)
2218 wmenu = gtk_menu_new ();
2219 xg_set_screen (wmenu, f);
2220 /* Connect this to the menu instead of items so we get enter/leave for
2221 disabled items also. TODO: Still does not get enter/leave for
2222 disabled items in detached menus. */
2223 g_signal_connect (G_OBJECT (wmenu),
2224 "enter-notify-event",
2225 G_CALLBACK (menuitem_highlight_callback),
2226 NULL);
2227 g_signal_connect (G_OBJECT (wmenu),
2228 "leave-notify-event",
2229 G_CALLBACK (menuitem_highlight_callback),
2230 NULL);
2232 else
2234 wmenu = gtk_menu_bar_new ();
2235 // Set width of menu bar to a small value so it doesn't enlarge
2236 // a small initial frame size. The width will be set to the
2237 // width of the frame later on when it is added to a container.
2238 // height -1: Natural height.
2239 gtk_widget_set_size_request (wmenu, 1, -1);
2242 /* Put cl_data on the top menu for easier access. */
2243 cl_data = make_cl_data (cl_data, f, highlight_cb);
2244 g_object_set_data (G_OBJECT (wmenu), XG_FRAME_DATA, (gpointer)cl_data);
2245 g_signal_connect (G_OBJECT (wmenu), "destroy",
2246 G_CALLBACK (menu_destroy_callback), cl_data);
2248 if (name)
2249 gtk_widget_set_name (wmenu, name);
2251 if (deactivate_cb)
2252 g_signal_connect (G_OBJECT (wmenu),
2253 "selection-done", deactivate_cb, 0);
2255 g_signal_connect (G_OBJECT (wmenu),
2256 "grab-notify", G_CALLBACK (menu_grab_callback), 0);
2259 if (! menu_bar_p && add_tearoff_p)
2261 GtkWidget *tearoff = gtk_tearoff_menu_item_new ();
2262 gtk_menu_shell_append (GTK_MENU_SHELL (wmenu), tearoff);
2264 g_signal_connect (G_OBJECT (tearoff), "activate",
2265 G_CALLBACK (tearoff_activate), 0);
2268 for (item = data; item; item = item->next)
2270 GtkWidget *w;
2272 if (pop_up_p && !item->contents && !item->call_data
2273 && !xg_separator_p (item->name))
2275 char *utf8_label;
2276 /* A title for a popup. We do the same as GTK does when
2277 creating titles, but it does not look good. */
2278 group = NULL;
2279 utf8_label = get_utf8_string (item->name);
2281 gtk_menu_set_title (GTK_MENU (wmenu), utf8_label);
2282 w = gtk_menu_item_new_with_label (utf8_label);
2283 gtk_widget_set_sensitive (w, FALSE);
2284 if (utf8_label && utf8_label != item->name) g_free (utf8_label);
2286 else if (xg_separator_p (item->name))
2288 group = NULL;
2289 /* GTK only have one separator type. */
2290 w = gtk_separator_menu_item_new ();
2292 else
2294 w = xg_create_one_menuitem (item,
2296 item->contents ? 0 : select_cb,
2297 highlight_cb,
2298 cl_data,
2299 &group);
2301 /* Create a possibly empty submenu for menu bar items, since some
2302 themes don't highlight items correctly without it. */
2303 if (item->contents || menu_bar_p)
2305 GtkWidget *submenu = create_menus (item->contents,
2307 select_cb,
2308 deactivate_cb,
2309 highlight_cb,
2312 add_tearoff_p,
2314 cl_data,
2316 gtk_menu_item_set_submenu (GTK_MENU_ITEM (w), submenu);
2320 gtk_menu_shell_append (GTK_MENU_SHELL (wmenu), w);
2321 gtk_widget_set_name (w, MENU_ITEM_NAME);
2324 return wmenu;
2327 /* Create a menubar, popup menu or dialog, depending on the TYPE argument.
2328 TYPE can be "menubar", "popup" for popup menu, or "dialog" for a dialog
2329 with some text and buttons.
2330 F is the frame the created item belongs to.
2331 NAME is the name to use for the top widget.
2332 VAL is a widget_value structure describing items to be created.
2333 SELECT_CB is the callback to use when a menu item is selected or
2334 a dialog button is pressed.
2335 DEACTIVATE_CB is the callback to use when an item is deactivated.
2336 For a menu, when a sub menu is not shown anymore, for a dialog it is
2337 called when the dialog is popped down.
2338 HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
2340 Returns the widget created. */
2342 GtkWidget *
2343 xg_create_widget (type, name, f, val,
2344 select_cb, deactivate_cb, highlight_cb)
2345 char *type;
2346 char *name;
2347 FRAME_PTR f;
2348 widget_value *val;
2349 GCallback select_cb;
2350 GCallback deactivate_cb;
2351 GCallback highlight_cb;
2353 GtkWidget *w = 0;
2354 int menu_bar_p = strcmp (type, "menubar") == 0;
2355 int pop_up_p = strcmp (type, "popup") == 0;
2357 if (strcmp (type, "dialog") == 0)
2359 w = create_dialog (val, select_cb, deactivate_cb);
2360 xg_set_screen (w, f);
2361 gtk_window_set_transient_for (GTK_WINDOW (w),
2362 GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)));
2363 gtk_window_set_destroy_with_parent (GTK_WINDOW (w), TRUE);
2364 gtk_widget_set_name (w, "emacs-dialog");
2365 gtk_window_set_modal (GTK_WINDOW (w), TRUE);
2367 else if (menu_bar_p || pop_up_p)
2369 w = create_menus (val->contents,
2371 select_cb,
2372 deactivate_cb,
2373 highlight_cb,
2374 pop_up_p,
2375 menu_bar_p,
2376 menu_bar_p,
2379 name);
2381 /* Set the cursor to an arrow for popup menus when they are mapped.
2382 This is done by default for menu bar menus. */
2383 if (pop_up_p)
2385 /* Must realize so the GdkWindow inside the widget is created. */
2386 gtk_widget_realize (w);
2387 xg_set_cursor (w, FRAME_X_DISPLAY_INFO (f)->xg_cursor);
2390 else
2392 fprintf (stderr, "bad type in xg_create_widget: %s, doing nothing\n",
2393 type);
2396 return w;
2399 /* Return the label for menu item WITEM. */
2401 static const char *
2402 xg_get_menu_item_label (witem)
2403 GtkMenuItem *witem;
2405 GtkLabel *wlabel = GTK_LABEL (gtk_bin_get_child (GTK_BIN (witem)));
2406 return gtk_label_get_label (wlabel);
2409 /* Return non-zero if the menu item WITEM has the text LABEL. */
2411 static int
2412 xg_item_label_same_p (witem, label)
2413 GtkMenuItem *witem;
2414 char *label;
2416 int is_same = 0;
2417 char *utf8_label = get_utf8_string (label);
2418 const char *old_label = witem ? xg_get_menu_item_label (witem) : 0;
2420 if (! old_label && ! utf8_label)
2421 is_same = 1;
2422 else if (old_label && utf8_label)
2423 is_same = strcmp (utf8_label, old_label) == 0;
2425 if (utf8_label && utf8_label != label) g_free (utf8_label);
2427 return is_same;
2430 /* Destroy widgets in LIST. */
2432 static void
2433 xg_destroy_widgets (list)
2434 GList *list;
2436 GList *iter;
2438 for (iter = list; iter; iter = g_list_next (iter))
2440 GtkWidget *w = GTK_WIDGET (iter->data);
2442 /* Destroying the widget will remove it from the container it is in. */
2443 gtk_widget_destroy (w);
2447 /* Update the top level names in MENUBAR (i.e. not submenus).
2448 F is the frame the menu bar belongs to.
2449 *LIST is a list with the current menu bar names (menu item widgets).
2450 ITER is the item within *LIST that shall be updated.
2451 POS is the numerical position, starting at 0, of ITER in *LIST.
2452 VAL describes what the menu bar shall look like after the update.
2453 SELECT_CB is the callback to use when a menu item is selected.
2454 HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
2455 CL_DATA points to the callback data to be used for this menu bar.
2457 This function calls itself to walk through the menu bar names. */
2459 static void
2460 xg_update_menubar (menubar, f, list, iter, pos, val,
2461 select_cb, deactivate_cb, highlight_cb, cl_data)
2462 GtkWidget *menubar;
2463 FRAME_PTR f;
2464 GList **list;
2465 GList *iter;
2466 int pos;
2467 widget_value *val;
2468 GCallback select_cb;
2469 GCallback deactivate_cb;
2470 GCallback highlight_cb;
2471 xg_menu_cb_data *cl_data;
2473 if (! iter && ! val)
2474 return;
2475 else if (iter && ! val)
2477 /* Item(s) have been removed. Remove all remaining items. */
2478 xg_destroy_widgets (iter);
2480 /* All updated. */
2481 val = 0;
2482 iter = 0;
2484 else if (! iter && val)
2486 /* Item(s) added. Add all new items in one call. */
2487 create_menus (val, f, select_cb, deactivate_cb, highlight_cb,
2488 0, 1, 0, menubar, cl_data, 0);
2490 /* All updated. */
2491 val = 0;
2492 iter = 0;
2494 /* Below this neither iter or val is NULL */
2495 else if (xg_item_label_same_p (GTK_MENU_ITEM (iter->data), val->name))
2497 /* This item is still the same, check next item. */
2498 val = val->next;
2499 iter = g_list_next (iter);
2500 ++pos;
2502 else /* This item is changed. */
2504 GtkMenuItem *witem = GTK_MENU_ITEM (iter->data);
2505 GtkMenuItem *witem2 = 0;
2506 int val_in_menubar = 0;
2507 int iter_in_new_menubar = 0;
2508 GList *iter2;
2509 widget_value *cur;
2511 /* See if the changed entry (val) is present later in the menu bar */
2512 for (iter2 = iter;
2513 iter2 && ! val_in_menubar;
2514 iter2 = g_list_next (iter2))
2516 witem2 = GTK_MENU_ITEM (iter2->data);
2517 val_in_menubar = xg_item_label_same_p (witem2, val->name);
2520 /* See if the current entry (iter) is present later in the
2521 specification for the new menu bar. */
2522 for (cur = val; cur && ! iter_in_new_menubar; cur = cur->next)
2523 iter_in_new_menubar = xg_item_label_same_p (witem, cur->name);
2525 if (val_in_menubar && ! iter_in_new_menubar)
2527 int nr = pos;
2529 /* This corresponds to:
2530 Current: A B C
2531 New: A C
2532 Remove B. */
2534 gtk_widget_ref (GTK_WIDGET (witem));
2535 gtk_container_remove (GTK_CONTAINER (menubar), GTK_WIDGET (witem));
2536 gtk_widget_destroy (GTK_WIDGET (witem));
2538 /* Must get new list since the old changed. */
2539 g_list_free (*list);
2540 *list = iter = gtk_container_get_children (GTK_CONTAINER (menubar));
2541 while (nr-- > 0) iter = g_list_next (iter);
2543 else if (! val_in_menubar && ! iter_in_new_menubar)
2545 /* This corresponds to:
2546 Current: A B C
2547 New: A X C
2548 Rename B to X. This might seem to be a strange thing to do,
2549 since if there is a menu under B it will be totally wrong for X.
2550 But consider editing a C file. Then there is a C-mode menu
2551 (corresponds to B above).
2552 If then doing C-x C-f the minibuf menu (X above) replaces the
2553 C-mode menu. When returning from the minibuffer, we get
2554 back the C-mode menu. Thus we do:
2555 Rename B to X (C-mode to minibuf menu)
2556 Rename X to B (minibuf to C-mode menu).
2557 If the X menu hasn't been invoked, the menu under B
2558 is up to date when leaving the minibuffer. */
2559 GtkLabel *wlabel = GTK_LABEL (gtk_bin_get_child (GTK_BIN (witem)));
2560 char *utf8_label = get_utf8_string (val->name);
2561 GtkWidget *submenu = gtk_menu_item_get_submenu (witem);
2563 gtk_label_set_text (wlabel, utf8_label);
2565 /* If this item has a submenu that has been detached, change
2566 the title in the WM decorations also. */
2567 if (submenu && gtk_menu_get_tearoff_state (GTK_MENU (submenu)))
2568 /* Set the title of the detached window. */
2569 gtk_menu_set_title (GTK_MENU (submenu), utf8_label);
2571 iter = g_list_next (iter);
2572 val = val->next;
2573 ++pos;
2575 else if (! val_in_menubar && iter_in_new_menubar)
2577 /* This corresponds to:
2578 Current: A B C
2579 New: A X B C
2580 Insert X. */
2582 int nr = pos;
2583 GList *group = 0;
2584 GtkWidget *w = xg_create_one_menuitem (val,
2586 select_cb,
2587 highlight_cb,
2588 cl_data,
2589 &group);
2591 /* Create a possibly empty submenu for menu bar items, since some
2592 themes don't highlight items correctly without it. */
2593 GtkWidget *submenu = create_menus (NULL, f,
2594 select_cb, deactivate_cb,
2595 highlight_cb,
2596 0, 0, 0, 0, cl_data, 0);
2597 gtk_widget_set_name (w, MENU_ITEM_NAME);
2598 gtk_menu_shell_insert (GTK_MENU_SHELL (menubar), w, pos);
2599 gtk_menu_item_set_submenu (GTK_MENU_ITEM (w), submenu);
2601 g_list_free (*list);
2602 *list = iter = gtk_container_get_children (GTK_CONTAINER (menubar));
2603 while (nr-- > 0) iter = g_list_next (iter);
2604 iter = g_list_next (iter);
2605 val = val->next;
2606 ++pos;
2608 else /* if (val_in_menubar && iter_in_new_menubar) */
2610 int nr = pos;
2611 /* This corresponds to:
2612 Current: A B C
2613 New: A C B
2614 Move C before B */
2616 gtk_widget_ref (GTK_WIDGET (witem2));
2617 gtk_container_remove (GTK_CONTAINER (menubar), GTK_WIDGET (witem2));
2618 gtk_menu_shell_insert (GTK_MENU_SHELL (menubar),
2619 GTK_WIDGET (witem2), pos);
2620 gtk_widget_unref (GTK_WIDGET (witem2));
2622 g_list_free (*list);
2623 *list = iter = gtk_container_get_children (GTK_CONTAINER (menubar));
2624 while (nr-- > 0) iter = g_list_next (iter);
2625 if (iter) iter = g_list_next (iter);
2626 val = val->next;
2627 ++pos;
2631 /* Update the rest of the menu bar. */
2632 xg_update_menubar (menubar, f, list, iter, pos, val,
2633 select_cb, deactivate_cb, highlight_cb, cl_data);
2636 /* Update the menu item W so it corresponds to VAL.
2637 SELECT_CB is the callback to use when a menu item is selected.
2638 HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
2639 CL_DATA is the data to set in the widget for menu invocation. */
2641 static void
2642 xg_update_menu_item (val, w, select_cb, highlight_cb, cl_data)
2643 widget_value *val;
2644 GtkWidget *w;
2645 GCallback select_cb;
2646 GCallback highlight_cb;
2647 xg_menu_cb_data *cl_data;
2649 GtkWidget *wchild;
2650 GtkLabel *wlbl = 0;
2651 GtkLabel *wkey = 0;
2652 char *utf8_label;
2653 char *utf8_key;
2654 const char *old_label = 0;
2655 const char *old_key = 0;
2656 xg_menu_item_cb_data *cb_data;
2658 wchild = gtk_bin_get_child (GTK_BIN (w));
2659 utf8_label = get_utf8_string (val->name);
2660 utf8_key = get_utf8_string (val->key);
2662 /* See if W is a menu item with a key. See make_menu_item above. */
2663 if (GTK_IS_HBOX (wchild))
2665 GList *list = gtk_container_get_children (GTK_CONTAINER (wchild));
2667 wlbl = GTK_LABEL (list->data);
2668 wkey = GTK_LABEL (list->next->data);
2669 g_list_free (list);
2671 if (! utf8_key)
2673 /* Remove the key and keep just the label. */
2674 gtk_widget_ref (GTK_WIDGET (wlbl));
2675 gtk_container_remove (GTK_CONTAINER (w), wchild);
2676 gtk_container_add (GTK_CONTAINER (w), GTK_WIDGET (wlbl));
2677 wkey = 0;
2681 else /* Just a label. */
2683 wlbl = GTK_LABEL (wchild);
2685 /* Check if there is now a key. */
2686 if (utf8_key)
2688 GtkWidget *wtoadd = make_widget_for_menu_item (utf8_label, utf8_key);
2689 GList *list = gtk_container_get_children (GTK_CONTAINER (wtoadd));
2691 wlbl = GTK_LABEL (list->data);
2692 wkey = GTK_LABEL (list->next->data);
2693 g_list_free (list);
2695 gtk_container_remove (GTK_CONTAINER (w), wchild);
2696 gtk_container_add (GTK_CONTAINER (w), wtoadd);
2701 if (wkey) old_key = gtk_label_get_label (wkey);
2702 if (wlbl) old_label = gtk_label_get_label (wlbl);
2704 if (wkey && utf8_key && (! old_key || strcmp (utf8_key, old_key) != 0))
2705 gtk_label_set_text (wkey, utf8_key);
2707 if (! old_label || strcmp (utf8_label, old_label) != 0)
2708 gtk_label_set_text (wlbl, utf8_label);
2710 if (utf8_key && utf8_key != val->key) g_free (utf8_key);
2711 if (utf8_label && utf8_label != val->name) g_free (utf8_label);
2713 if (! val->enabled && GTK_WIDGET_SENSITIVE (w))
2714 gtk_widget_set_sensitive (w, FALSE);
2715 else if (val->enabled && ! GTK_WIDGET_SENSITIVE (w))
2716 gtk_widget_set_sensitive (w, TRUE);
2718 cb_data = (xg_menu_item_cb_data*) g_object_get_data (G_OBJECT (w),
2719 XG_ITEM_DATA);
2720 if (cb_data)
2722 cb_data->call_data = val->call_data;
2723 cb_data->help = val->help;
2724 cb_data->cl_data = cl_data;
2726 /* We assume the callback functions don't change. */
2727 if (val->call_data && ! val->contents)
2729 /* This item shall have a select callback. */
2730 if (! cb_data->select_id)
2731 cb_data->select_id
2732 = g_signal_connect (G_OBJECT (w), "activate",
2733 select_cb, cb_data);
2735 else if (cb_data->select_id)
2737 g_signal_handler_disconnect (w, cb_data->select_id);
2738 cb_data->select_id = 0;
2743 /* Update the toggle menu item W so it corresponds to VAL. */
2745 static void
2746 xg_update_toggle_item (val, w)
2747 widget_value *val;
2748 GtkWidget *w;
2750 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w), val->selected);
2753 /* Update the radio menu item W so it corresponds to VAL. */
2755 static void
2756 xg_update_radio_item (val, w)
2757 widget_value *val;
2758 GtkWidget *w;
2760 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w), val->selected);
2763 /* Update the sub menu SUBMENU and all its children so it corresponds to VAL.
2764 SUBMENU may be NULL, in that case a new menu is created.
2765 F is the frame the menu bar belongs to.
2766 VAL describes the contents of the menu bar.
2767 SELECT_CB is the callback to use when a menu item is selected.
2768 DEACTIVATE_CB is the callback to use when a sub menu is not shown anymore.
2769 HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
2770 CL_DATA is the call back data to use for any newly created items.
2772 Returns the updated submenu widget, that is SUBMENU unless SUBMENU
2773 was NULL. */
2775 static GtkWidget *
2776 xg_update_submenu (submenu, f, val,
2777 select_cb, deactivate_cb, highlight_cb, cl_data)
2778 GtkWidget *submenu;
2779 FRAME_PTR f;
2780 widget_value *val;
2781 GCallback select_cb;
2782 GCallback deactivate_cb;
2783 GCallback highlight_cb;
2784 xg_menu_cb_data *cl_data;
2786 GtkWidget *newsub = submenu;
2787 GList *list = 0;
2788 GList *iter;
2789 widget_value *cur;
2790 int has_tearoff_p = 0;
2791 GList *first_radio = 0;
2793 if (submenu)
2794 list = gtk_container_get_children (GTK_CONTAINER (submenu));
2796 for (cur = val, iter = list;
2797 cur && iter;
2798 iter = g_list_next (iter), cur = cur->next)
2800 GtkWidget *w = GTK_WIDGET (iter->data);
2802 /* Skip tearoff items, they have no counterpart in val. */
2803 if (GTK_IS_TEAROFF_MENU_ITEM (w))
2805 has_tearoff_p = 1;
2806 iter = g_list_next (iter);
2807 if (iter) w = GTK_WIDGET (iter->data);
2808 else break;
2811 /* Remember first radio button in a group. If we get a mismatch in
2812 a radio group we must rebuild the whole group so that the connections
2813 in GTK becomes correct. */
2814 if (cur->button_type == BUTTON_TYPE_RADIO && ! first_radio)
2815 first_radio = iter;
2816 else if (cur->button_type != BUTTON_TYPE_RADIO
2817 && ! GTK_IS_RADIO_MENU_ITEM (w))
2818 first_radio = 0;
2820 if (GTK_IS_SEPARATOR_MENU_ITEM (w))
2822 if (! xg_separator_p (cur->name))
2823 break;
2825 else if (GTK_IS_CHECK_MENU_ITEM (w))
2827 if (cur->button_type != BUTTON_TYPE_TOGGLE)
2828 break;
2829 xg_update_toggle_item (cur, w);
2830 xg_update_menu_item (cur, w, select_cb, highlight_cb, cl_data);
2832 else if (GTK_IS_RADIO_MENU_ITEM (w))
2834 if (cur->button_type != BUTTON_TYPE_RADIO)
2835 break;
2836 xg_update_radio_item (cur, w);
2837 xg_update_menu_item (cur, w, select_cb, highlight_cb, cl_data);
2839 else if (GTK_IS_MENU_ITEM (w))
2841 GtkMenuItem *witem = GTK_MENU_ITEM (w);
2842 GtkWidget *sub;
2844 if (cur->button_type != BUTTON_TYPE_NONE ||
2845 xg_separator_p (cur->name))
2846 break;
2848 xg_update_menu_item (cur, w, select_cb, highlight_cb, cl_data);
2850 sub = gtk_menu_item_get_submenu (witem);
2851 if (sub && ! cur->contents)
2853 /* Not a submenu anymore. */
2854 gtk_widget_ref (sub);
2855 gtk_menu_item_remove_submenu (witem);
2856 gtk_widget_destroy (sub);
2858 else if (cur->contents)
2860 GtkWidget *nsub;
2862 nsub = xg_update_submenu (sub, f, cur->contents,
2863 select_cb, deactivate_cb,
2864 highlight_cb, cl_data);
2866 /* If this item just became a submenu, we must set it. */
2867 if (nsub != sub)
2868 gtk_menu_item_set_submenu (witem, nsub);
2871 else
2873 /* Structural difference. Remove everything from here and down
2874 in SUBMENU. */
2875 break;
2879 /* Remove widgets from first structual change. */
2880 if (iter)
2882 /* If we are adding new menu items below, we must remove from
2883 first radio button so that radio groups become correct. */
2884 if (cur && first_radio) xg_destroy_widgets (first_radio);
2885 else xg_destroy_widgets (iter);
2888 if (cur)
2890 /* More items added. Create them. */
2891 newsub = create_menus (cur,
2893 select_cb,
2894 deactivate_cb,
2895 highlight_cb,
2898 ! has_tearoff_p,
2899 submenu,
2900 cl_data,
2904 if (list) g_list_free (list);
2906 return newsub;
2909 /* Update the MENUBAR.
2910 F is the frame the menu bar belongs to.
2911 VAL describes the contents of the menu bar.
2912 If DEEP_P is non-zero, rebuild all but the top level menu names in
2913 the MENUBAR. If DEEP_P is zero, just rebuild the names in the menubar.
2914 SELECT_CB is the callback to use when a menu item is selected.
2915 DEACTIVATE_CB is the callback to use when a sub menu is not shown anymore.
2916 HIGHLIGHT_CB is the callback to call when entering/leaving menu items. */
2918 void
2919 xg_modify_menubar_widgets (menubar, f, val, deep_p,
2920 select_cb, deactivate_cb, highlight_cb)
2921 GtkWidget *menubar;
2922 FRAME_PTR f;
2923 widget_value *val;
2924 int deep_p;
2925 GCallback select_cb;
2926 GCallback deactivate_cb;
2927 GCallback highlight_cb;
2929 xg_menu_cb_data *cl_data;
2930 GList *list = gtk_container_get_children (GTK_CONTAINER (menubar));
2932 if (! list) return;
2934 cl_data = (xg_menu_cb_data*) g_object_get_data (G_OBJECT (menubar),
2935 XG_FRAME_DATA);
2937 xg_update_menubar (menubar, f, &list, list, 0, val->contents,
2938 select_cb, deactivate_cb, highlight_cb, cl_data);
2940 if (deep_p)
2942 widget_value *cur;
2944 /* Update all sub menus.
2945 We must keep the submenus (GTK menu item widgets) since the
2946 X Window in the XEvent that activates the menu are those widgets. */
2948 /* Update cl_data, menu_item things in F may have changed. */
2949 update_cl_data (cl_data, f, highlight_cb);
2951 for (cur = val->contents; cur; cur = cur->next)
2953 GList *iter;
2954 GtkWidget *sub = 0;
2955 GtkWidget *newsub;
2956 GtkMenuItem *witem;
2958 /* Find sub menu that corresponds to val and update it. */
2959 for (iter = list ; iter; iter = g_list_next (iter))
2961 witem = GTK_MENU_ITEM (iter->data);
2962 if (xg_item_label_same_p (witem, cur->name))
2964 sub = gtk_menu_item_get_submenu (witem);
2965 break;
2969 newsub = xg_update_submenu (sub,
2971 cur->contents,
2972 select_cb,
2973 deactivate_cb,
2974 highlight_cb,
2975 cl_data);
2976 /* sub may still be NULL. If we just updated non deep and added
2977 a new menu bar item, it has no sub menu yet. So we set the
2978 newly created sub menu under witem. */
2979 if (newsub != sub)
2981 xg_set_screen (newsub, f);
2982 gtk_menu_item_set_submenu (witem, newsub);
2987 g_list_free (list);
2988 gtk_widget_show_all (menubar);
2991 /* Recompute all the widgets of frame F, when the menu bar has been
2992 changed. Value is non-zero if widgets were updated. */
2995 xg_update_frame_menubar (f)
2996 FRAME_PTR f;
2998 struct x_output *x = f->output_data.x;
2999 GtkRequisition req;
3001 if (!x->menubar_widget || GTK_WIDGET_MAPPED (x->menubar_widget))
3002 return 0;
3004 if (x->menubar_widget && gtk_widget_get_parent (x->menubar_widget))
3005 return 0; /* Already done this, happens for frames created invisible. */
3007 BLOCK_INPUT;
3009 gtk_box_pack_start (GTK_BOX (x->vbox_widget), x->menubar_widget,
3010 FALSE, FALSE, 0);
3011 gtk_box_reorder_child (GTK_BOX (x->vbox_widget), x->menubar_widget, 0);
3013 gtk_widget_show_all (x->menubar_widget);
3014 gtk_widget_size_request (x->menubar_widget, &req);
3015 FRAME_MENUBAR_HEIGHT (f) = req.height;
3016 xg_height_changed (f);
3017 UNBLOCK_INPUT;
3019 return 1;
3022 /* Get rid of the menu bar of frame F, and free its storage.
3023 This is used when deleting a frame, and when turning off the menu bar. */
3025 void
3026 free_frame_menubar (f)
3027 FRAME_PTR f;
3029 struct x_output *x = f->output_data.x;
3031 if (x->menubar_widget)
3033 BLOCK_INPUT;
3035 gtk_container_remove (GTK_CONTAINER (x->vbox_widget), x->menubar_widget);
3036 /* The menubar and its children shall be deleted when removed from
3037 the container. */
3038 x->menubar_widget = 0;
3039 FRAME_MENUBAR_HEIGHT (f) = 0;
3040 xg_height_changed (f);
3041 UNBLOCK_INPUT;
3047 /***********************************************************************
3048 Scroll bar functions
3049 ***********************************************************************/
3052 /* Setting scroll bar values invokes the callback. Use this variable
3053 to indicate that callback should do nothing. */
3055 int xg_ignore_gtk_scrollbar;
3057 /* Xlib's `Window' fits in 32 bits. But we want to store pointers, and they
3058 may be larger than 32 bits. Keep a mapping from integer index to widget
3059 pointers to get around the 32 bit limitation. */
3061 static struct
3063 GtkWidget **widgets;
3064 int max_size;
3065 int used;
3066 } id_to_widget;
3068 /* Grow this much every time we need to allocate more */
3070 #define ID_TO_WIDGET_INCR 32
3072 /* Store the widget pointer W in id_to_widget and return the integer index. */
3074 static int
3075 xg_store_widget_in_map (w)
3076 GtkWidget *w;
3078 int i;
3080 if (id_to_widget.max_size == id_to_widget.used)
3082 int new_size = id_to_widget.max_size + ID_TO_WIDGET_INCR;
3084 id_to_widget.widgets = xrealloc (id_to_widget.widgets,
3085 sizeof (GtkWidget *)*new_size);
3087 for (i = id_to_widget.max_size; i < new_size; ++i)
3088 id_to_widget.widgets[i] = 0;
3089 id_to_widget.max_size = new_size;
3092 /* Just loop over the array and find a free place. After all,
3093 how many scroll bars are we creating? Should be a small number.
3094 The check above guarantees we will find a free place. */
3095 for (i = 0; i < id_to_widget.max_size; ++i)
3097 if (! id_to_widget.widgets[i])
3099 id_to_widget.widgets[i] = w;
3100 ++id_to_widget.used;
3102 return i;
3106 /* Should never end up here */
3107 abort ();
3110 /* Remove pointer at IDX from id_to_widget.
3111 Called when scroll bar is destroyed. */
3113 static void
3114 xg_remove_widget_from_map (idx)
3115 int idx;
3117 if (idx < id_to_widget.max_size && id_to_widget.widgets[idx] != 0)
3119 id_to_widget.widgets[idx] = 0;
3120 --id_to_widget.used;
3124 /* Get the widget pointer at IDX from id_to_widget. */
3126 static GtkWidget *
3127 xg_get_widget_from_map (idx)
3128 int idx;
3130 if (idx < id_to_widget.max_size && id_to_widget.widgets[idx] != 0)
3131 return id_to_widget.widgets[idx];
3133 return 0;
3136 /* Return the scrollbar id for X Window WID on display DPY.
3137 Return -1 if WID not in id_to_widget. */
3140 xg_get_scroll_id_for_window (dpy, wid)
3141 Display *dpy;
3142 Window wid;
3144 int idx;
3145 GtkWidget *w;
3147 w = xg_win_to_widget (dpy, wid);
3149 if (w)
3151 for (idx = 0; idx < id_to_widget.max_size; ++idx)
3152 if (id_to_widget.widgets[idx] == w)
3153 return idx;
3156 return -1;
3159 /* Callback invoked when scroll bar WIDGET is destroyed.
3160 DATA is the index into id_to_widget for WIDGET.
3161 We free pointer to last scroll bar values here and remove the index. */
3163 static void
3164 xg_gtk_scroll_destroy (widget, data)
3165 GtkWidget *widget;
3166 gpointer data;
3168 gpointer p;
3169 int id = (int) (EMACS_INT) data; /* The EMACS_INT cast avoids a warning. */
3171 p = g_object_get_data (G_OBJECT (widget), XG_LAST_SB_DATA);
3172 xfree (p);
3173 xg_remove_widget_from_map (id);
3176 /* Callback for button press/release events. Used to start timer so that
3177 the scroll bar repetition timer in GTK gets handled.
3178 Also, sets bar->dragging to Qnil when dragging (button release) is done.
3179 WIDGET is the scroll bar widget the event is for (not used).
3180 EVENT contains the event.
3181 USER_DATA points to the struct scrollbar structure.
3183 Returns FALSE to tell GTK that it shall continue propagate the event
3184 to widgets. */
3186 static gboolean
3187 scroll_bar_button_cb (widget, event, user_data)
3188 GtkWidget *widget;
3189 GdkEventButton *event;
3190 gpointer user_data;
3192 if (event->type == GDK_BUTTON_PRESS && ! xg_timer)
3193 xg_start_timer ();
3194 else if (event->type == GDK_BUTTON_RELEASE)
3196 struct scroll_bar *bar = (struct scroll_bar *) user_data;
3197 if (xg_timer) xg_stop_timer ();
3198 bar->dragging = Qnil;
3201 return FALSE;
3204 /* Create a scroll bar widget for frame F. Store the scroll bar
3205 in BAR.
3206 SCROLL_CALLBACK is the callback to invoke when the value of the
3207 bar changes.
3208 SCROLL_BAR_NAME is the name we use for the scroll bar. Can be used
3209 to set resources for the widget. */
3211 void
3212 xg_create_scroll_bar (f, bar, scroll_callback, scroll_bar_name)
3213 FRAME_PTR f;
3214 struct scroll_bar *bar;
3215 GCallback scroll_callback;
3216 char *scroll_bar_name;
3218 GtkWidget *wscroll;
3219 GtkWidget *webox;
3220 GtkObject *vadj;
3221 int scroll_id;
3223 /* Page, step increment values are not so important here, they
3224 will be corrected in x_set_toolkit_scroll_bar_thumb. */
3225 vadj = gtk_adjustment_new (XG_SB_MIN, XG_SB_MIN, XG_SB_MAX,
3226 0.1, 0.1, 0.1);
3228 wscroll = gtk_vscrollbar_new (GTK_ADJUSTMENT (vadj));
3229 webox = gtk_event_box_new ();
3230 gtk_widget_set_name (wscroll, scroll_bar_name);
3231 gtk_range_set_update_policy (GTK_RANGE (wscroll), GTK_UPDATE_CONTINUOUS);
3233 scroll_id = xg_store_widget_in_map (wscroll);
3235 g_signal_connect (G_OBJECT (wscroll),
3236 "value-changed",
3237 scroll_callback,
3238 (gpointer) bar);
3239 /* The EMACS_INT cast avoids a warning. */
3240 g_signal_connect (G_OBJECT (wscroll),
3241 "destroy",
3242 G_CALLBACK (xg_gtk_scroll_destroy),
3243 (gpointer) (EMACS_INT) scroll_id);
3245 /* Connect to button press and button release to detect if any scroll bar
3246 has the pointer. */
3247 g_signal_connect (G_OBJECT (wscroll),
3248 "button-press-event",
3249 G_CALLBACK (scroll_bar_button_cb),
3250 (gpointer) bar);
3251 g_signal_connect (G_OBJECT (wscroll),
3252 "button-release-event",
3253 G_CALLBACK (scroll_bar_button_cb),
3254 (gpointer) bar);
3256 /* The scroll bar widget does not draw on a window of its own. Instead
3257 it draws on the parent window, in this case the edit widget. So
3258 whenever the edit widget is cleared, the scroll bar needs to redraw
3259 also, which causes flicker. Put an event box between the edit widget
3260 and the scroll bar, so the scroll bar instead draws itself on the
3261 event box window. */
3262 gtk_fixed_put (GTK_FIXED (f->output_data.x->edit_widget), webox, -1, -1);
3263 gtk_container_add (GTK_CONTAINER (webox), wscroll);
3266 /* Set the cursor to an arrow. */
3267 xg_set_cursor (webox, FRAME_X_DISPLAY_INFO (f)->xg_cursor);
3269 bar->x_window = scroll_id;
3272 /* Make the scroll bar represented by SCROLLBAR_ID visible. */
3274 void
3275 xg_show_scroll_bar (scrollbar_id)
3276 int scrollbar_id;
3278 GtkWidget *w = xg_get_widget_from_map (scrollbar_id);
3279 if (w)
3280 gtk_widget_show_all (gtk_widget_get_parent (w));
3283 /* Remove the scroll bar represented by SCROLLBAR_ID from the frame F. */
3285 void
3286 xg_remove_scroll_bar (f, scrollbar_id)
3287 FRAME_PTR f;
3288 int scrollbar_id;
3290 GtkWidget *w = xg_get_widget_from_map (scrollbar_id);
3291 if (w)
3293 GtkWidget *wparent = gtk_widget_get_parent (w);
3294 gtk_widget_destroy (w);
3295 gtk_widget_destroy (wparent);
3296 SET_FRAME_GARBAGED (f);
3300 /* Update the position of the vertical scroll bar represented by SCROLLBAR_ID
3301 in frame F.
3302 TOP/LEFT are the new pixel positions where the bar shall appear.
3303 WIDTH, HEIGHT is the size in pixels the bar shall have. */
3305 void
3306 xg_update_scrollbar_pos (f, scrollbar_id, top, left, width, height)
3307 FRAME_PTR f;
3308 int scrollbar_id;
3309 int top;
3310 int left;
3311 int width;
3312 int height;
3315 GtkWidget *wscroll = xg_get_widget_from_map (scrollbar_id);
3317 if (wscroll)
3319 GtkWidget *wfixed = f->output_data.x->edit_widget;
3320 GtkWidget *wparent = gtk_widget_get_parent (wscroll);
3322 /* Move and resize to new values. */
3323 gtk_fixed_move (GTK_FIXED (wfixed), wparent, left, top);
3324 gtk_widget_set_size_request (wscroll, width, height);
3325 gtk_widget_queue_draw (wparent);
3326 gdk_window_process_all_updates ();
3327 /* GTK does not redraw until the main loop is entered again, but
3328 if there are no X events pending we will not enter it. So we sync
3329 here to get some events. */
3330 x_sync (f);
3331 SET_FRAME_GARBAGED (f);
3332 cancel_mouse_face (f);
3336 /* Set the thumb size and position of scroll bar BAR. We are currently
3337 displaying PORTION out of a whole WHOLE, and our position POSITION. */
3339 void
3340 xg_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
3341 struct scroll_bar *bar;
3342 int portion, position, whole;
3344 GtkWidget *wscroll = xg_get_widget_from_map (bar->x_window);
3346 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
3348 if (wscroll && NILP (bar->dragging))
3350 GtkAdjustment *adj;
3351 gdouble shown;
3352 gdouble top;
3353 int size, value;
3354 int new_step;
3355 int changed = 0;
3357 adj = gtk_range_get_adjustment (GTK_RANGE (wscroll));
3359 /* We do the same as for MOTIF in xterm.c, assume 30 chars per line
3360 rather than the real portion value. This makes the thumb less likely
3361 to resize and that looks better. */
3362 portion = WINDOW_TOTAL_LINES (XWINDOW (bar->window)) * 30;
3363 /* When the thumb is at the bottom, position == whole.
3364 So we need to increase `whole' to make space for the thumb. */
3365 whole += portion;
3367 if (whole <= 0)
3368 top = 0, shown = 1;
3369 else
3371 top = (gdouble) position / whole;
3372 shown = (gdouble) portion / whole;
3375 size = shown * XG_SB_RANGE;
3376 size = min (size, XG_SB_RANGE);
3377 size = max (size, 1);
3379 value = top * XG_SB_RANGE;
3380 value = min (value, XG_SB_MAX - size);
3381 value = max (value, XG_SB_MIN);
3383 /* Assume all lines are of equal size. */
3384 new_step = size / max (1, FRAME_LINES (f));
3386 if ((int) adj->page_size != size
3387 || (int) adj->step_increment != new_step)
3389 adj->page_size = size;
3390 adj->step_increment = new_step;
3391 /* Assume a page increment is about 95% of the page size */
3392 adj->page_increment = (int) (0.95*adj->page_size);
3393 changed = 1;
3396 if (changed || (int) gtk_range_get_value (GTK_RANGE (wscroll)) != value)
3398 GtkWidget *wfixed = f->output_data.x->edit_widget;
3400 BLOCK_INPUT;
3402 /* gtk_range_set_value invokes the callback. Set
3403 ignore_gtk_scrollbar to make the callback do nothing */
3404 xg_ignore_gtk_scrollbar = 1;
3406 if ((int) gtk_range_get_value (GTK_RANGE (wscroll)) != value)
3407 gtk_range_set_value (GTK_RANGE (wscroll), (gdouble)value);
3408 else if (changed)
3409 gtk_adjustment_changed (adj);
3411 xg_ignore_gtk_scrollbar = 0;
3413 UNBLOCK_INPUT;
3418 /* Return non-zero if EVENT is for a scroll bar in frame F.
3419 When the same X window is used for several Gtk+ widgets, we cannot
3420 say for sure based on the X window alone if an event is for the
3421 frame. This function does additional checks.
3423 Return non-zero if the event is for a scroll bar, zero otherwise. */
3426 xg_event_is_for_scrollbar (f, event)
3427 FRAME_PTR f;
3428 XEvent *event;
3430 int retval = 0;
3432 if (f && event->type == ButtonPress)
3434 /* Check if press occurred outside the edit widget. */
3435 GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (FRAME_X_DISPLAY (f));
3436 retval = gdk_display_get_window_at_pointer (gdpy, NULL, NULL)
3437 != f->output_data.x->edit_widget->window;
3439 else if (f && (event->type != ButtonRelease || event->type != MotionNotify))
3441 /* If we are releasing or moving the scroll bar, it has the grab. */
3442 retval = gtk_grab_get_current () != 0
3443 && gtk_grab_get_current () != f->output_data.x->edit_widget;
3446 return retval;
3451 /***********************************************************************
3452 Tool bar functions
3453 ***********************************************************************/
3454 /* The key for the data we put in the GtkImage widgets. The data is
3455 the image used by Emacs. We use this to see if we need to update
3456 the GtkImage with a new image. */
3457 #define XG_TOOL_BAR_IMAGE_DATA "emacs-tool-bar-image"
3459 /* The key for storing the latest modifiers so the activate callback can
3460 get them. */
3461 #define XG_TOOL_BAR_LAST_MODIFIER "emacs-tool-bar-modifier"
3463 /* The key for storing the button widget in its proxy menu item. */
3464 #define XG_TOOL_BAR_PROXY_BUTTON "emacs-tool-bar-proxy-button"
3466 /* The key for the data we put in the GtkImage widgets. The data is
3467 the stock name used by Emacs. We use this to see if we need to update
3468 the GtkImage with a new image. */
3469 #define XG_TOOL_BAR_STOCK_NAME "emacs-tool-bar-stock-name"
3471 /* As above, but this is used for named theme widgets, as opposed to
3472 stock items. */
3473 #define XG_TOOL_BAR_ICON_NAME "emacs-tool-bar-icon-name"
3475 /* Callback function invoked when a tool bar item is pressed.
3476 W is the button widget in the tool bar that got pressed,
3477 CLIENT_DATA is an integer that is the index of the button in the
3478 tool bar. 0 is the first button. */
3480 static gboolean
3481 xg_tool_bar_button_cb (widget, event, user_data)
3482 GtkWidget *widget;
3483 GdkEventButton *event;
3484 gpointer user_data;
3486 /* Casts to avoid warnings when gpointer is 64 bits and int is 32 bits */
3487 gpointer ptr = (gpointer) (EMACS_INT) event->state;
3488 g_object_set_data (G_OBJECT (widget), XG_TOOL_BAR_LAST_MODIFIER, ptr);
3489 return FALSE;
3493 /* Callback function invoked when a tool bar item is pressed.
3494 W is the button widget in the tool bar that got pressed,
3495 CLIENT_DATA is an integer that is the index of the button in the
3496 tool bar. 0 is the first button. */
3498 static void
3499 xg_tool_bar_callback (w, client_data)
3500 GtkWidget *w;
3501 gpointer client_data;
3503 /* The EMACS_INT cast avoids a warning. */
3504 int idx = (int) (EMACS_INT) client_data;
3505 int mod = (int) (EMACS_INT) g_object_get_data (G_OBJECT (w),
3506 XG_TOOL_BAR_LAST_MODIFIER);
3508 FRAME_PTR f = (FRAME_PTR) g_object_get_data (G_OBJECT (w), XG_FRAME_DATA);
3509 Lisp_Object key, frame;
3510 struct input_event event;
3511 EVENT_INIT (event);
3513 if (! f || ! f->n_tool_bar_items || NILP (f->tool_bar_items))
3514 return;
3516 idx *= TOOL_BAR_ITEM_NSLOTS;
3518 key = AREF (f->tool_bar_items, idx + TOOL_BAR_ITEM_KEY);
3519 XSETFRAME (frame, f);
3521 /* We generate two events here. The first one is to set the prefix
3522 to `(tool_bar)', see keyboard.c. */
3523 event.kind = TOOL_BAR_EVENT;
3524 event.frame_or_window = frame;
3525 event.arg = frame;
3526 kbd_buffer_store_event (&event);
3528 event.kind = TOOL_BAR_EVENT;
3529 event.frame_or_window = frame;
3530 event.arg = key;
3531 /* Convert between the modifier bits GDK uses and the modifier bits
3532 Emacs uses. This assumes GDK and X masks are the same, which they are when
3533 this is written. */
3534 event.modifiers = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f), mod);
3535 kbd_buffer_store_event (&event);
3537 /* Return focus to the frame after we have clicked on a detached
3538 tool bar button. */
3539 Fx_focus_frame (frame);
3542 /* Callback function invoked when a tool bar item is pressed in a detached
3543 tool bar or the overflow drop down menu.
3544 We just call xg_tool_bar_callback.
3545 W is the menu item widget that got pressed,
3546 CLIENT_DATA is an integer that is the index of the button in the
3547 tool bar. 0 is the first button. */
3549 static void
3550 xg_tool_bar_proxy_callback (w, client_data)
3551 GtkWidget *w;
3552 gpointer client_data;
3554 GtkWidget *wbutton = GTK_WIDGET (g_object_get_data (G_OBJECT (w),
3555 XG_TOOL_BAR_PROXY_BUTTON));
3556 xg_tool_bar_callback (wbutton, client_data);
3560 static gboolean
3561 xg_tool_bar_help_callback P_ ((GtkWidget *w,
3562 GdkEventCrossing *event,
3563 gpointer client_data));
3565 /* This callback is called when a help is to be shown for an item in
3566 the detached tool bar when the detached tool bar it is not expanded. */
3568 static gboolean
3569 xg_tool_bar_proxy_help_callback (w, event, client_data)
3570 GtkWidget *w;
3571 GdkEventCrossing *event;
3572 gpointer client_data;
3574 GtkWidget *wbutton = GTK_WIDGET (g_object_get_data (G_OBJECT (w),
3575 XG_TOOL_BAR_PROXY_BUTTON));
3577 xg_tool_bar_help_callback (wbutton, event, client_data);
3581 /* This callback is called when a tool item should create a proxy item,
3582 such as for the overflow menu. Also called when the tool bar is detached.
3583 If we don't create a proxy menu item, the detached tool bar will be
3584 blank. */
3586 static gboolean
3587 xg_tool_bar_menu_proxy (toolitem, user_data)
3588 GtkToolItem *toolitem;
3589 gpointer user_data;
3591 GtkWidget *weventbox = gtk_bin_get_child (GTK_BIN (toolitem));
3592 GtkButton *wbutton = GTK_BUTTON (gtk_bin_get_child (GTK_BIN (weventbox)));
3593 GtkWidget *wmenuitem = gtk_image_menu_item_new_with_label ("");
3594 GtkWidget *wmenuimage;
3596 if (gtk_button_get_use_stock (wbutton))
3597 wmenuimage = gtk_image_new_from_stock (gtk_button_get_label (wbutton),
3598 GTK_ICON_SIZE_MENU);
3599 else
3601 GtkImage *wimage = GTK_IMAGE (gtk_bin_get_child (GTK_BIN (wbutton)));
3602 GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (wbutton));
3603 GtkImageType store_type = gtk_image_get_storage_type (wimage);
3605 if (store_type == GTK_IMAGE_STOCK)
3607 gchar *stock_id;
3608 gtk_image_get_stock (wimage, &stock_id, NULL);
3609 wmenuimage = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_MENU);
3611 else if (store_type == GTK_IMAGE_ICON_SET)
3613 GtkIconSet *icon_set;
3614 gtk_image_get_icon_set (wimage, &icon_set, NULL);
3615 wmenuimage = gtk_image_new_from_icon_set (icon_set,
3616 GTK_ICON_SIZE_MENU);
3618 else if (store_type == GTK_IMAGE_PIXBUF)
3620 gint width, height;
3622 if (settings &&
3623 gtk_icon_size_lookup_for_settings (settings, GTK_ICON_SIZE_MENU,
3624 &width, &height))
3626 GdkPixbuf *src_pixbuf, *dest_pixbuf;
3628 src_pixbuf = gtk_image_get_pixbuf (wimage);
3629 dest_pixbuf = gdk_pixbuf_scale_simple (src_pixbuf, width, height,
3630 GDK_INTERP_BILINEAR);
3632 wmenuimage = gtk_image_new_from_pixbuf (dest_pixbuf);
3634 else
3636 fprintf (stderr, "internal error: GTK_IMAGE_PIXBUF failed\n");
3637 abort ();
3640 else if (store_type == GTK_IMAGE_ICON_NAME)
3642 const gchar *icon_name;
3643 GtkIconSize icon_size;
3645 gtk_image_get_icon_name (wimage, &icon_name, &icon_size);
3646 wmenuimage = gtk_image_new_from_icon_name (icon_name,
3647 GTK_ICON_SIZE_MENU);
3649 else
3651 fprintf (stderr, "internal error: store_type is %d\n", store_type);
3652 abort ();
3655 if (wmenuimage)
3656 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (wmenuitem), wmenuimage);
3658 g_signal_connect (G_OBJECT (wmenuitem),
3659 "activate",
3660 G_CALLBACK (xg_tool_bar_proxy_callback),
3661 user_data);
3664 g_object_set_data (G_OBJECT (wmenuitem), XG_TOOL_BAR_PROXY_BUTTON,
3665 (gpointer) wbutton);
3666 gtk_tool_item_set_proxy_menu_item (toolitem, "Emacs toolbar item", wmenuitem);
3667 gtk_widget_set_sensitive (wmenuitem, GTK_WIDGET_SENSITIVE (wbutton));
3669 /* Use enter/leave notify to show help. We use the events
3670 rather than the GtkButton specific signals "enter" and
3671 "leave", so we can have only one callback. The event
3672 will tell us what kind of event it is. */
3673 g_signal_connect (G_OBJECT (wmenuitem),
3674 "enter-notify-event",
3675 G_CALLBACK (xg_tool_bar_proxy_help_callback),
3676 user_data);
3677 g_signal_connect (G_OBJECT (wmenuitem),
3678 "leave-notify-event",
3679 G_CALLBACK (xg_tool_bar_proxy_help_callback),
3680 user_data);
3682 return TRUE;
3685 /* This callback is called when a tool bar is detached. We must set
3686 the height of the tool bar to zero when this happens so frame sizes
3687 are correctly calculated.
3688 WBOX is the handle box widget that enables detach/attach of the tool bar.
3689 W is the tool bar widget.
3690 CLIENT_DATA is a pointer to the frame the tool bar belongs to. */
3692 static void
3693 xg_tool_bar_detach_callback (wbox, w, client_data)
3694 GtkHandleBox *wbox;
3695 GtkWidget *w;
3696 gpointer client_data;
3698 FRAME_PTR f = (FRAME_PTR) client_data;
3699 extern int x_gtk_whole_detached_tool_bar;
3701 g_object_set (G_OBJECT (w), "show-arrow", !x_gtk_whole_detached_tool_bar,
3702 NULL);
3704 if (f)
3706 FRAME_X_OUTPUT (f)->toolbar_detached = 1;
3708 /* When detaching a tool bar, not everything dissapear. There are
3709 a few pixels left that are used to drop the tool bar back into
3710 place. */
3711 FRAME_TOOLBAR_HEIGHT (f) = 4;
3712 xg_height_changed (f);
3716 /* This callback is called when a tool bar is reattached. We must set
3717 the height of the tool bar when this happens so frame sizes
3718 are correctly calculated.
3719 WBOX is the handle box widget that enables detach/attach of the tool bar.
3720 W is the tool bar widget.
3721 CLIENT_DATA is a pointer to the frame the tool bar belongs to. */
3723 static void
3724 xg_tool_bar_attach_callback (wbox, w, client_data)
3725 GtkHandleBox *wbox;
3726 GtkWidget *w;
3727 gpointer client_data;
3729 FRAME_PTR f = (FRAME_PTR) client_data;
3730 g_object_set (G_OBJECT (w), "show-arrow", TRUE, NULL);
3732 if (f)
3734 GtkRequisition req;
3736 FRAME_X_OUTPUT (f)->toolbar_detached = 0;
3738 gtk_widget_size_request (w, &req);
3739 FRAME_TOOLBAR_HEIGHT (f) = req.height;
3740 xg_height_changed (f);
3744 /* This callback is called when the mouse enters or leaves a tool bar item.
3745 It is used for displaying and hiding the help text.
3746 W is the tool bar item, a button.
3747 EVENT is either an enter event or leave event.
3748 CLIENT_DATA is an integer that is the index of the button in the
3749 tool bar. 0 is the first button.
3751 Returns FALSE to tell GTK to keep processing this event. */
3753 static gboolean
3754 xg_tool_bar_help_callback (w, event, client_data)
3755 GtkWidget *w;
3756 GdkEventCrossing *event;
3757 gpointer client_data;
3759 /* The EMACS_INT cast avoids a warning. */
3760 int idx = (int) (EMACS_INT) client_data;
3761 FRAME_PTR f = (FRAME_PTR) g_object_get_data (G_OBJECT (w), XG_FRAME_DATA);
3762 Lisp_Object help, frame;
3764 if (! f || ! f->n_tool_bar_items || NILP (f->tool_bar_items))
3765 return FALSE;
3767 if (event->type == GDK_ENTER_NOTIFY)
3769 idx *= TOOL_BAR_ITEM_NSLOTS;
3770 help = AREF (f->tool_bar_items, idx + TOOL_BAR_ITEM_HELP);
3772 if (NILP (help))
3773 help = AREF (f->tool_bar_items, idx + TOOL_BAR_ITEM_CAPTION);
3775 else
3776 help = Qnil;
3778 XSETFRAME (frame, f);
3779 kbd_buffer_store_help_event (frame, help);
3781 return FALSE;
3785 /* This callback is called when a tool bar item shall be redrawn.
3786 It modifies the expose event so that the GtkImage widget redraws the
3787 whole image. This to overcome a bug that makes GtkImage draw the image
3788 in the wrong place when it tries to redraw just a part of the image.
3789 W is the GtkImage to be redrawn.
3790 EVENT is the expose event for W.
3791 CLIENT_DATA is unused.
3793 Returns FALSE to tell GTK to keep processing this event. */
3795 static gboolean
3796 xg_tool_bar_item_expose_callback (w, event, client_data)
3797 GtkWidget *w;
3798 GdkEventExpose *event;
3799 gpointer client_data;
3801 gint width, height;
3803 gdk_drawable_get_size (event->window, &width, &height);
3805 event->area.x -= width > event->area.width ? width-event->area.width : 0;
3806 event->area.y -= height > event->area.height ? height-event->area.height : 0;
3808 event->area.x = max (0, event->area.x);
3809 event->area.y = max (0, event->area.y);
3811 event->area.width = max (width, event->area.width);
3812 event->area.height = max (height, event->area.height);
3814 return FALSE;
3817 /* Attach a tool bar to frame F. */
3819 static void
3820 xg_pack_tool_bar (f)
3821 FRAME_PTR f;
3823 struct x_output *x = f->output_data.x;
3824 int vbox_pos = x->menubar_widget ? 1 : 0;
3826 x->handlebox_widget = gtk_handle_box_new ();
3827 g_signal_connect (G_OBJECT (x->handlebox_widget), "child-detached",
3828 G_CALLBACK (xg_tool_bar_detach_callback), f);
3829 g_signal_connect (G_OBJECT (x->handlebox_widget), "child-attached",
3830 G_CALLBACK (xg_tool_bar_attach_callback), f);
3832 gtk_container_add (GTK_CONTAINER (x->handlebox_widget),
3833 x->toolbar_widget);
3835 gtk_box_pack_start (GTK_BOX (x->vbox_widget), x->handlebox_widget,
3836 FALSE, FALSE, 0);
3838 gtk_box_reorder_child (GTK_BOX (x->vbox_widget), x->handlebox_widget,
3839 vbox_pos);
3840 gtk_widget_show_all (x->handlebox_widget);
3843 /* Create a tool bar for frame F. */
3845 static void
3846 xg_create_tool_bar (f)
3847 FRAME_PTR f;
3849 struct x_output *x = f->output_data.x;
3850 GtkRequisition req;
3852 x->toolbar_widget = gtk_toolbar_new ();
3853 x->toolbar_detached = 0;
3855 gtk_widget_set_name (x->toolbar_widget, "emacs-toolbar");
3857 /* We only have icons, so override any user setting. We could
3858 use the caption property of the toolbar item (see update_frame_tool_bar
3859 below), but some of those strings are long, making the toolbar so
3860 long it does not fit on the screen. The GtkToolbar widget makes every
3861 item equal size, so the longest caption determine the size of every
3862 tool bar item. I think the creators of the GtkToolbar widget
3863 counted on 4 or 5 character long strings. */
3864 gtk_toolbar_set_style (GTK_TOOLBAR (x->toolbar_widget), GTK_TOOLBAR_ICONS);
3865 gtk_toolbar_set_orientation (GTK_TOOLBAR (x->toolbar_widget),
3866 GTK_ORIENTATION_HORIZONTAL);
3870 #define PROP(IDX) AREF (f->tool_bar_items, i * TOOL_BAR_ITEM_NSLOTS + (IDX))
3872 /* Find the right-to-left image named by RTL in the tool bar images for F.
3873 Returns IMAGE if RTL is not found. */
3875 static Lisp_Object
3876 find_rtl_image (f, image, rtl)
3877 FRAME_PTR f;
3878 Lisp_Object image;
3879 Lisp_Object rtl;
3881 int i;
3882 Lisp_Object file, rtl_name;
3883 struct gcpro gcpro1, gcpro2;
3884 GCPRO2 (file, rtl_name);
3886 rtl_name = Ffile_name_nondirectory (rtl);
3888 for (i = 0; i < f->n_tool_bar_items; ++i)
3890 Lisp_Object rtl_image = PROP (TOOL_BAR_ITEM_IMAGES);
3891 if (!NILP (file = file_for_image (rtl_image)))
3893 file = call1 (intern ("file-name-sans-extension"),
3894 Ffile_name_nondirectory (file));
3895 if (EQ (Fequal (file, rtl_name), Qt))
3897 image = rtl_image;
3898 break;
3903 return image;
3906 /* Update the tool bar for frame F. Add new buttons and remove old. */
3908 extern Lisp_Object Qx_gtk_map_stock;
3910 void
3911 update_frame_tool_bar (f)
3912 FRAME_PTR f;
3914 int i;
3915 GtkRequisition old_req, new_req;
3916 struct x_output *x = f->output_data.x;
3917 int hmargin = 0, vmargin = 0;
3918 GtkToolbar *wtoolbar;
3919 GtkToolItem *ti;
3920 GtkTextDirection dir;
3921 int pack_tool_bar = x->handlebox_widget == NULL;
3923 if (! FRAME_GTK_WIDGET (f))
3924 return;
3926 BLOCK_INPUT;
3928 if (INTEGERP (Vtool_bar_button_margin)
3929 && XINT (Vtool_bar_button_margin) > 0)
3931 hmargin = XFASTINT (Vtool_bar_button_margin);
3932 vmargin = XFASTINT (Vtool_bar_button_margin);
3934 else if (CONSP (Vtool_bar_button_margin))
3936 if (INTEGERP (XCAR (Vtool_bar_button_margin))
3937 && XINT (XCAR (Vtool_bar_button_margin)) > 0)
3938 hmargin = XFASTINT (XCAR (Vtool_bar_button_margin));
3940 if (INTEGERP (XCDR (Vtool_bar_button_margin))
3941 && XINT (XCDR (Vtool_bar_button_margin)) > 0)
3942 vmargin = XFASTINT (XCDR (Vtool_bar_button_margin));
3945 /* The natural size (i.e. when GTK uses 0 as margin) looks best,
3946 so take DEFAULT_TOOL_BAR_BUTTON_MARGIN to mean "default for GTK",
3947 i.e. zero. This means that margins less than
3948 DEFAULT_TOOL_BAR_BUTTON_MARGIN has no effect. */
3949 hmargin = max (0, hmargin - DEFAULT_TOOL_BAR_BUTTON_MARGIN);
3950 vmargin = max (0, vmargin - DEFAULT_TOOL_BAR_BUTTON_MARGIN);
3952 if (! x->toolbar_widget)
3953 xg_create_tool_bar (f);
3955 wtoolbar = GTK_TOOLBAR (x->toolbar_widget);
3956 gtk_widget_size_request (GTK_WIDGET (wtoolbar), &old_req);
3957 dir = gtk_widget_get_direction (x->toolbar_widget);
3959 for (i = 0; i < f->n_tool_bar_items; ++i)
3961 int enabled_p = !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P));
3962 int selected_p = !NILP (PROP (TOOL_BAR_ITEM_SELECTED_P));
3963 int idx;
3964 int img_id;
3965 int icon_size = 0;
3966 struct image *img = NULL;
3967 Lisp_Object image;
3968 Lisp_Object stock = Qnil;
3969 GtkStockItem stock_item;
3970 char *stock_name = NULL;
3971 char *icon_name = NULL;
3972 Lisp_Object rtl;
3973 GtkWidget *wbutton = NULL;
3974 GtkWidget *weventbox;
3975 Lisp_Object specified_file;
3977 ti = gtk_toolbar_get_nth_item (GTK_TOOLBAR (x->toolbar_widget), i);
3979 if (ti)
3981 weventbox = gtk_bin_get_child (GTK_BIN (ti));
3982 wbutton = gtk_bin_get_child (GTK_BIN (weventbox));
3985 image = PROP (TOOL_BAR_ITEM_IMAGES);
3987 /* Ignore invalid image specifications. */
3988 if (!valid_image_p (image))
3990 if (wbutton) gtk_widget_hide (wbutton);
3991 continue;
3994 specified_file = file_for_image (image);
3995 if (!NILP (specified_file) && !NILP (Ffboundp (Qx_gtk_map_stock)))
3996 stock = call1 (Qx_gtk_map_stock, specified_file);
3998 if (STRINGP (stock))
4000 stock_name = SSDATA (stock);
4001 if (stock_name[0] == 'n' && stock_name[1] == ':')
4003 GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (wtoolbar));
4004 GtkIconTheme *icon_theme = gtk_icon_theme_get_for_screen (screen);
4006 icon_name = stock_name + 2;
4007 stock_name = NULL;
4008 stock = Qnil;
4010 if (! gtk_icon_theme_has_icon (icon_theme, icon_name))
4011 icon_name = NULL;
4012 else
4013 icon_size = gtk_toolbar_get_icon_size (wtoolbar);
4015 else if (gtk_stock_lookup (SSDATA (stock), &stock_item))
4016 icon_size = gtk_toolbar_get_icon_size (wtoolbar);
4017 else
4019 stock = Qnil;
4020 stock_name = NULL;
4024 if (stock_name == NULL && icon_name == NULL)
4026 /* No stock image, or stock item not known. Try regular image. */
4028 /* If image is a vector, choose the image according to the
4029 button state. */
4030 if (dir == GTK_TEXT_DIR_RTL
4031 && !NILP (rtl = PROP (TOOL_BAR_ITEM_RTL_IMAGE))
4032 && STRINGP (rtl))
4034 image = find_rtl_image (f, image, rtl);
4037 if (VECTORP (image))
4039 if (enabled_p)
4040 idx = (selected_p
4041 ? TOOL_BAR_IMAGE_ENABLED_SELECTED
4042 : TOOL_BAR_IMAGE_ENABLED_DESELECTED);
4043 else
4044 idx = (selected_p
4045 ? TOOL_BAR_IMAGE_DISABLED_SELECTED
4046 : TOOL_BAR_IMAGE_DISABLED_DESELECTED);
4048 xassert (ASIZE (image) >= idx);
4049 image = AREF (image, idx);
4051 else
4052 idx = -1;
4054 img_id = lookup_image (f, image);
4055 img = IMAGE_FROM_ID (f, img_id);
4056 prepare_image_for_display (f, img);
4058 if (img->load_failed_p || img->pixmap == None)
4060 if (ti)
4061 gtk_widget_hide_all (GTK_WIDGET (ti));
4062 else
4064 /* Insert an empty (non-image) button */
4065 weventbox = gtk_event_box_new ();
4066 wbutton = gtk_button_new ();
4067 gtk_button_set_focus_on_click (GTK_BUTTON (wbutton), FALSE);
4068 gtk_button_set_relief (GTK_BUTTON (wbutton),
4069 GTK_RELIEF_NONE);
4070 gtk_container_add (GTK_CONTAINER (weventbox), wbutton);
4071 ti = gtk_tool_item_new ();
4072 gtk_container_add (GTK_CONTAINER (ti), weventbox);
4073 gtk_toolbar_insert (GTK_TOOLBAR (x->toolbar_widget), ti, -1);
4075 continue;
4079 if (ti == NULL)
4081 GtkWidget *w;
4082 if (stock_name)
4084 w = gtk_image_new_from_stock (stock_name, icon_size);
4085 g_object_set_data_full (G_OBJECT (w), XG_TOOL_BAR_STOCK_NAME,
4086 (gpointer) xstrdup (stock_name),
4087 (GDestroyNotify) xfree);
4089 else if (icon_name)
4091 w = gtk_image_new_from_icon_name (icon_name, icon_size);
4092 g_object_set_data_full (G_OBJECT (w), XG_TOOL_BAR_ICON_NAME,
4093 (gpointer) xstrdup (icon_name),
4094 (GDestroyNotify) xfree);
4096 else
4098 w = xg_get_image_for_pixmap (f, img, x->widget, NULL);
4099 /* Save the image so we can see if an update is needed when
4100 this function is called again. */
4101 g_object_set_data (G_OBJECT (w), XG_TOOL_BAR_IMAGE_DATA,
4102 (gpointer)img->pixmap);
4105 gtk_misc_set_padding (GTK_MISC (w), hmargin, vmargin);
4106 wbutton = gtk_button_new ();
4107 gtk_button_set_focus_on_click (GTK_BUTTON (wbutton), FALSE);
4108 gtk_button_set_relief (GTK_BUTTON (wbutton), GTK_RELIEF_NONE);
4109 gtk_container_add (GTK_CONTAINER (wbutton), w);
4110 weventbox = gtk_event_box_new ();
4111 gtk_container_add (GTK_CONTAINER (weventbox), wbutton);
4112 ti = gtk_tool_item_new ();
4113 gtk_container_add (GTK_CONTAINER (ti), weventbox);
4114 gtk_toolbar_insert (GTK_TOOLBAR (x->toolbar_widget), ti, -1);
4117 /* The EMACS_INT cast avoids a warning. */
4118 g_signal_connect (G_OBJECT (ti), "create-menu-proxy",
4119 G_CALLBACK (xg_tool_bar_menu_proxy),
4120 (gpointer) (EMACS_INT) i);
4122 g_signal_connect (G_OBJECT (wbutton), "clicked",
4123 G_CALLBACK (xg_tool_bar_callback),
4124 (gpointer) (EMACS_INT) i);
4126 gtk_widget_show_all (GTK_WIDGET (ti));
4129 g_object_set_data (G_OBJECT (weventbox), XG_FRAME_DATA, (gpointer)f);
4131 /* Catch expose events to overcome an annoying redraw bug, see
4132 comment for xg_tool_bar_item_expose_callback. */
4133 g_signal_connect (G_OBJECT (ti),
4134 "expose-event",
4135 G_CALLBACK (xg_tool_bar_item_expose_callback),
4138 gtk_widget_set_sensitive (wbutton, enabled_p);
4139 gtk_tool_item_set_homogeneous (ti, FALSE);
4141 /* Callback to save modifyer mask (Shift/Control, etc). GTK makes
4142 no distinction based on modifiers in the activate callback,
4143 so we have to do it ourselves. */
4144 g_signal_connect (wbutton, "button-release-event",
4145 G_CALLBACK (xg_tool_bar_button_cb),
4146 NULL);
4148 g_object_set_data (G_OBJECT (wbutton), XG_FRAME_DATA, (gpointer)f);
4150 /* Use enter/leave notify to show help. We use the events
4151 rather than the GtkButton specific signals "enter" and
4152 "leave", so we can have only one callback. The event
4153 will tell us what kind of event it is. */
4154 /* The EMACS_INT cast avoids a warning. */
4155 g_signal_connect (G_OBJECT (weventbox),
4156 "enter-notify-event",
4157 G_CALLBACK (xg_tool_bar_help_callback),
4158 (gpointer) (EMACS_INT) i);
4159 g_signal_connect (G_OBJECT (weventbox),
4160 "leave-notify-event",
4161 G_CALLBACK (xg_tool_bar_help_callback),
4162 (gpointer) (EMACS_INT) i);
4164 else
4166 GtkWidget *wimage = gtk_bin_get_child (GTK_BIN (wbutton));
4167 Pixmap old_img = (Pixmap)g_object_get_data (G_OBJECT (wimage),
4168 XG_TOOL_BAR_IMAGE_DATA);
4169 gpointer old_stock_name = g_object_get_data (G_OBJECT (wimage),
4170 XG_TOOL_BAR_STOCK_NAME);
4171 gpointer old_icon_name = g_object_get_data (G_OBJECT (wimage),
4172 XG_TOOL_BAR_ICON_NAME);
4173 if (stock_name &&
4174 (! old_stock_name || strcmp (old_stock_name, stock_name) != 0))
4176 gtk_image_set_from_stock (GTK_IMAGE (wimage),
4177 stock_name, icon_size);
4178 g_object_set_data_full (G_OBJECT (wimage), XG_TOOL_BAR_STOCK_NAME,
4179 (gpointer) xstrdup (stock_name),
4180 (GDestroyNotify) xfree);
4181 g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_IMAGE_DATA,
4182 NULL);
4183 g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_ICON_NAME, NULL);
4185 else if (icon_name &&
4186 (! old_icon_name || strcmp (old_icon_name, icon_name) != 0))
4188 gtk_image_set_from_icon_name (GTK_IMAGE (wimage),
4189 icon_name, icon_size);
4190 g_object_set_data_full (G_OBJECT (wimage), XG_TOOL_BAR_ICON_NAME,
4191 (gpointer) xstrdup (icon_name),
4192 (GDestroyNotify) xfree);
4193 g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_IMAGE_DATA,
4194 NULL);
4195 g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_STOCK_NAME,
4196 NULL);
4198 else if (img && old_img != img->pixmap)
4200 (void) xg_get_image_for_pixmap (f, img, x->widget, wimage);
4201 g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_IMAGE_DATA,
4202 (gpointer)img->pixmap);
4204 g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_STOCK_NAME,
4205 NULL);
4206 g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_ICON_NAME, NULL);
4209 gtk_misc_set_padding (GTK_MISC (wimage), hmargin, vmargin);
4211 gtk_widget_set_sensitive (wbutton, enabled_p);
4212 gtk_widget_show_all (GTK_WIDGET (ti));
4215 #undef PROP
4218 /* Remove buttons not longer needed. We just hide them so they
4219 can be reused later on. */
4222 ti = gtk_toolbar_get_nth_item (GTK_TOOLBAR (x->toolbar_widget), i++);
4223 if (ti) gtk_widget_hide_all (GTK_WIDGET (ti));
4224 } while (ti != NULL);
4226 new_req.height = 0;
4227 if (pack_tool_bar && f->n_tool_bar_items != 0)
4228 xg_pack_tool_bar (f);
4231 gtk_widget_size_request (GTK_WIDGET (x->toolbar_widget), &new_req);
4232 if (old_req.height != new_req.height
4233 && ! FRAME_X_OUTPUT (f)->toolbar_detached)
4235 FRAME_TOOLBAR_HEIGHT (f) = new_req.height;
4236 xg_height_changed (f);
4238 UNBLOCK_INPUT;
4241 /* Deallocate all resources for the tool bar on frame F.
4242 Remove the tool bar. */
4244 void
4245 free_frame_tool_bar (f)
4246 FRAME_PTR f;
4248 struct x_output *x = f->output_data.x;
4250 if (x->toolbar_widget)
4252 int is_packed = x->handlebox_widget != 0;
4253 BLOCK_INPUT;
4254 /* We may have created the toolbar_widget in xg_create_tool_bar, but
4255 not the x->handlebox_widget which is created in xg_pack_tool_bar. */
4256 if (is_packed)
4257 gtk_container_remove (GTK_CONTAINER (x->vbox_widget),
4258 x->handlebox_widget);
4259 else
4260 gtk_widget_destroy (x->toolbar_widget);
4262 x->toolbar_widget = 0;
4263 x->handlebox_widget = 0;
4264 FRAME_TOOLBAR_HEIGHT (f) = 0;
4265 xg_height_changed (f);
4267 UNBLOCK_INPUT;
4273 /***********************************************************************
4274 Initializing
4275 ***********************************************************************/
4276 void
4277 xg_initialize ()
4279 GtkBindingSet *binding_set;
4281 #if HAVE_XFT
4282 /* Work around a bug with corrupted data if libXft gets unloaded. This way
4283 we keep it permanently linked in. */
4284 XftInit (0);
4285 #endif
4287 gdpy_def = NULL;
4288 xg_ignore_gtk_scrollbar = 0;
4289 xg_detached_menus = 0;
4290 xg_menu_cb_list.prev = xg_menu_cb_list.next =
4291 xg_menu_item_cb_list.prev = xg_menu_item_cb_list.next = 0;
4293 id_to_widget.max_size = id_to_widget.used = 0;
4294 id_to_widget.widgets = 0;
4296 /* Remove F10 as a menu accelerator, it does not mix well with Emacs key
4297 bindings. It doesn't seem to be any way to remove properties,
4298 so we set it to VoidSymbol which in X means "no key". */
4299 gtk_settings_set_string_property (gtk_settings_get_default (),
4300 "gtk-menu-bar-accel",
4301 "VoidSymbol",
4302 EMACS_CLASS);
4304 /* Make GTK text input widgets use Emacs style keybindings. This is
4305 Emacs after all. */
4306 gtk_settings_set_string_property (gtk_settings_get_default (),
4307 "gtk-key-theme-name",
4308 "Emacs",
4309 EMACS_CLASS);
4311 /* Make dialogs close on C-g. Since file dialog inherits from
4312 dialog, this works for them also. */
4313 binding_set = gtk_binding_set_by_class (g_type_class_ref (GTK_TYPE_DIALOG));
4314 gtk_binding_entry_add_signal (binding_set, GDK_g, GDK_CONTROL_MASK,
4315 "close", 0);
4317 /* Make menus close on C-g. */
4318 binding_set = gtk_binding_set_by_class (g_type_class_ref
4319 (GTK_TYPE_MENU_SHELL));
4320 gtk_binding_entry_add_signal (binding_set, GDK_g, GDK_CONTROL_MASK,
4321 "cancel", 0);
4324 #endif /* USE_GTK */
4326 /* arch-tag: fe7104da-bc1e-4aba-9bd1-f349c528f7e3
4327 (do not change this comment) */