]> code.delx.au - gnu-emacs/blob - src/gtkutil.c
* xterm.c:
[gnu-emacs] / src / gtkutil.c
1 /* Functions for creating and updating GTK widgets.
2 Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009
3 Free Software Foundation, Inc.
4
5 This file is part of GNU Emacs.
6
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.
11
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.
16
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/>. */
19
20 #include <config.h>
21
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>
39
40 #ifdef HAVE_XFT
41 #include <X11/Xft/Xft.h>
42 #endif
43
44 #define FRAME_TOTAL_PIXEL_HEIGHT(f) \
45 (FRAME_PIXEL_HEIGHT (f) + FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f))
46
47 /* Avoid "differ in sign" warnings */
48 #define SSDATA(x) ((char *) SDATA (x))
49
50 \f
51 /***********************************************************************
52 Display handling functions
53 ***********************************************************************/
54
55 #ifdef HAVE_GTK_MULTIDISPLAY
56
57 /* Keep track of the default display, or NULL if there is none. Emacs
58 may close all its displays. */
59
60 static GdkDisplay *gdpy_def;
61
62 /* Return the GdkDisplay that corresponds to the X display DPY. */
63
64 static GdkDisplay *
65 xg_get_gdk_display (dpy)
66 Display *dpy;
67 {
68 return gdk_x11_lookup_xdisplay (dpy);
69 }
70
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. */
74
75 static void
76 xg_set_screen (w, f)
77 GtkWidget *w;
78 FRAME_PTR f;
79 {
80 if (FRAME_X_DISPLAY (f) != GDK_DISPLAY ())
81 {
82 GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (FRAME_X_DISPLAY (f));
83 GdkScreen *gscreen = gdk_display_get_default_screen (gdpy);
84
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);
89 }
90 }
91
92
93 #else /* not HAVE_GTK_MULTIDISPLAY */
94
95 /* Make some defines so we can use the GTK 2.2 functions when
96 compiling with GTK 2.0. */
97
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
104
105 #endif /* not HAVE_GTK_MULTIDISPLAY */
106
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.
109
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. */
113
114 int
115 xg_display_open (display_name, dpy)
116 char *display_name;
117 Display **dpy;
118 {
119 #ifdef HAVE_GTK_MULTIDISPLAY
120 GdkDisplay *gdpy;
121
122 gdpy = gdk_display_open (display_name);
123 if (!gdpy_def && gdpy)
124 {
125 gdpy_def = gdpy;
126 gdk_display_manager_set_default_display (gdk_display_manager_get (),
127 gdpy);
128 }
129
130 *dpy = gdpy ? GDK_DISPLAY_XDISPLAY (gdpy) : NULL;
131 return gdpy != NULL;
132
133 #else /* not HAVE_GTK_MULTIDISPLAY */
134
135 return -1;
136 #endif /* not HAVE_GTK_MULTIDISPLAY */
137 }
138
139
140 /* Close display DPY. */
141
142 void
143 xg_display_close (Display *dpy)
144 {
145 #ifdef HAVE_GTK_MULTIDISPLAY
146 GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (dpy);
147
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)
152 {
153 struct x_display_info *dpyinfo;
154 GdkDisplay *gdpy_new = NULL;
155
156 /* Find another display. */
157 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
158 if (dpyinfo->display != dpy)
159 {
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;
164 }
165 gdpy_def = gdpy_new;
166 }
167
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 */
178 }
179
180 \f
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;
187
188
189 /* The next two variables and functions are taken from lwlib. */
190 static widget_value *widget_value_free_list;
191 static int malloc_cpt;
192
193 /* Allocate a widget_value structure, either by taking one from the
194 widget_value_free_list or by malloc:ing a new one.
195
196 Return a pointer to the allocated structure. */
197
198 widget_value *
199 malloc_widget_value ()
200 {
201 widget_value *wv;
202 if (widget_value_free_list)
203 {
204 wv = widget_value_free_list;
205 widget_value_free_list = wv->free_list;
206 wv->free_list = 0;
207 }
208 else
209 {
210 wv = (widget_value *) xmalloc (sizeof (widget_value));
211 malloc_cpt++;
212 }
213 memset (wv, 0, sizeof (widget_value));
214 return wv;
215 }
216
217 /* This is analogous to free. It frees only what was allocated
218 by malloc_widget_value, and no substructures. */
219
220 void
221 free_widget_value (wv)
222 widget_value *wv;
223 {
224 if (wv->free_list)
225 abort ();
226
227 if (malloc_cpt > 25)
228 {
229 /* When the number of already allocated cells is too big,
230 We free it. */
231 xfree (wv);
232 malloc_cpt--;
233 }
234 else
235 {
236 wv->free_list = widget_value_free_list;
237 widget_value_free_list = wv;
238 }
239 }
240
241
242 /* Create and return the cursor to be used for popup menus and
243 scroll bars on display DPY. */
244
245 GdkCursor *
246 xg_create_default_cursor (dpy)
247 Display *dpy;
248 {
249 GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (dpy);
250 return gdk_cursor_new_for_display (gdpy, GDK_LEFT_PTR);
251 }
252
253 /* Apply GMASK to GPIX and return a GdkPixbuf with an alpha channel. */
254
255 static GdkPixbuf *
256 xg_get_pixbuf_from_pix_and_mask (gpix, gmask, cmap)
257 GdkPixmap *gpix;
258 GdkPixmap *gmask;
259 GdkColormap *cmap;
260 {
261 int x, y, width, height, rowstride, mask_rowstride;
262 GdkPixbuf *icon_buf, *tmp_buf;
263 guchar *pixels;
264 guchar *mask_pixels;
265
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));
271
272 if (gmask)
273 {
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;
284
285 for (y = 0; y < height; ++y)
286 {
287 guchar *iconptr, *maskptr;
288 int x;
289
290 iconptr = pixels + y * rowstride;
291 maskptr = mask_pixels + y * mask_rowstride;
292
293 for (x = 0; x < width; ++x)
294 {
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. */
299
300 iconptr += rowstride/width;
301 maskptr += mask_rowstride/width;
302 }
303 }
304
305 g_object_unref (G_OBJECT (mask_buf));
306 }
307
308 return icon_buf;
309 }
310
311 static Lisp_Object
312 file_for_image (image)
313 Lisp_Object image;
314 {
315 Lisp_Object specified_file = Qnil;
316 Lisp_Object tail;
317 extern Lisp_Object QCfile;
318
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));
324
325 return specified_file;
326 }
327
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. */
338
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;
345 {
346 GdkPixmap *gpix;
347 GdkPixmap *gmask;
348 GdkDisplay *gdpy;
349 GdkColormap *cmap;
350 GdkPixbuf *icon_buf;
351
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;
357
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. */
361
362 if (STRINGP (specified_file)
363 && STRINGP (file = x_find_image_file (specified_file)))
364 {
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));
369
370 return GTK_WIDGET (old_widget);
371 }
372
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. */
376
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;
380
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);
392
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);
397
398 g_object_unref (G_OBJECT (icon_buf));
399
400 g_object_unref (G_OBJECT (gpix));
401 if (gmask) g_object_unref (G_OBJECT (gmask));
402
403 return GTK_WIDGET (old_widget);
404 }
405
406
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. */
410
411 static void
412 xg_set_cursor (w, cursor)
413 GtkWidget *w;
414 GdkCursor *cursor;
415 {
416 GList *children = gdk_window_peek_children (w->window);
417
418 gdk_window_set_cursor (w->window, cursor);
419
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. */
424
425 for ( ; children; children = g_list_next (children))
426 gdk_window_set_cursor (GDK_WINDOW (children->data), cursor);
427 }
428
429 /* Timer function called when a timeout occurs for xg_timer.
430 This function processes all GTK events in a recursive event loop.
431 This is done because GTK timer events are not seen by Emacs event
432 detection, Emacs only looks for X events. When a scroll bar has the
433 pointer (detected by button press/release events below) an Emacs
434 timer is started, and this function can then check if the GTK timer
435 has expired by calling the GTK event loop.
436 Also, when a menu is active, it has a small timeout before it
437 pops down the sub menu under it. */
438
439 static void
440 xg_process_timeouts (timer)
441 struct atimer *timer;
442 {
443 BLOCK_INPUT;
444 /* Ideally we would like to just handle timer events, like the Xt version
445 of this does in xterm.c, but there is no such feature in GTK. */
446 while (gtk_events_pending ())
447 gtk_main_iteration ();
448 UNBLOCK_INPUT;
449 }
450
451 /* Start the xg_timer with an interval of 0.1 seconds, if not already started.
452 xg_process_timeouts is called when the timer expires. The timer
453 started is continuous, i.e. runs until xg_stop_timer is called. */
454
455 static void
456 xg_start_timer ()
457 {
458 if (! xg_timer)
459 {
460 EMACS_TIME interval;
461 EMACS_SET_SECS_USECS (interval, 0, 100000);
462 xg_timer = start_atimer (ATIMER_CONTINUOUS,
463 interval,
464 xg_process_timeouts,
465 0);
466 }
467 }
468
469 /* Stop the xg_timer if started. */
470
471 static void
472 xg_stop_timer ()
473 {
474 if (xg_timer)
475 {
476 cancel_atimer (xg_timer);
477 xg_timer = 0;
478 }
479 }
480
481 /* Insert NODE into linked LIST. */
482
483 static void
484 xg_list_insert (xg_list_node *list, xg_list_node *node)
485 {
486 xg_list_node *list_start = list->next;
487
488 if (list_start) list_start->prev = node;
489 node->next = list_start;
490 node->prev = 0;
491 list->next = node;
492 }
493
494 /* Remove NODE from linked LIST. */
495
496 static void
497 xg_list_remove (xg_list_node *list, xg_list_node *node)
498 {
499 xg_list_node *list_start = list->next;
500 if (node == list_start)
501 {
502 list->next = node->next;
503 if (list->next) list->next->prev = 0;
504 }
505 else
506 {
507 node->prev->next = node->next;
508 if (node->next) node->next->prev = node->prev;
509 }
510 }
511
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. */
516
517 static char *
518 get_utf8_string (str)
519 char *str;
520 {
521 char *utf8_str = str;
522
523 if (!str) return NULL;
524
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);
528
529 if (!utf8_str)
530 {
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;
538
539 while (! (cp = g_locale_to_utf8 ((char *)p, -1, &bytes_read,
540 &bytes_written, &error))
541 && error->code == G_CONVERT_ERROR_ILLEGAL_SEQUENCE)
542 {
543 ++nr_bad;
544 p += bytes_written+1;
545 g_error_free (error);
546 error = NULL;
547 }
548
549 if (error)
550 {
551 g_error_free (error);
552 error = NULL;
553 }
554 if (cp) g_free (cp);
555
556 up = utf8_str = xmalloc (strlen (str) + nr_bad * 4 + 1);
557 p = (unsigned char *)str;
558
559 while (! (cp = g_locale_to_utf8 ((char *)p, -1, &bytes_read,
560 &bytes_written, &error))
561 && error->code == G_CONVERT_ERROR_ILLEGAL_SEQUENCE)
562 {
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;
570 }
571
572 if (cp)
573 {
574 strcat (utf8_str, cp);
575 g_free (cp);
576 }
577 if (error)
578 {
579 g_error_free (error);
580 error = NULL;
581 }
582 }
583 return utf8_str;
584 }
585
586
587 \f
588 /***********************************************************************
589 General functions for creating widgets, resizing, events, e.t.c.
590 ***********************************************************************/
591
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. */
596
597 static void
598 xg_set_geometry (f)
599 FRAME_PTR f;
600 {
601 if (f->size_hint_flags & USPosition)
602 {
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];
608
609 if (xneg)
610 left = -left;
611 if (yneg)
612 top = -top;
613
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);
619
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);
623 }
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);
627 }
628
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. */
634
635 void
636 xg_frame_resized (f, pixelwidth, pixelheight)
637 FRAME_PTR f;
638 int pixelwidth, pixelheight;
639 {
640 int rows, columns;
641
642 if (pixelwidth == -1 && pixelheight == -1)
643 {
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;
648 }
649
650
651 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, pixelheight);
652 columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, pixelwidth);
653
654 if (columns != FRAME_COLS (f)
655 || rows != FRAME_LINES (f)
656 || pixelwidth != FRAME_PIXEL_WIDTH (f)
657 || pixelheight != FRAME_PIXEL_HEIGHT (f))
658 {
659 FRAME_PIXEL_WIDTH (f) = pixelwidth;
660 FRAME_PIXEL_HEIGHT (f) = pixelheight;
661
662 change_frame_size (f, rows, columns, 0, 1, 0);
663 SET_FRAME_GARBAGED (f);
664 cancel_mouse_face (f);
665 }
666 }
667
668 static void
669 flush_and_sync (f)
670 FRAME_PTR f;
671 {
672 gdk_window_process_all_updates ();
673 x_sync (f);
674 while (gtk_events_pending ())
675 {
676 gtk_main_iteration ();
677 gdk_window_process_all_updates ();
678 x_sync (f);
679 }
680 }
681
682 /* Resize the outer window of frame F after chainging the height.
683 COLUMNS/ROWS is the size the edit area shall have after the resize. */
684
685 void
686 xg_frame_set_char_size (f, cols, rows)
687 FRAME_PTR f;
688 int cols;
689 int rows;
690 {
691 int pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows)
692 + FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f);
693 int pixelwidth;
694
695 if (FRAME_PIXEL_HEIGHT (f) == 0)
696 return;
697
698 /* Take into account the size of the scroll bar. Always use the
699 number of columns occupied by the scroll bar here otherwise we
700 might end up with a frame width that is not a multiple of the
701 frame's character width which is bad for vertically split
702 windows. */
703 f->scroll_bar_actual_width
704 = FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f);
705
706 compute_fringe_widths (f, 0);
707
708 /* FRAME_TEXT_COLS_TO_PIXEL_WIDTH uses scroll_bar_actual_width, so call it
709 after calculating that value. */
710 pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, cols);
711
712 /* Must resize our top level widget. Font size may have changed,
713 but not rows/cols. */
714 gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
715 pixelwidth, pixelheight);
716 x_wm_set_size_hint (f, 0, 0);
717
718 /* We can not call change_frame_size for a mapped frame,
719 we can not set pixel width/height either. The window manager may
720 override our resize request, XMonad does this all the time.
721 The best we can do is try to sync, so lisp code sees the updated
722 size as fast as possible.
723 For unmapped windows, we can set rows/cols. When
724 the frame is mapped again we will (hopefully) get the correct size. */
725 if (f->async_visible)
726 flush_and_sync (f);
727 else
728 {
729 FRAME_PIXEL_WIDTH (f) = pixelwidth;
730 FRAME_PIXEL_HEIGHT (f) = pixelheight;
731 change_frame_size (f, rows, cols, 0, 1, 0);
732 SET_FRAME_GARBAGED (f);
733 cancel_mouse_face (f);
734 }
735 }
736
737 /* Handle height changes (i.e. add/remove menu/toolbar).
738 The policy is to keep the number of editable lines. */
739
740 static void
741 xg_height_changed (f)
742 FRAME_PTR f;
743 {
744 gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
745 FRAME_PIXEL_WIDTH (f), FRAME_TOTAL_PIXEL_HEIGHT (f));
746 f->output_data.x->hint_flags = 0;
747 x_wm_set_size_hint (f, 0, 0);
748 }
749
750 /* Convert an X Window WSESC on display DPY to its corresponding GtkWidget.
751 Must be done like this, because GtkWidget:s can have "hidden"
752 X Window that aren't accessible.
753
754 Return 0 if no widget match WDESC. */
755
756 GtkWidget *
757 xg_win_to_widget (dpy, wdesc)
758 Display *dpy;
759 Window wdesc;
760 {
761 gpointer gdkwin;
762 GtkWidget *gwdesc = 0;
763
764 BLOCK_INPUT;
765
766 gdkwin = gdk_xid_table_lookup_for_display (gdk_x11_lookup_xdisplay (dpy),
767 wdesc);
768 if (gdkwin)
769 {
770 GdkEvent event;
771 event.any.window = gdkwin;
772 gwdesc = gtk_get_event_widget (&event);
773 }
774
775 UNBLOCK_INPUT;
776 return gwdesc;
777 }
778
779 /* Fill in the GdkColor C so that it represents PIXEL.
780 W is the widget that color will be used for. Used to find colormap. */
781
782 static void
783 xg_pix_to_gcolor (w, pixel, c)
784 GtkWidget *w;
785 unsigned long pixel;
786 GdkColor *c;
787 {
788 GdkColormap *map = gtk_widget_get_colormap (w);
789 gdk_colormap_query_color (map, pixel, c);
790 }
791
792 /* Create and set up the GTK widgets for frame F.
793 Return 0 if creation failed, non-zero otherwise. */
794
795 int
796 xg_create_frame_widgets (f)
797 FRAME_PTR f;
798 {
799 GtkWidget *wtop;
800 GtkWidget *wvbox;
801 GtkWidget *wfixed;
802 GdkColor bg;
803 GtkRcStyle *style;
804 int i;
805 char *title = 0;
806
807 BLOCK_INPUT;
808
809 if (FRAME_X_EMBEDDED_P (f))
810 wtop = gtk_plug_new (f->output_data.x->parent_desc);
811 else
812 wtop = gtk_window_new (GTK_WINDOW_TOPLEVEL);
813
814 xg_set_screen (wtop, f);
815
816 wvbox = gtk_vbox_new (FALSE, 0);
817 wfixed = gtk_fixed_new (); /* Must have this to place scroll bars */
818
819 if (! wtop || ! wvbox || ! wfixed)
820 {
821 if (wtop) gtk_widget_destroy (wtop);
822 if (wvbox) gtk_widget_destroy (wvbox);
823 if (wfixed) gtk_widget_destroy (wfixed);
824
825 UNBLOCK_INPUT;
826 return 0;
827 }
828
829 /* Use same names as the Xt port does. I.e. Emacs.pane.emacs by default */
830 gtk_widget_set_name (wtop, EMACS_CLASS);
831 gtk_widget_set_name (wvbox, "pane");
832 gtk_widget_set_name (wfixed, SSDATA (Vx_resource_name));
833
834 /* If this frame has a title or name, set it in the title bar. */
835 if (! NILP (f->title)) title = SSDATA (ENCODE_UTF_8 (f->title));
836 else if (! NILP (f->name)) title = SSDATA (ENCODE_UTF_8 (f->name));
837
838 if (title) gtk_window_set_title (GTK_WINDOW (wtop), title);
839
840 FRAME_GTK_OUTER_WIDGET (f) = wtop;
841 FRAME_GTK_WIDGET (f) = wfixed;
842 f->output_data.x->vbox_widget = wvbox;
843
844 gtk_fixed_set_has_window (GTK_FIXED (wfixed), TRUE);
845
846 gtk_container_add (GTK_CONTAINER (wtop), wvbox);
847 gtk_box_pack_end (GTK_BOX (wvbox), wfixed, TRUE, TRUE, 0);
848
849 if (FRAME_EXTERNAL_TOOL_BAR (f))
850 update_frame_tool_bar (f);
851
852 /* We don't want this widget double buffered, because we draw on it
853 with regular X drawing primitives, so from a GTK/GDK point of
854 view, the widget is totally blank. When an expose comes, this
855 will make the widget blank, and then Emacs redraws it. This flickers
856 a lot, so we turn off double buffering. */
857 gtk_widget_set_double_buffered (wfixed, FALSE);
858
859 gtk_window_set_wmclass (GTK_WINDOW (wtop),
860 SSDATA (Vx_resource_name),
861 SSDATA (Vx_resource_class));
862
863 /* Add callback to do nothing on WM_DELETE_WINDOW. The default in
864 GTK is to destroy the widget. We want Emacs to do that instead. */
865 g_signal_connect (G_OBJECT (wtop), "delete-event",
866 G_CALLBACK (gtk_true), 0);
867
868 /* Convert our geometry parameters into a geometry string
869 and specify it.
870 GTK will itself handle calculating the real position this way. */
871 xg_set_geometry (f);
872 int grav = gtk_window_get_gravity (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)));
873 f->win_gravity = grav;
874
875 gtk_widget_add_events (wfixed,
876 GDK_POINTER_MOTION_MASK
877 | GDK_EXPOSURE_MASK
878 | GDK_BUTTON_PRESS_MASK
879 | GDK_BUTTON_RELEASE_MASK
880 | GDK_KEY_PRESS_MASK
881 | GDK_ENTER_NOTIFY_MASK
882 | GDK_LEAVE_NOTIFY_MASK
883 | GDK_FOCUS_CHANGE_MASK
884 | GDK_STRUCTURE_MASK
885 | GDK_VISIBILITY_NOTIFY_MASK);
886
887 /* Must realize the windows so the X window gets created. It is used
888 by callers of this function. */
889 gtk_widget_realize (wfixed);
890 FRAME_X_WINDOW (f) = GTK_WIDGET_TO_X_WIN (wfixed);
891
892 /* Since GTK clears its window by filling with the background color,
893 we must keep X and GTK background in sync. */
894 xg_pix_to_gcolor (wfixed, FRAME_BACKGROUND_PIXEL (f), &bg);
895 gtk_widget_modify_bg (wfixed, GTK_STATE_NORMAL, &bg);
896
897 /* Also, do not let any background pixmap to be set, this looks very
898 bad as Emacs overwrites the background pixmap with its own idea
899 of background color. */
900 style = gtk_widget_get_modifier_style (wfixed);
901
902 /* Must use g_strdup because gtk_widget_modify_style does g_free. */
903 style->bg_pixmap_name[GTK_STATE_NORMAL] = g_strdup ("<none>");
904 gtk_widget_modify_style (wfixed, style);
905
906 /* GTK does not set any border, and they look bad with GTK. */
907 /* That they look bad is no excuse for imposing this here. --Stef
908 It should be done by providing the proper default in Fx_create_Frame.
909 f->border_width = 0;
910 f->internal_border_width = 0; */
911
912 UNBLOCK_INPUT;
913
914 return 1;
915 }
916
917 /* Set the normal size hints for the window manager, for frame F.
918 FLAGS is the flags word to use--or 0 meaning preserve the flags
919 that the window now has.
920 If USER_POSITION is nonzero, we set the User Position
921 flag (this is useful when FLAGS is 0). */
922
923 void
924 x_wm_set_size_hint (f, flags, user_position)
925 FRAME_PTR f;
926 long flags;
927 int user_position;
928 {
929 /* Don't set size hints during initialization; that apparently leads
930 to a race condition. See the thread at
931 http://lists.gnu.org/archive/html/emacs-devel/2008-10/msg00033.html */
932 if (NILP (Vafter_init_time) || !FRAME_GTK_OUTER_WIDGET (f))
933 return;
934
935 /* Must use GTK routines here, otherwise GTK resets the size hints
936 to its own defaults. */
937 GdkGeometry size_hints;
938 gint hint_flags = 0;
939 int base_width, base_height;
940 int min_rows = 0, min_cols = 0;
941 int win_gravity = f->win_gravity;
942
943 if (flags)
944 {
945 memset (&size_hints, 0, sizeof (size_hints));
946 f->output_data.x->size_hints = size_hints;
947 f->output_data.x->hint_flags = hint_flags;
948 }
949 else
950 flags = f->size_hint_flags;
951
952 size_hints = f->output_data.x->size_hints;
953 hint_flags = f->output_data.x->hint_flags;
954
955 hint_flags |= GDK_HINT_RESIZE_INC | GDK_HINT_MIN_SIZE;
956 size_hints.width_inc = FRAME_COLUMN_WIDTH (f);
957 size_hints.height_inc = FRAME_LINE_HEIGHT (f);
958
959 hint_flags |= GDK_HINT_BASE_SIZE;
960 base_width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, 0);
961 base_height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, 0)
962 + FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f);
963
964 check_frame_size (f, &min_rows, &min_cols);
965
966 size_hints.base_width = base_width;
967 size_hints.base_height = base_height;
968 size_hints.min_width = base_width + min_cols * size_hints.width_inc;
969 size_hints.min_height = base_height + min_rows * size_hints.height_inc;
970
971 /* These currently have a one to one mapping with the X values, but I
972 don't think we should rely on that. */
973 hint_flags |= GDK_HINT_WIN_GRAVITY;
974 size_hints.win_gravity = 0;
975 if (win_gravity == NorthWestGravity)
976 size_hints.win_gravity = GDK_GRAVITY_NORTH_WEST;
977 else if (win_gravity == NorthGravity)
978 size_hints.win_gravity = GDK_GRAVITY_NORTH;
979 else if (win_gravity == NorthEastGravity)
980 size_hints.win_gravity = GDK_GRAVITY_NORTH_EAST;
981 else if (win_gravity == WestGravity)
982 size_hints.win_gravity = GDK_GRAVITY_WEST;
983 else if (win_gravity == CenterGravity)
984 size_hints.win_gravity = GDK_GRAVITY_CENTER;
985 else if (win_gravity == EastGravity)
986 size_hints.win_gravity = GDK_GRAVITY_EAST;
987 else if (win_gravity == SouthWestGravity)
988 size_hints.win_gravity = GDK_GRAVITY_SOUTH_WEST;
989 else if (win_gravity == SouthGravity)
990 size_hints.win_gravity = GDK_GRAVITY_SOUTH;
991 else if (win_gravity == SouthEastGravity)
992 size_hints.win_gravity = GDK_GRAVITY_SOUTH_EAST;
993 else if (win_gravity == StaticGravity)
994 size_hints.win_gravity = GDK_GRAVITY_STATIC;
995
996 if (flags & PPosition) hint_flags |= GDK_HINT_POS;
997 if (flags & USPosition) hint_flags |= GDK_HINT_USER_POS;
998 if (flags & USSize) hint_flags |= GDK_HINT_USER_SIZE;
999
1000 if (user_position)
1001 {
1002 hint_flags &= ~GDK_HINT_POS;
1003 hint_flags |= GDK_HINT_USER_POS;
1004 }
1005
1006 if (hint_flags != f->output_data.x->hint_flags
1007 || memcmp (&size_hints,
1008 &f->output_data.x->size_hints,
1009 sizeof (size_hints)) != 0)
1010 {
1011 BLOCK_INPUT;
1012 gtk_window_set_geometry_hints (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
1013 NULL, &size_hints, hint_flags);
1014 f->output_data.x->size_hints = size_hints;
1015 f->output_data.x->hint_flags = hint_flags;
1016 UNBLOCK_INPUT;
1017 }
1018 }
1019
1020 /* Change background color of a frame.
1021 Since GTK uses the background color to clear the window, we must
1022 keep the GTK and X colors in sync.
1023 F is the frame to change,
1024 BG is the pixel value to change to. */
1025
1026 void
1027 xg_set_background_color (f, bg)
1028 FRAME_PTR f;
1029 unsigned long bg;
1030 {
1031 if (FRAME_GTK_WIDGET (f))
1032 {
1033 GdkColor gdk_bg;
1034
1035 BLOCK_INPUT;
1036 xg_pix_to_gcolor (FRAME_GTK_WIDGET (f), bg, &gdk_bg);
1037 gtk_widget_modify_bg (FRAME_GTK_WIDGET (f), GTK_STATE_NORMAL, &gdk_bg);
1038 UNBLOCK_INPUT;
1039 }
1040 }
1041
1042
1043 /* Set the frame icon to ICON_PIXMAP/MASK. This must be done with GTK
1044 functions so GTK does not overwrite the icon. */
1045
1046 void
1047 xg_set_frame_icon (f, icon_pixmap, icon_mask)
1048 FRAME_PTR f;
1049 Pixmap icon_pixmap;
1050 Pixmap icon_mask;
1051 {
1052 GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (FRAME_X_DISPLAY (f));
1053 GdkPixmap *gpix = gdk_pixmap_foreign_new_for_display (gdpy, icon_pixmap);
1054 GdkPixmap *gmask = gdk_pixmap_foreign_new_for_display (gdpy, icon_mask);
1055 GdkPixbuf *gp = xg_get_pixbuf_from_pix_and_mask (gpix, gmask, NULL);
1056
1057 gtk_window_set_icon (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), gp);
1058 }
1059
1060
1061 \f
1062 /***********************************************************************
1063 Dialog functions
1064 ***********************************************************************/
1065 /* Return the dialog title to use for a dialog of type KEY.
1066 This is the encoding used by lwlib. We use the same for GTK. */
1067
1068 static char *
1069 get_dialog_title (char key)
1070 {
1071 char *title = "";
1072
1073 switch (key) {
1074 case 'E': case 'e':
1075 title = "Error";
1076 break;
1077
1078 case 'I': case 'i':
1079 title = "Information";
1080 break;
1081
1082 case 'L': case 'l':
1083 title = "Prompt";
1084 break;
1085
1086 case 'P': case 'p':
1087 title = "Prompt";
1088 break;
1089
1090 case 'Q': case 'q':
1091 title = "Question";
1092 break;
1093 }
1094
1095 return title;
1096 }
1097
1098 /* Callback for dialogs that get WM_DELETE_WINDOW. We pop down
1099 the dialog, but return TRUE so the event does not propagate further
1100 in GTK. This prevents GTK from destroying the dialog widget automatically
1101 and we can always destrou the widget manually, regardles of how
1102 it was popped down (button press or WM_DELETE_WINDOW).
1103 W is the dialog widget.
1104 EVENT is the GdkEvent that represents WM_DELETE_WINDOW (not used).
1105 user_data is NULL (not used).
1106
1107 Returns TRUE to end propagation of event. */
1108
1109 static gboolean
1110 dialog_delete_callback (w, event, user_data)
1111 GtkWidget *w;
1112 GdkEvent *event;
1113 gpointer user_data;
1114 {
1115 gtk_widget_unmap (w);
1116 return TRUE;
1117 }
1118
1119 /* Create a popup dialog window. See also xg_create_widget below.
1120 WV is a widget_value describing the dialog.
1121 SELECT_CB is the callback to use when a button has been pressed.
1122 DEACTIVATE_CB is the callback to use when the dialog pops down.
1123
1124 Returns the GTK dialog widget. */
1125
1126 static GtkWidget *
1127 create_dialog (wv, select_cb, deactivate_cb)
1128 widget_value *wv;
1129 GCallback select_cb;
1130 GCallback deactivate_cb;
1131 {
1132 char *title = get_dialog_title (wv->name[0]);
1133 int total_buttons = wv->name[1] - '0';
1134 int right_buttons = wv->name[4] - '0';
1135 int left_buttons;
1136 int button_nr = 0;
1137 int button_spacing = 10;
1138 GtkWidget *wdialog = gtk_dialog_new ();
1139 widget_value *item;
1140 GtkBox *cur_box;
1141 GtkWidget *wvbox;
1142 GtkWidget *whbox_up;
1143 GtkWidget *whbox_down;
1144
1145 /* If the number of buttons is greater than 4, make two rows of buttons
1146 instead. This looks better. */
1147 int make_two_rows = total_buttons > 4;
1148
1149 if (right_buttons == 0) right_buttons = total_buttons/2;
1150 left_buttons = total_buttons - right_buttons;
1151
1152 gtk_window_set_title (GTK_WINDOW (wdialog), title);
1153 gtk_widget_set_name (wdialog, "emacs-dialog");
1154
1155 cur_box = GTK_BOX (GTK_DIALOG (wdialog)->action_area);
1156
1157 if (make_two_rows)
1158 {
1159 wvbox = gtk_vbox_new (TRUE, button_spacing);
1160 whbox_up = gtk_hbox_new (FALSE, 0);
1161 whbox_down = gtk_hbox_new (FALSE, 0);
1162
1163 gtk_box_pack_start (cur_box, wvbox, FALSE, FALSE, 0);
1164 gtk_box_pack_start (GTK_BOX (wvbox), whbox_up, FALSE, FALSE, 0);
1165 gtk_box_pack_start (GTK_BOX (wvbox), whbox_down, FALSE, FALSE, 0);
1166
1167 cur_box = GTK_BOX (whbox_up);
1168 }
1169
1170 g_signal_connect (G_OBJECT (wdialog), "delete-event",
1171 G_CALLBACK (dialog_delete_callback), 0);
1172
1173 if (deactivate_cb)
1174 {
1175 g_signal_connect (G_OBJECT (wdialog), "close", deactivate_cb, 0);
1176 g_signal_connect (G_OBJECT (wdialog), "response", deactivate_cb, 0);
1177 }
1178
1179 for (item = wv->contents; item; item = item->next)
1180 {
1181 char *utf8_label = get_utf8_string (item->value);
1182 GtkWidget *w;
1183 GtkRequisition req;
1184
1185 if (item->name && strcmp (item->name, "message") == 0)
1186 {
1187 /* This is the text part of the dialog. */
1188 w = gtk_label_new (utf8_label);
1189 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (wdialog)->vbox),
1190 gtk_label_new (""),
1191 FALSE, FALSE, 0);
1192 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (wdialog)->vbox), w,
1193 TRUE, TRUE, 0);
1194 gtk_misc_set_alignment (GTK_MISC (w), 0.1, 0.5);
1195
1196 /* Try to make dialog look better. Must realize first so
1197 the widget can calculate the size it needs. */
1198 gtk_widget_realize (w);
1199 gtk_widget_size_request (w, &req);
1200 gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (wdialog)->vbox),
1201 req.height);
1202 if (item->value && strlen (item->value) > 0)
1203 button_spacing = 2*req.width/strlen (item->value);
1204 }
1205 else
1206 {
1207 /* This is one button to add to the dialog. */
1208 w = gtk_button_new_with_label (utf8_label);
1209 if (! item->enabled)
1210 gtk_widget_set_sensitive (w, FALSE);
1211 if (select_cb)
1212 g_signal_connect (G_OBJECT (w), "clicked",
1213 select_cb, item->call_data);
1214
1215 gtk_box_pack_start (cur_box, w, TRUE, TRUE, button_spacing);
1216 if (++button_nr == left_buttons)
1217 {
1218 if (make_two_rows)
1219 cur_box = GTK_BOX (whbox_down);
1220 else
1221 gtk_box_pack_start (cur_box,
1222 gtk_label_new (""),
1223 TRUE, TRUE,
1224 button_spacing);
1225 }
1226 }
1227
1228 if (utf8_label && utf8_label != item->value)
1229 g_free (utf8_label);
1230 }
1231
1232 return wdialog;
1233 }
1234
1235
1236 \f
1237 /***********************************************************************
1238 File dialog functions
1239 ***********************************************************************/
1240 /* Return non-zero if the old file selection dialog is being used.
1241 Return zero if not. */
1242
1243 int
1244 xg_uses_old_file_dialog ()
1245 {
1246 #ifdef HAVE_GTK_FILE_BOTH
1247 extern int x_gtk_use_old_file_dialog;
1248 return x_gtk_use_old_file_dialog;
1249 #else /* ! HAVE_GTK_FILE_BOTH */
1250
1251 #ifdef HAVE_GTK_FILE_SELECTION_NEW
1252 return 1;
1253 #else
1254 return 0;
1255 #endif
1256
1257 #endif /* ! HAVE_GTK_FILE_BOTH */
1258 }
1259
1260
1261 /* Function that is called when the file or font dialogs pop down.
1262 W is the dialog widget, RESPONSE is the response code.
1263 USER_DATA is what we passed in to g_signal_connect (pointer to int). */
1264
1265 static void
1266 xg_dialog_response_cb (w,
1267 response,
1268 user_data)
1269 GtkDialog *w;
1270 gint response;
1271 gpointer user_data;
1272 {
1273 int *ptr = (int *) user_data;
1274 *ptr = response;
1275 }
1276
1277
1278 /* Destroy the dialog. This makes it pop down. */
1279
1280 static Lisp_Object
1281 pop_down_dialog (arg)
1282 Lisp_Object arg;
1283 {
1284 struct Lisp_Save_Value *p = XSAVE_VALUE (arg);
1285 BLOCK_INPUT;
1286 gtk_widget_destroy (GTK_WIDGET (p->pointer));
1287 UNBLOCK_INPUT;
1288 return Qnil;
1289 }
1290
1291 typedef char * (*xg_get_file_func) P_ ((GtkWidget *));
1292
1293 #ifdef HAVE_GTK_FILE_CHOOSER_DIALOG_NEW
1294
1295 /* Return the selected file for file chooser dialog W.
1296 The returned string must be free:d. */
1297
1298 static char *
1299 xg_get_file_name_from_chooser (w)
1300 GtkWidget *w;
1301 {
1302 return gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (w));
1303 }
1304
1305 /* Callback called when the "Show hidden files" toggle is pressed.
1306 WIDGET is the toggle widget, DATA is the file chooser dialog. */
1307
1308 static void
1309 xg_toggle_visibility_cb (widget, data)
1310 GtkWidget *widget;
1311 gpointer data;
1312 {
1313 GtkFileChooser *dialog = GTK_FILE_CHOOSER (data);
1314 gboolean visible;
1315 g_object_get (G_OBJECT (dialog), "show-hidden", &visible, NULL);
1316 g_object_set (G_OBJECT (dialog), "show-hidden", !visible, NULL);
1317 }
1318
1319
1320 /* Callback called when a property changes in a file chooser.
1321 GOBJECT is the file chooser dialog, ARG1 describes the property.
1322 USER_DATA is the toggle widget in the file chooser dialog.
1323 We use this to update the "Show hidden files" toggle when the user
1324 changes that property by right clicking in the file list. */
1325
1326 static void
1327 xg_toggle_notify_cb (gobject, arg1, user_data)
1328 GObject *gobject;
1329 GParamSpec *arg1;
1330 gpointer user_data;
1331 {
1332 extern int x_gtk_show_hidden_files;
1333
1334 if (strcmp (arg1->name, "show-hidden") == 0)
1335 {
1336 GtkFileChooser *dialog = GTK_FILE_CHOOSER (gobject);
1337 GtkWidget *wtoggle = GTK_WIDGET (user_data);
1338 gboolean visible, toggle_on;
1339
1340 g_object_get (G_OBJECT (gobject), "show-hidden", &visible, NULL);
1341 toggle_on = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (wtoggle));
1342
1343 if (!!visible != !!toggle_on)
1344 {
1345 g_signal_handlers_block_by_func (G_OBJECT (wtoggle),
1346 G_CALLBACK (xg_toggle_visibility_cb),
1347 gobject);
1348 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wtoggle), visible);
1349 g_signal_handlers_unblock_by_func
1350 (G_OBJECT (wtoggle),
1351 G_CALLBACK (xg_toggle_visibility_cb),
1352 gobject);
1353 }
1354 x_gtk_show_hidden_files = visible;
1355 }
1356 }
1357
1358 /* Read a file name from the user using a file chooser dialog.
1359 F is the current frame.
1360 PROMPT is a prompt to show to the user. May not be NULL.
1361 DEFAULT_FILENAME is a default selection to be displayed. May be NULL.
1362 If MUSTMATCH_P is non-zero, the returned file name must be an existing
1363 file. *FUNC is set to a function that can be used to retrieve the
1364 selected file name from the returned widget.
1365
1366 Returns the created widget. */
1367
1368 static GtkWidget *
1369 xg_get_file_with_chooser (f, prompt, default_filename,
1370 mustmatch_p, only_dir_p, func)
1371 FRAME_PTR f;
1372 char *prompt;
1373 char *default_filename;
1374 int mustmatch_p, only_dir_p;
1375 xg_get_file_func *func;
1376 {
1377 char message[1024];
1378
1379 GtkWidget *filewin, *wtoggle, *wbox, *wmessage;
1380 GtkWindow *gwin = GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f));
1381 GtkFileChooserAction action = (mustmatch_p ?
1382 GTK_FILE_CHOOSER_ACTION_OPEN :
1383 GTK_FILE_CHOOSER_ACTION_SAVE);
1384 extern int x_gtk_show_hidden_files;
1385 extern int x_gtk_file_dialog_help_text;
1386
1387
1388 if (only_dir_p)
1389 action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
1390
1391 filewin = gtk_file_chooser_dialog_new (prompt, gwin, action,
1392 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1393 (mustmatch_p || only_dir_p ?
1394 GTK_STOCK_OPEN : GTK_STOCK_OK),
1395 GTK_RESPONSE_OK,
1396 NULL);
1397 gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (filewin), TRUE);
1398
1399 wbox = gtk_vbox_new (FALSE, 0);
1400 gtk_widget_show (wbox);
1401 wtoggle = gtk_check_button_new_with_label ("Show hidden files.");
1402
1403 if (x_gtk_show_hidden_files)
1404 {
1405 g_object_set (G_OBJECT (filewin), "show-hidden", TRUE, NULL);
1406 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wtoggle), TRUE);
1407 }
1408 gtk_widget_show (wtoggle);
1409 g_signal_connect (G_OBJECT (wtoggle), "clicked",
1410 G_CALLBACK (xg_toggle_visibility_cb), filewin);
1411 g_signal_connect (G_OBJECT (filewin), "notify",
1412 G_CALLBACK (xg_toggle_notify_cb), wtoggle);
1413
1414 if (x_gtk_file_dialog_help_text)
1415 {
1416 message[0] = '\0';
1417 /* Gtk+ 2.10 has the file name text entry box integrated in the dialog.
1418 Show the C-l help text only for versions < 2.10. */
1419 if (gtk_check_version (2, 10, 0) && action != GTK_FILE_CHOOSER_ACTION_SAVE)
1420 strcat (message, "\nType C-l to display a file name text entry box.\n");
1421 strcat (message, "\nIf you don't like this file selector, use the "
1422 "corresponding\nkey binding or customize "
1423 "use-file-dialog to turn it off.");
1424
1425 wmessage = gtk_label_new (message);
1426 gtk_widget_show (wmessage);
1427 }
1428
1429 gtk_box_pack_start (GTK_BOX (wbox), wtoggle, FALSE, FALSE, 0);
1430 if (x_gtk_file_dialog_help_text)
1431 gtk_box_pack_start (GTK_BOX (wbox), wmessage, FALSE, FALSE, 0);
1432 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (filewin), wbox);
1433
1434 if (default_filename)
1435 {
1436 Lisp_Object file;
1437 struct gcpro gcpro1;
1438 char *utf8_filename;
1439 GCPRO1 (file);
1440
1441 file = build_string (default_filename);
1442
1443 /* File chooser does not understand ~/... in the file name. It must be
1444 an absolute name starting with /. */
1445 if (default_filename[0] != '/')
1446 file = Fexpand_file_name (file, Qnil);
1447
1448 utf8_filename = SSDATA (ENCODE_UTF_8 (file));
1449 if (! NILP (Ffile_directory_p (file)))
1450 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (filewin),
1451 utf8_filename);
1452 else
1453 {
1454 gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (filewin),
1455 utf8_filename);
1456 if (action == GTK_FILE_CHOOSER_ACTION_SAVE)
1457 {
1458 char *cp = strrchr (utf8_filename, '/');
1459 if (cp) ++cp;
1460 else cp = utf8_filename;
1461 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (filewin), cp);
1462 }
1463 }
1464
1465 UNGCPRO;
1466 }
1467
1468 *func = xg_get_file_name_from_chooser;
1469 return filewin;
1470 }
1471 #endif /* HAVE_GTK_FILE_CHOOSER_DIALOG_NEW */
1472
1473 #ifdef HAVE_GTK_FILE_SELECTION_NEW
1474
1475 /* Return the selected file for file selector dialog W.
1476 The returned string must be free:d. */
1477
1478 static char *
1479 xg_get_file_name_from_selector (w)
1480 GtkWidget *w;
1481 {
1482 GtkFileSelection *filesel = GTK_FILE_SELECTION (w);
1483 return xstrdup ((char*) gtk_file_selection_get_filename (filesel));
1484 }
1485
1486 /* Create a file selection dialog.
1487 F is the current frame.
1488 PROMPT is a prompt to show to the user. May not be NULL.
1489 DEFAULT_FILENAME is a default selection to be displayed. May be NULL.
1490 If MUSTMATCH_P is non-zero, the returned file name must be an existing
1491 file. *FUNC is set to a function that can be used to retrieve the
1492 selected file name from the returned widget.
1493
1494 Returns the created widget. */
1495
1496 static GtkWidget *
1497 xg_get_file_with_selection (f, prompt, default_filename,
1498 mustmatch_p, only_dir_p, func)
1499 FRAME_PTR f;
1500 char *prompt;
1501 char *default_filename;
1502 int mustmatch_p, only_dir_p;
1503 xg_get_file_func *func;
1504 {
1505 GtkWidget *filewin;
1506 GtkFileSelection *filesel;
1507
1508 filewin = gtk_file_selection_new (prompt);
1509 filesel = GTK_FILE_SELECTION (filewin);
1510
1511 if (default_filename)
1512 gtk_file_selection_set_filename (filesel, default_filename);
1513
1514 if (mustmatch_p)
1515 {
1516 /* The selection_entry part of filesel is not documented. */
1517 gtk_widget_set_sensitive (filesel->selection_entry, FALSE);
1518 gtk_file_selection_hide_fileop_buttons (filesel);
1519 }
1520
1521 *func = xg_get_file_name_from_selector;
1522
1523 return filewin;
1524 }
1525 #endif /* HAVE_GTK_FILE_SELECTION_NEW */
1526
1527 /* Read a file name from the user using a file dialog, either the old
1528 file selection dialog, or the new file chooser dialog. Which to use
1529 depends on what the GTK version used has, and what the value of
1530 gtk-use-old-file-dialog.
1531 F is the current frame.
1532 PROMPT is a prompt to show to the user. May not be NULL.
1533 DEFAULT_FILENAME is a default selection to be displayed. May be NULL.
1534 If MUSTMATCH_P is non-zero, the returned file name must be an existing
1535 file.
1536
1537 Returns a file name or NULL if no file was selected.
1538 The returned string must be freed by the caller. */
1539
1540 char *
1541 xg_get_file_name (f, prompt, default_filename, mustmatch_p, only_dir_p)
1542 FRAME_PTR f;
1543 char *prompt;
1544 char *default_filename;
1545 int mustmatch_p, only_dir_p;
1546 {
1547 GtkWidget *w = 0;
1548 int count = SPECPDL_INDEX ();
1549 char *fn = 0;
1550 int filesel_done = 0;
1551 xg_get_file_func func;
1552
1553 #if defined (HAVE_GTK_AND_PTHREAD) && defined (__SIGRTMIN)
1554 /* I really don't know why this is needed, but without this the GLIBC add on
1555 library linuxthreads hangs when the Gnome file chooser backend creates
1556 threads. */
1557 sigblock (sigmask (__SIGRTMIN));
1558 #endif /* HAVE_GTK_AND_PTHREAD */
1559
1560 #ifdef HAVE_GTK_FILE_BOTH
1561
1562 if (xg_uses_old_file_dialog ())
1563 w = xg_get_file_with_selection (f, prompt, default_filename,
1564 mustmatch_p, only_dir_p, &func);
1565 else
1566 w = xg_get_file_with_chooser (f, prompt, default_filename,
1567 mustmatch_p, only_dir_p, &func);
1568
1569 #else /* not HAVE_GTK_FILE_BOTH */
1570
1571 #ifdef HAVE_GTK_FILE_SELECTION_NEW
1572 w = xg_get_file_with_selection (f, prompt, default_filename,
1573 mustmatch_p, only_dir_p, &func);
1574 #endif
1575 #ifdef HAVE_GTK_FILE_CHOOSER_DIALOG_NEW
1576 w = xg_get_file_with_chooser (f, prompt, default_filename,
1577 mustmatch_p, only_dir_p, &func);
1578 #endif
1579
1580 #endif /* HAVE_GTK_FILE_BOTH */
1581
1582 xg_set_screen (w, f);
1583 gtk_widget_set_name (w, "emacs-filedialog");
1584 gtk_window_set_transient_for (GTK_WINDOW (w),
1585 GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)));
1586 gtk_window_set_destroy_with_parent (GTK_WINDOW (w), TRUE);
1587 gtk_window_set_modal (GTK_WINDOW (w), TRUE);
1588
1589 g_signal_connect (G_OBJECT (w),
1590 "response",
1591 G_CALLBACK (xg_dialog_response_cb),
1592 &filesel_done);
1593
1594 /* Don't destroy the widget if closed by the window manager close button. */
1595 g_signal_connect (G_OBJECT (w), "delete-event", G_CALLBACK (gtk_true), NULL);
1596
1597 gtk_widget_show (w);
1598
1599 record_unwind_protect (pop_down_dialog, make_save_value (w, 0));
1600 while (! filesel_done)
1601 {
1602 x_menu_wait_for_event (0);
1603 gtk_main_iteration ();
1604 }
1605
1606 #if defined (HAVE_GTK_AND_PTHREAD) && defined (__SIGRTMIN)
1607 sigunblock (sigmask (__SIGRTMIN));
1608 #endif
1609
1610 if (filesel_done == GTK_RESPONSE_OK)
1611 fn = (*func) (w);
1612
1613 unbind_to (count, Qnil);
1614
1615 return fn;
1616 }
1617
1618 #ifdef HAVE_FREETYPE
1619 /* Pop up a GTK font selector and return the name of the font the user
1620 selects, as a C string. The returned font name follows GTK's own
1621 format:
1622
1623 `FAMILY [VALUE1 VALUE2] SIZE'
1624
1625 This can be parsed using font_parse_fcname in font.c.
1626 DEFAULT_NAME, if non-zero, is the default font name. */
1627
1628 char *
1629 xg_get_font_name (f, default_name)
1630 FRAME_PTR f;
1631 char *default_name;
1632 {
1633 GtkWidget *w = 0;
1634 int count = SPECPDL_INDEX ();
1635 char *fontname = NULL;
1636 int done = 0;
1637
1638 #if defined (HAVE_GTK_AND_PTHREAD) && defined (__SIGRTMIN)
1639 sigblock (sigmask (__SIGRTMIN));
1640 #endif /* HAVE_GTK_AND_PTHREAD */
1641
1642 w = gtk_font_selection_dialog_new ("Pick a font");
1643 if (default_name)
1644 gtk_font_selection_dialog_set_font_name (GTK_FONT_SELECTION_DIALOG (w),
1645 default_name);
1646
1647 xg_set_screen (w, f);
1648 gtk_widget_set_name (w, "emacs-fontdialog");
1649 gtk_window_set_transient_for (GTK_WINDOW (w),
1650 GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)));
1651 gtk_window_set_destroy_with_parent (GTK_WINDOW (w), TRUE);
1652 gtk_window_set_modal (GTK_WINDOW (w), TRUE);
1653
1654 g_signal_connect (G_OBJECT (w), "response",
1655 G_CALLBACK (xg_dialog_response_cb), &done);
1656
1657 /* Don't destroy the widget if closed by the window manager close button. */
1658 g_signal_connect (G_OBJECT (w), "delete-event", G_CALLBACK (gtk_true), NULL);
1659
1660 gtk_widget_show (w);
1661
1662 record_unwind_protect (pop_down_dialog, make_save_value (w, 0));
1663 while (!done)
1664 {
1665 x_menu_wait_for_event (0);
1666 gtk_main_iteration ();
1667 }
1668
1669 #if defined (HAVE_GTK_AND_PTHREAD) && defined (__SIGRTMIN)
1670 sigunblock (sigmask (__SIGRTMIN));
1671 #endif
1672
1673 if (done == GTK_RESPONSE_OK)
1674 fontname = gtk_font_selection_dialog_get_font_name
1675 ((GtkFontSelectionDialog *) w);
1676
1677 unbind_to (count, Qnil);
1678
1679 return fontname;
1680 }
1681 #endif /* HAVE_FREETYPE */
1682
1683
1684 \f
1685 /***********************************************************************
1686 Menu functions.
1687 ***********************************************************************/
1688
1689 /* The name of menu items that can be used for customization. Since GTK
1690 RC files are very crude and primitive, we have to set this on all
1691 menu item names so a user can easily customize menu items. */
1692
1693 #define MENU_ITEM_NAME "emacs-menuitem"
1694
1695
1696 /* Linked list of all allocated struct xg_menu_cb_data. Used for marking
1697 during GC. The next member points to the items. */
1698 static xg_list_node xg_menu_cb_list;
1699
1700 /* Linked list of all allocated struct xg_menu_item_cb_data. Used for marking
1701 during GC. The next member points to the items. */
1702 static xg_list_node xg_menu_item_cb_list;
1703
1704 /* Allocate and initialize CL_DATA if NULL, otherwise increase ref_count.
1705 F is the frame CL_DATA will be initialized for.
1706 HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
1707
1708 The menu bar and all sub menus under the menu bar in a frame
1709 share the same structure, hence the reference count.
1710
1711 Returns CL_DATA if CL_DATA is not NULL, or a pointer to a newly
1712 allocated xg_menu_cb_data if CL_DATA is NULL. */
1713
1714 static xg_menu_cb_data *
1715 make_cl_data (cl_data, f, highlight_cb)
1716 xg_menu_cb_data *cl_data;
1717 FRAME_PTR f;
1718 GCallback highlight_cb;
1719 {
1720 if (! cl_data)
1721 {
1722 cl_data = (xg_menu_cb_data*) xmalloc (sizeof (*cl_data));
1723 cl_data->f = f;
1724 cl_data->menu_bar_vector = f->menu_bar_vector;
1725 cl_data->menu_bar_items_used = f->menu_bar_items_used;
1726 cl_data->highlight_cb = highlight_cb;
1727 cl_data->ref_count = 0;
1728
1729 xg_list_insert (&xg_menu_cb_list, &cl_data->ptrs);
1730 }
1731
1732 cl_data->ref_count++;
1733
1734 return cl_data;
1735 }
1736
1737 /* Update CL_DATA with values from frame F and with HIGHLIGHT_CB.
1738 HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
1739
1740 When the menu bar is updated, menu items may have been added and/or
1741 removed, so menu_bar_vector and menu_bar_items_used change. We must
1742 then update CL_DATA since it is used to determine which menu
1743 item that is invoked in the menu.
1744 HIGHLIGHT_CB could change, there is no check that the same
1745 function is given when modifying a menu bar as was given when
1746 creating the menu bar. */
1747
1748 static void
1749 update_cl_data (cl_data, f, highlight_cb)
1750 xg_menu_cb_data *cl_data;
1751 FRAME_PTR f;
1752 GCallback highlight_cb;
1753 {
1754 if (cl_data)
1755 {
1756 cl_data->f = f;
1757 cl_data->menu_bar_vector = f->menu_bar_vector;
1758 cl_data->menu_bar_items_used = f->menu_bar_items_used;
1759 cl_data->highlight_cb = highlight_cb;
1760 }
1761 }
1762
1763 /* Decrease reference count for CL_DATA.
1764 If reference count is zero, free CL_DATA. */
1765
1766 static void
1767 unref_cl_data (cl_data)
1768 xg_menu_cb_data *cl_data;
1769 {
1770 if (cl_data && cl_data->ref_count > 0)
1771 {
1772 cl_data->ref_count--;
1773 if (cl_data->ref_count == 0)
1774 {
1775 xg_list_remove (&xg_menu_cb_list, &cl_data->ptrs);
1776 xfree (cl_data);
1777 }
1778 }
1779 }
1780
1781 /* Function that marks all lisp data during GC. */
1782
1783 void
1784 xg_mark_data ()
1785 {
1786 xg_list_node *iter;
1787
1788 for (iter = xg_menu_cb_list.next; iter; iter = iter->next)
1789 mark_object (((xg_menu_cb_data *) iter)->menu_bar_vector);
1790
1791 for (iter = xg_menu_item_cb_list.next; iter; iter = iter->next)
1792 {
1793 xg_menu_item_cb_data *cb_data = (xg_menu_item_cb_data *) iter;
1794
1795 if (! NILP (cb_data->help))
1796 mark_object (cb_data->help);
1797 }
1798 }
1799
1800
1801 /* Callback called when a menu item is destroyed. Used to free data.
1802 W is the widget that is being destroyed (not used).
1803 CLIENT_DATA points to the xg_menu_item_cb_data associated with the W. */
1804
1805 static void
1806 menuitem_destroy_callback (w, client_data)
1807 GtkWidget *w;
1808 gpointer client_data;
1809 {
1810 if (client_data)
1811 {
1812 xg_menu_item_cb_data *data = (xg_menu_item_cb_data*) client_data;
1813 xg_list_remove (&xg_menu_item_cb_list, &data->ptrs);
1814 xfree (data);
1815 }
1816 }
1817
1818 /* Callback called when the pointer enters/leaves a menu item.
1819 W is the parent of the menu item.
1820 EVENT is either an enter event or leave event.
1821 CLIENT_DATA is not used.
1822
1823 Returns FALSE to tell GTK to keep processing this event. */
1824
1825 static gboolean
1826 menuitem_highlight_callback (w, event, client_data)
1827 GtkWidget *w;
1828 GdkEventCrossing *event;
1829 gpointer client_data;
1830 {
1831 GdkEvent ev;
1832 GtkWidget *subwidget;
1833 xg_menu_item_cb_data *data;
1834
1835 ev.crossing = *event;
1836 subwidget = gtk_get_event_widget (&ev);
1837 data = (xg_menu_item_cb_data *) g_object_get_data (G_OBJECT (subwidget),
1838 XG_ITEM_DATA);
1839 if (data)
1840 {
1841 if (! NILP (data->help) && data->cl_data->highlight_cb)
1842 {
1843 gpointer call_data = event->type == GDK_LEAVE_NOTIFY ? 0 : data;
1844 GtkCallback func = (GtkCallback) data->cl_data->highlight_cb;
1845 (*func) (subwidget, call_data);
1846 }
1847 }
1848
1849 return FALSE;
1850 }
1851
1852 /* Callback called when a menu is destroyed. Used to free data.
1853 W is the widget that is being destroyed (not used).
1854 CLIENT_DATA points to the xg_menu_cb_data associated with W. */
1855
1856 static void
1857 menu_destroy_callback (w, client_data)
1858 GtkWidget *w;
1859 gpointer client_data;
1860 {
1861 unref_cl_data ((xg_menu_cb_data*) client_data);
1862 }
1863
1864 /* Callback called when a menu does a grab or ungrab. That means the
1865 menu has been activated or deactivated.
1866 Used to start a timer so the small timeout the menus in GTK uses before
1867 popping down a menu is seen by Emacs (see xg_process_timeouts above).
1868 W is the widget that does the grab (not used).
1869 UNGRAB_P is TRUE if this is an ungrab, FALSE if it is a grab.
1870 CLIENT_DATA is NULL (not used). */
1871
1872 /* Keep track of total number of grabs. */
1873 static int menu_grab_callback_cnt;
1874
1875 static void
1876 menu_grab_callback (GtkWidget *widget,
1877 gboolean ungrab_p,
1878 gpointer client_data)
1879 {
1880 if (ungrab_p) menu_grab_callback_cnt--;
1881 else menu_grab_callback_cnt++;
1882
1883 if (menu_grab_callback_cnt > 0 && ! xg_timer) xg_start_timer ();
1884 else if (menu_grab_callback_cnt == 0 && xg_timer) xg_stop_timer ();
1885 }
1886
1887 /* Make a GTK widget that contains both UTF8_LABEL and UTF8_KEY (both
1888 must be non-NULL) and can be inserted into a menu item.
1889
1890 Returns the GtkHBox. */
1891
1892 static GtkWidget *
1893 make_widget_for_menu_item (utf8_label, utf8_key)
1894 char *utf8_label;
1895 char *utf8_key;
1896 {
1897 GtkWidget *wlbl;
1898 GtkWidget *wkey;
1899 GtkWidget *wbox;
1900
1901 wbox = gtk_hbox_new (FALSE, 0);
1902 wlbl = gtk_label_new (utf8_label);
1903 wkey = gtk_label_new (utf8_key);
1904
1905 gtk_misc_set_alignment (GTK_MISC (wlbl), 0.0, 0.5);
1906 gtk_misc_set_alignment (GTK_MISC (wkey), 0.0, 0.5);
1907
1908 gtk_box_pack_start (GTK_BOX (wbox), wlbl, TRUE, TRUE, 0);
1909 gtk_box_pack_start (GTK_BOX (wbox), wkey, FALSE, FALSE, 0);
1910
1911 gtk_widget_set_name (wlbl, MENU_ITEM_NAME);
1912 gtk_widget_set_name (wkey, MENU_ITEM_NAME);
1913 gtk_widget_set_name (wbox, MENU_ITEM_NAME);
1914
1915 return wbox;
1916 }
1917
1918 /* Make and return a menu item widget with the key to the right.
1919 UTF8_LABEL is the text for the menu item (GTK uses UTF8 internally).
1920 UTF8_KEY is the text representing the key binding.
1921 ITEM is the widget_value describing the menu item.
1922
1923 GROUP is an in/out parameter. If the menu item to be created is not
1924 part of any radio menu group, *GROUP contains NULL on entry and exit.
1925 If the menu item to be created is part of a radio menu group, on entry
1926 *GROUP contains the group to use, or NULL if this is the first item
1927 in the group. On exit, *GROUP contains the radio item group.
1928
1929 Unfortunately, keys don't line up as nicely as in Motif,
1930 but the MacOS X version doesn't either, so I guess that is OK. */
1931
1932 static GtkWidget *
1933 make_menu_item (utf8_label, utf8_key, item, group)
1934 char *utf8_label;
1935 char *utf8_key;
1936 widget_value *item;
1937 GSList **group;
1938 {
1939 GtkWidget *w;
1940 GtkWidget *wtoadd = 0;
1941
1942 /* It has been observed that some menu items have a NULL name field.
1943 This will lead to this function being called with a NULL utf8_label.
1944 GTK crashes on that so we set a blank label. Why there is a NULL
1945 name remains to be investigated. */
1946 if (! utf8_label) utf8_label = " ";
1947
1948 if (utf8_key)
1949 wtoadd = make_widget_for_menu_item (utf8_label, utf8_key);
1950
1951 if (item->button_type == BUTTON_TYPE_TOGGLE)
1952 {
1953 *group = NULL;
1954 if (utf8_key) w = gtk_check_menu_item_new ();
1955 else w = gtk_check_menu_item_new_with_label (utf8_label);
1956 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w), item->selected);
1957 }
1958 else if (item->button_type == BUTTON_TYPE_RADIO)
1959 {
1960 if (utf8_key) w = gtk_radio_menu_item_new (*group);
1961 else w = gtk_radio_menu_item_new_with_label (*group, utf8_label);
1962 *group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (w));
1963 if (item->selected)
1964 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w), TRUE);
1965 }
1966 else
1967 {
1968 *group = NULL;
1969 if (utf8_key) w = gtk_menu_item_new ();
1970 else w = gtk_menu_item_new_with_label (utf8_label);
1971 }
1972
1973 if (wtoadd) gtk_container_add (GTK_CONTAINER (w), wtoadd);
1974 if (! item->enabled) gtk_widget_set_sensitive (w, FALSE);
1975
1976 return w;
1977 }
1978
1979 /* Return non-zero if LABEL specifies a separator (GTK only has one
1980 separator type) */
1981
1982 static char* separator_names[] = {
1983 "space",
1984 "no-line",
1985 "single-line",
1986 "double-line",
1987 "single-dashed-line",
1988 "double-dashed-line",
1989 "shadow-etched-in",
1990 "shadow-etched-out",
1991 "shadow-etched-in-dash",
1992 "shadow-etched-out-dash",
1993 "shadow-double-etched-in",
1994 "shadow-double-etched-out",
1995 "shadow-double-etched-in-dash",
1996 "shadow-double-etched-out-dash",
1997 0,
1998 };
1999
2000 static int
2001 xg_separator_p (char *label)
2002 {
2003 if (! label) return 0;
2004 else if (strlen (label) > 3
2005 && strncmp (label, "--", 2) == 0
2006 && label[2] != '-')
2007 {
2008 int i;
2009
2010 label += 2;
2011 for (i = 0; separator_names[i]; ++i)
2012 if (strcmp (label, separator_names[i]) == 0)
2013 return 1;
2014 }
2015 else
2016 {
2017 /* Old-style separator, maybe. It's a separator if it contains
2018 only dashes. */
2019 while (*label == '-')
2020 ++label;
2021 if (*label == 0) return 1;
2022 }
2023
2024 return 0;
2025 }
2026
2027 static int xg_detached_menus;
2028
2029 /* Returns non-zero if there are detached menus. */
2030
2031 int
2032 xg_have_tear_offs ()
2033 {
2034 return xg_detached_menus > 0;
2035 }
2036
2037 /* Callback invoked when a detached menu window is removed. Here we
2038 decrease the xg_detached_menus count.
2039 WIDGET is the top level window that is removed (the parent of the menu).
2040 CLIENT_DATA is not used. */
2041
2042 static void
2043 tearoff_remove (widget, client_data)
2044 GtkWidget *widget;
2045 gpointer client_data;
2046 {
2047 if (xg_detached_menus > 0) --xg_detached_menus;
2048 }
2049
2050 /* Callback invoked when a menu is detached. It increases the
2051 xg_detached_menus count.
2052 WIDGET is the GtkTearoffMenuItem.
2053 CLIENT_DATA is not used. */
2054
2055 static void
2056 tearoff_activate (widget, client_data)
2057 GtkWidget *widget;
2058 gpointer client_data;
2059 {
2060 GtkWidget *menu = gtk_widget_get_parent (widget);
2061 if (gtk_menu_get_tearoff_state (GTK_MENU (menu)))
2062 {
2063 ++xg_detached_menus;
2064 g_signal_connect (G_OBJECT (gtk_widget_get_toplevel (widget)),
2065 "destroy",
2066 G_CALLBACK (tearoff_remove), 0);
2067 }
2068 }
2069
2070
2071 /* Create a menu item widget, and connect the callbacks.
2072 ITEM decribes the menu item.
2073 F is the frame the created menu belongs to.
2074 SELECT_CB is the callback to use when a menu item is selected.
2075 HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
2076 CL_DATA points to the callback data to be used for this menu.
2077 GROUP is an in/out parameter. If the menu item to be created is not
2078 part of any radio menu group, *GROUP contains NULL on entry and exit.
2079 If the menu item to be created is part of a radio menu group, on entry
2080 *GROUP contains the group to use, or NULL if this is the first item
2081 in the group. On exit, *GROUP contains the radio item group.
2082
2083 Returns the created GtkWidget. */
2084
2085 static GtkWidget *
2086 xg_create_one_menuitem (item, f, select_cb, highlight_cb, cl_data, group)
2087 widget_value *item;
2088 FRAME_PTR f;
2089 GCallback select_cb;
2090 GCallback highlight_cb;
2091 xg_menu_cb_data *cl_data;
2092 GSList **group;
2093 {
2094 char *utf8_label;
2095 char *utf8_key;
2096 GtkWidget *w;
2097 xg_menu_item_cb_data *cb_data;
2098
2099 utf8_label = get_utf8_string (item->name);
2100 utf8_key = get_utf8_string (item->key);
2101
2102 w = make_menu_item (utf8_label, utf8_key, item, group);
2103
2104 if (utf8_label && utf8_label != item->name) g_free (utf8_label);
2105 if (utf8_key && utf8_key != item->key) g_free (utf8_key);
2106
2107 cb_data = xmalloc (sizeof (xg_menu_item_cb_data));
2108
2109 xg_list_insert (&xg_menu_item_cb_list, &cb_data->ptrs);
2110
2111 cb_data->select_id = 0;
2112 cb_data->help = item->help;
2113 cb_data->cl_data = cl_data;
2114 cb_data->call_data = item->call_data;
2115
2116 g_signal_connect (G_OBJECT (w),
2117 "destroy",
2118 G_CALLBACK (menuitem_destroy_callback),
2119 cb_data);
2120
2121 /* Put cb_data in widget, so we can get at it when modifying menubar */
2122 g_object_set_data (G_OBJECT (w), XG_ITEM_DATA, cb_data);
2123
2124 /* final item, not a submenu */
2125 if (item->call_data && ! item->contents)
2126 {
2127 if (select_cb)
2128 cb_data->select_id
2129 = g_signal_connect (G_OBJECT (w), "activate", select_cb, cb_data);
2130 }
2131
2132 return w;
2133 }
2134
2135 static GtkWidget *create_menus P_ ((widget_value *, FRAME_PTR, GCallback,
2136 GCallback, GCallback, int, int, int,
2137 GtkWidget *, xg_menu_cb_data *, char *));
2138
2139 /* Create a full menu tree specified by DATA.
2140 F is the frame the created menu belongs to.
2141 SELECT_CB is the callback to use when a menu item is selected.
2142 DEACTIVATE_CB is the callback to use when a sub menu is not shown anymore.
2143 HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
2144 POP_UP_P is non-zero if we shall create a popup menu.
2145 MENU_BAR_P is non-zero if we shall create a menu bar.
2146 ADD_TEAROFF_P is non-zero if we shall add a teroff menu item. Ignored
2147 if MENU_BAR_P is non-zero.
2148 TOPMENU is the topmost GtkWidget that others shall be placed under.
2149 It may be NULL, in that case we create the appropriate widget
2150 (menu bar or menu item depending on POP_UP_P and MENU_BAR_P)
2151 CL_DATA is the callback data we shall use for this menu, or NULL
2152 if we haven't set the first callback yet.
2153 NAME is the name to give to the top level menu if this function
2154 creates it. May be NULL to not set any name.
2155
2156 Returns the top level GtkWidget. This is TOPLEVEL if TOPLEVEL is
2157 not NULL.
2158
2159 This function calls itself to create submenus. */
2160
2161 static GtkWidget *
2162 create_menus (data, f, select_cb, deactivate_cb, highlight_cb,
2163 pop_up_p, menu_bar_p, add_tearoff_p, topmenu, cl_data, name)
2164 widget_value *data;
2165 FRAME_PTR f;
2166 GCallback select_cb;
2167 GCallback deactivate_cb;
2168 GCallback highlight_cb;
2169 int pop_up_p;
2170 int menu_bar_p;
2171 int add_tearoff_p;
2172 GtkWidget *topmenu;
2173 xg_menu_cb_data *cl_data;
2174 char *name;
2175 {
2176 widget_value *item;
2177 GtkWidget *wmenu = topmenu;
2178 GSList *group = NULL;
2179
2180 if (! topmenu)
2181 {
2182 if (! menu_bar_p)
2183 {
2184 wmenu = gtk_menu_new ();
2185 xg_set_screen (wmenu, f);
2186 /* Connect this to the menu instead of items so we get enter/leave for
2187 disabled items also. TODO: Still does not get enter/leave for
2188 disabled items in detached menus. */
2189 g_signal_connect (G_OBJECT (wmenu),
2190 "enter-notify-event",
2191 G_CALLBACK (menuitem_highlight_callback),
2192 NULL);
2193 g_signal_connect (G_OBJECT (wmenu),
2194 "leave-notify-event",
2195 G_CALLBACK (menuitem_highlight_callback),
2196 NULL);
2197 }
2198 else
2199 {
2200 wmenu = gtk_menu_bar_new ();
2201 // Set width of menu bar to a small value so it doesn't enlarge
2202 // a small initial frame size. The width will be set to the
2203 // width of the frame later on when it is added to a container.
2204 // height -1: Natural height.
2205 gtk_widget_set_size_request (wmenu, 1, -1);
2206 }
2207
2208 /* Put cl_data on the top menu for easier access. */
2209 cl_data = make_cl_data (cl_data, f, highlight_cb);
2210 g_object_set_data (G_OBJECT (wmenu), XG_FRAME_DATA, (gpointer)cl_data);
2211 g_signal_connect (G_OBJECT (wmenu), "destroy",
2212 G_CALLBACK (menu_destroy_callback), cl_data);
2213
2214 if (name)
2215 gtk_widget_set_name (wmenu, name);
2216
2217 if (deactivate_cb)
2218 g_signal_connect (G_OBJECT (wmenu),
2219 "selection-done", deactivate_cb, 0);
2220
2221 g_signal_connect (G_OBJECT (wmenu),
2222 "grab-notify", G_CALLBACK (menu_grab_callback), 0);
2223 }
2224
2225 if (! menu_bar_p && add_tearoff_p)
2226 {
2227 GtkWidget *tearoff = gtk_tearoff_menu_item_new ();
2228 gtk_menu_shell_append (GTK_MENU_SHELL (wmenu), tearoff);
2229
2230 g_signal_connect (G_OBJECT (tearoff), "activate",
2231 G_CALLBACK (tearoff_activate), 0);
2232 }
2233
2234 for (item = data; item; item = item->next)
2235 {
2236 GtkWidget *w;
2237
2238 if (pop_up_p && !item->contents && !item->call_data
2239 && !xg_separator_p (item->name))
2240 {
2241 char *utf8_label;
2242 /* A title for a popup. We do the same as GTK does when
2243 creating titles, but it does not look good. */
2244 group = NULL;
2245 utf8_label = get_utf8_string (item->name);
2246
2247 gtk_menu_set_title (GTK_MENU (wmenu), utf8_label);
2248 w = gtk_menu_item_new_with_label (utf8_label);
2249 gtk_widget_set_sensitive (w, FALSE);
2250 if (utf8_label && utf8_label != item->name) g_free (utf8_label);
2251 }
2252 else if (xg_separator_p (item->name))
2253 {
2254 group = NULL;
2255 /* GTK only have one separator type. */
2256 w = gtk_separator_menu_item_new ();
2257 }
2258 else
2259 {
2260 w = xg_create_one_menuitem (item,
2261 f,
2262 item->contents ? 0 : select_cb,
2263 highlight_cb,
2264 cl_data,
2265 &group);
2266
2267 /* Create a possibly empty submenu for menu bar items, since some
2268 themes don't highlight items correctly without it. */
2269 if (item->contents || menu_bar_p)
2270 {
2271 GtkWidget *submenu = create_menus (item->contents,
2272 f,
2273 select_cb,
2274 deactivate_cb,
2275 highlight_cb,
2276 0,
2277 0,
2278 add_tearoff_p,
2279 0,
2280 cl_data,
2281 0);
2282 gtk_menu_item_set_submenu (GTK_MENU_ITEM (w), submenu);
2283 }
2284 }
2285
2286 gtk_menu_shell_append (GTK_MENU_SHELL (wmenu), w);
2287 gtk_widget_set_name (w, MENU_ITEM_NAME);
2288 }
2289
2290 return wmenu;
2291 }
2292
2293 /* Create a menubar, popup menu or dialog, depending on the TYPE argument.
2294 TYPE can be "menubar", "popup" for popup menu, or "dialog" for a dialog
2295 with some text and buttons.
2296 F is the frame the created item belongs to.
2297 NAME is the name to use for the top widget.
2298 VAL is a widget_value structure describing items to be created.
2299 SELECT_CB is the callback to use when a menu item is selected or
2300 a dialog button is pressed.
2301 DEACTIVATE_CB is the callback to use when an item is deactivated.
2302 For a menu, when a sub menu is not shown anymore, for a dialog it is
2303 called when the dialog is popped down.
2304 HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
2305
2306 Returns the widget created. */
2307
2308 GtkWidget *
2309 xg_create_widget (type, name, f, val,
2310 select_cb, deactivate_cb, highlight_cb)
2311 char *type;
2312 char *name;
2313 FRAME_PTR f;
2314 widget_value *val;
2315 GCallback select_cb;
2316 GCallback deactivate_cb;
2317 GCallback highlight_cb;
2318 {
2319 GtkWidget *w = 0;
2320 int menu_bar_p = strcmp (type, "menubar") == 0;
2321 int pop_up_p = strcmp (type, "popup") == 0;
2322
2323 if (strcmp (type, "dialog") == 0)
2324 {
2325 w = create_dialog (val, select_cb, deactivate_cb);
2326 xg_set_screen (w, f);
2327 gtk_window_set_transient_for (GTK_WINDOW (w),
2328 GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)));
2329 gtk_window_set_destroy_with_parent (GTK_WINDOW (w), TRUE);
2330 gtk_widget_set_name (w, "emacs-dialog");
2331 gtk_window_set_modal (GTK_WINDOW (w), TRUE);
2332 }
2333 else if (menu_bar_p || pop_up_p)
2334 {
2335 w = create_menus (val->contents,
2336 f,
2337 select_cb,
2338 deactivate_cb,
2339 highlight_cb,
2340 pop_up_p,
2341 menu_bar_p,
2342 menu_bar_p,
2343 0,
2344 0,
2345 name);
2346
2347 /* Set the cursor to an arrow for popup menus when they are mapped.
2348 This is done by default for menu bar menus. */
2349 if (pop_up_p)
2350 {
2351 /* Must realize so the GdkWindow inside the widget is created. */
2352 gtk_widget_realize (w);
2353 xg_set_cursor (w, FRAME_X_DISPLAY_INFO (f)->xg_cursor);
2354 }
2355 }
2356 else
2357 {
2358 fprintf (stderr, "bad type in xg_create_widget: %s, doing nothing\n",
2359 type);
2360 }
2361
2362 return w;
2363 }
2364
2365 /* Return the label for menu item WITEM. */
2366
2367 static const char *
2368 xg_get_menu_item_label (witem)
2369 GtkMenuItem *witem;
2370 {
2371 GtkLabel *wlabel = GTK_LABEL (gtk_bin_get_child (GTK_BIN (witem)));
2372 return gtk_label_get_label (wlabel);
2373 }
2374
2375 /* Return non-zero if the menu item WITEM has the text LABEL. */
2376
2377 static int
2378 xg_item_label_same_p (witem, label)
2379 GtkMenuItem *witem;
2380 char *label;
2381 {
2382 int is_same = 0;
2383 char *utf8_label = get_utf8_string (label);
2384 const char *old_label = witem ? xg_get_menu_item_label (witem) : 0;
2385
2386 if (! old_label && ! utf8_label)
2387 is_same = 1;
2388 else if (old_label && utf8_label)
2389 is_same = strcmp (utf8_label, old_label) == 0;
2390
2391 if (utf8_label && utf8_label != label) g_free (utf8_label);
2392
2393 return is_same;
2394 }
2395
2396 /* Destroy widgets in LIST. */
2397
2398 static void
2399 xg_destroy_widgets (list)
2400 GList *list;
2401 {
2402 GList *iter;
2403
2404 for (iter = list; iter; iter = g_list_next (iter))
2405 {
2406 GtkWidget *w = GTK_WIDGET (iter->data);
2407
2408 /* Destroying the widget will remove it from the container it is in. */
2409 gtk_widget_destroy (w);
2410 }
2411 }
2412
2413 /* Update the top level names in MENUBAR (i.e. not submenus).
2414 F is the frame the menu bar belongs to.
2415 *LIST is a list with the current menu bar names (menu item widgets).
2416 ITER is the item within *LIST that shall be updated.
2417 POS is the numerical position, starting at 0, of ITER in *LIST.
2418 VAL describes what the menu bar shall look like after the update.
2419 SELECT_CB is the callback to use when a menu item is selected.
2420 HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
2421 CL_DATA points to the callback data to be used for this menu bar.
2422
2423 This function calls itself to walk through the menu bar names. */
2424
2425 static void
2426 xg_update_menubar (menubar, f, list, iter, pos, val,
2427 select_cb, deactivate_cb, highlight_cb, cl_data)
2428 GtkWidget *menubar;
2429 FRAME_PTR f;
2430 GList **list;
2431 GList *iter;
2432 int pos;
2433 widget_value *val;
2434 GCallback select_cb;
2435 GCallback deactivate_cb;
2436 GCallback highlight_cb;
2437 xg_menu_cb_data *cl_data;
2438 {
2439 if (! iter && ! val)
2440 return;
2441 else if (iter && ! val)
2442 {
2443 /* Item(s) have been removed. Remove all remaining items. */
2444 xg_destroy_widgets (iter);
2445
2446 /* All updated. */
2447 val = 0;
2448 iter = 0;
2449 }
2450 else if (! iter && val)
2451 {
2452 /* Item(s) added. Add all new items in one call. */
2453 create_menus (val, f, select_cb, deactivate_cb, highlight_cb,
2454 0, 1, 0, menubar, cl_data, 0);
2455
2456 /* All updated. */
2457 val = 0;
2458 iter = 0;
2459 }
2460 /* Below this neither iter or val is NULL */
2461 else if (xg_item_label_same_p (GTK_MENU_ITEM (iter->data), val->name))
2462 {
2463 /* This item is still the same, check next item. */
2464 val = val->next;
2465 iter = g_list_next (iter);
2466 ++pos;
2467 }
2468 else /* This item is changed. */
2469 {
2470 GtkMenuItem *witem = GTK_MENU_ITEM (iter->data);
2471 GtkMenuItem *witem2 = 0;
2472 int val_in_menubar = 0;
2473 int iter_in_new_menubar = 0;
2474 GList *iter2;
2475 widget_value *cur;
2476
2477 /* See if the changed entry (val) is present later in the menu bar */
2478 for (iter2 = iter;
2479 iter2 && ! val_in_menubar;
2480 iter2 = g_list_next (iter2))
2481 {
2482 witem2 = GTK_MENU_ITEM (iter2->data);
2483 val_in_menubar = xg_item_label_same_p (witem2, val->name);
2484 }
2485
2486 /* See if the current entry (iter) is present later in the
2487 specification for the new menu bar. */
2488 for (cur = val; cur && ! iter_in_new_menubar; cur = cur->next)
2489 iter_in_new_menubar = xg_item_label_same_p (witem, cur->name);
2490
2491 if (val_in_menubar && ! iter_in_new_menubar)
2492 {
2493 int nr = pos;
2494
2495 /* This corresponds to:
2496 Current: A B C
2497 New: A C
2498 Remove B. */
2499
2500 gtk_widget_ref (GTK_WIDGET (witem));
2501 gtk_container_remove (GTK_CONTAINER (menubar), GTK_WIDGET (witem));
2502 gtk_widget_destroy (GTK_WIDGET (witem));
2503
2504 /* Must get new list since the old changed. */
2505 g_list_free (*list);
2506 *list = iter = gtk_container_get_children (GTK_CONTAINER (menubar));
2507 while (nr-- > 0) iter = g_list_next (iter);
2508 }
2509 else if (! val_in_menubar && ! iter_in_new_menubar)
2510 {
2511 /* This corresponds to:
2512 Current: A B C
2513 New: A X C
2514 Rename B to X. This might seem to be a strange thing to do,
2515 since if there is a menu under B it will be totally wrong for X.
2516 But consider editing a C file. Then there is a C-mode menu
2517 (corresponds to B above).
2518 If then doing C-x C-f the minibuf menu (X above) replaces the
2519 C-mode menu. When returning from the minibuffer, we get
2520 back the C-mode menu. Thus we do:
2521 Rename B to X (C-mode to minibuf menu)
2522 Rename X to B (minibuf to C-mode menu).
2523 If the X menu hasn't been invoked, the menu under B
2524 is up to date when leaving the minibuffer. */
2525 GtkLabel *wlabel = GTK_LABEL (gtk_bin_get_child (GTK_BIN (witem)));
2526 char *utf8_label = get_utf8_string (val->name);
2527 GtkWidget *submenu = gtk_menu_item_get_submenu (witem);
2528
2529 gtk_label_set_text (wlabel, utf8_label);
2530
2531 /* If this item has a submenu that has been detached, change
2532 the title in the WM decorations also. */
2533 if (submenu && gtk_menu_get_tearoff_state (GTK_MENU (submenu)))
2534 /* Set the title of the detached window. */
2535 gtk_menu_set_title (GTK_MENU (submenu), utf8_label);
2536
2537 iter = g_list_next (iter);
2538 val = val->next;
2539 ++pos;
2540 }
2541 else if (! val_in_menubar && iter_in_new_menubar)
2542 {
2543 /* This corresponds to:
2544 Current: A B C
2545 New: A X B C
2546 Insert X. */
2547
2548 int nr = pos;
2549 GList *group = 0;
2550 GtkWidget *w = xg_create_one_menuitem (val,
2551 f,
2552 select_cb,
2553 highlight_cb,
2554 cl_data,
2555 &group);
2556
2557 /* Create a possibly empty submenu for menu bar items, since some
2558 themes don't highlight items correctly without it. */
2559 GtkWidget *submenu = create_menus (NULL, f,
2560 select_cb, deactivate_cb,
2561 highlight_cb,
2562 0, 0, 0, 0, cl_data, 0);
2563 gtk_widget_set_name (w, MENU_ITEM_NAME);
2564 gtk_menu_shell_insert (GTK_MENU_SHELL (menubar), w, pos);
2565 gtk_menu_item_set_submenu (GTK_MENU_ITEM (w), submenu);
2566
2567 g_list_free (*list);
2568 *list = iter = gtk_container_get_children (GTK_CONTAINER (menubar));
2569 while (nr-- > 0) iter = g_list_next (iter);
2570 iter = g_list_next (iter);
2571 val = val->next;
2572 ++pos;
2573 }
2574 else /* if (val_in_menubar && iter_in_new_menubar) */
2575 {
2576 int nr = pos;
2577 /* This corresponds to:
2578 Current: A B C
2579 New: A C B
2580 Move C before B */
2581
2582 gtk_widget_ref (GTK_WIDGET (witem2));
2583 gtk_container_remove (GTK_CONTAINER (menubar), GTK_WIDGET (witem2));
2584 gtk_menu_shell_insert (GTK_MENU_SHELL (menubar),
2585 GTK_WIDGET (witem2), pos);
2586 gtk_widget_unref (GTK_WIDGET (witem2));
2587
2588 g_list_free (*list);
2589 *list = iter = gtk_container_get_children (GTK_CONTAINER (menubar));
2590 while (nr-- > 0) iter = g_list_next (iter);
2591 if (iter) iter = g_list_next (iter);
2592 val = val->next;
2593 ++pos;
2594 }
2595 }
2596
2597 /* Update the rest of the menu bar. */
2598 xg_update_menubar (menubar, f, list, iter, pos, val,
2599 select_cb, deactivate_cb, highlight_cb, cl_data);
2600 }
2601
2602 /* Update the menu item W so it corresponds to VAL.
2603 SELECT_CB is the callback to use when a menu item is selected.
2604 HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
2605 CL_DATA is the data to set in the widget for menu invocation. */
2606
2607 static void
2608 xg_update_menu_item (val, w, select_cb, highlight_cb, cl_data)
2609 widget_value *val;
2610 GtkWidget *w;
2611 GCallback select_cb;
2612 GCallback highlight_cb;
2613 xg_menu_cb_data *cl_data;
2614 {
2615 GtkWidget *wchild;
2616 GtkLabel *wlbl = 0;
2617 GtkLabel *wkey = 0;
2618 char *utf8_label;
2619 char *utf8_key;
2620 const char *old_label = 0;
2621 const char *old_key = 0;
2622 xg_menu_item_cb_data *cb_data;
2623
2624 wchild = gtk_bin_get_child (GTK_BIN (w));
2625 utf8_label = get_utf8_string (val->name);
2626 utf8_key = get_utf8_string (val->key);
2627
2628 /* See if W is a menu item with a key. See make_menu_item above. */
2629 if (GTK_IS_HBOX (wchild))
2630 {
2631 GList *list = gtk_container_get_children (GTK_CONTAINER (wchild));
2632
2633 wlbl = GTK_LABEL (list->data);
2634 wkey = GTK_LABEL (list->next->data);
2635 g_list_free (list);
2636
2637 if (! utf8_key)
2638 {
2639 /* Remove the key and keep just the label. */
2640 gtk_widget_ref (GTK_WIDGET (wlbl));
2641 gtk_container_remove (GTK_CONTAINER (w), wchild);
2642 gtk_container_add (GTK_CONTAINER (w), GTK_WIDGET (wlbl));
2643 wkey = 0;
2644 }
2645
2646 }
2647 else /* Just a label. */
2648 {
2649 wlbl = GTK_LABEL (wchild);
2650
2651 /* Check if there is now a key. */
2652 if (utf8_key)
2653 {
2654 GtkWidget *wtoadd = make_widget_for_menu_item (utf8_label, utf8_key);
2655 GList *list = gtk_container_get_children (GTK_CONTAINER (wtoadd));
2656
2657 wlbl = GTK_LABEL (list->data);
2658 wkey = GTK_LABEL (list->next->data);
2659 g_list_free (list);
2660
2661 gtk_container_remove (GTK_CONTAINER (w), wchild);
2662 gtk_container_add (GTK_CONTAINER (w), wtoadd);
2663 }
2664 }
2665
2666
2667 if (wkey) old_key = gtk_label_get_label (wkey);
2668 if (wlbl) old_label = gtk_label_get_label (wlbl);
2669
2670 if (wkey && utf8_key && (! old_key || strcmp (utf8_key, old_key) != 0))
2671 gtk_label_set_text (wkey, utf8_key);
2672
2673 if (! old_label || strcmp (utf8_label, old_label) != 0)
2674 gtk_label_set_text (wlbl, utf8_label);
2675
2676 if (utf8_key && utf8_key != val->key) g_free (utf8_key);
2677 if (utf8_label && utf8_label != val->name) g_free (utf8_label);
2678
2679 if (! val->enabled && GTK_WIDGET_SENSITIVE (w))
2680 gtk_widget_set_sensitive (w, FALSE);
2681 else if (val->enabled && ! GTK_WIDGET_SENSITIVE (w))
2682 gtk_widget_set_sensitive (w, TRUE);
2683
2684 cb_data = (xg_menu_item_cb_data*) g_object_get_data (G_OBJECT (w),
2685 XG_ITEM_DATA);
2686 if (cb_data)
2687 {
2688 cb_data->call_data = val->call_data;
2689 cb_data->help = val->help;
2690 cb_data->cl_data = cl_data;
2691
2692 /* We assume the callback functions don't change. */
2693 if (val->call_data && ! val->contents)
2694 {
2695 /* This item shall have a select callback. */
2696 if (! cb_data->select_id)
2697 cb_data->select_id
2698 = g_signal_connect (G_OBJECT (w), "activate",
2699 select_cb, cb_data);
2700 }
2701 else if (cb_data->select_id)
2702 {
2703 g_signal_handler_disconnect (w, cb_data->select_id);
2704 cb_data->select_id = 0;
2705 }
2706 }
2707 }
2708
2709 /* Update the toggle menu item W so it corresponds to VAL. */
2710
2711 static void
2712 xg_update_toggle_item (val, w)
2713 widget_value *val;
2714 GtkWidget *w;
2715 {
2716 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w), val->selected);
2717 }
2718
2719 /* Update the radio menu item W so it corresponds to VAL. */
2720
2721 static void
2722 xg_update_radio_item (val, w)
2723 widget_value *val;
2724 GtkWidget *w;
2725 {
2726 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w), val->selected);
2727 }
2728
2729 /* Update the sub menu SUBMENU and all its children so it corresponds to VAL.
2730 SUBMENU may be NULL, in that case a new menu is created.
2731 F is the frame the menu bar belongs to.
2732 VAL describes the contents of the menu bar.
2733 SELECT_CB is the callback to use when a menu item is selected.
2734 DEACTIVATE_CB is the callback to use when a sub menu is not shown anymore.
2735 HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
2736 CL_DATA is the call back data to use for any newly created items.
2737
2738 Returns the updated submenu widget, that is SUBMENU unless SUBMENU
2739 was NULL. */
2740
2741 static GtkWidget *
2742 xg_update_submenu (submenu, f, val,
2743 select_cb, deactivate_cb, highlight_cb, cl_data)
2744 GtkWidget *submenu;
2745 FRAME_PTR f;
2746 widget_value *val;
2747 GCallback select_cb;
2748 GCallback deactivate_cb;
2749 GCallback highlight_cb;
2750 xg_menu_cb_data *cl_data;
2751 {
2752 GtkWidget *newsub = submenu;
2753 GList *list = 0;
2754 GList *iter;
2755 widget_value *cur;
2756 int has_tearoff_p = 0;
2757 GList *first_radio = 0;
2758
2759 if (submenu)
2760 list = gtk_container_get_children (GTK_CONTAINER (submenu));
2761
2762 for (cur = val, iter = list;
2763 cur && iter;
2764 iter = g_list_next (iter), cur = cur->next)
2765 {
2766 GtkWidget *w = GTK_WIDGET (iter->data);
2767
2768 /* Skip tearoff items, they have no counterpart in val. */
2769 if (GTK_IS_TEAROFF_MENU_ITEM (w))
2770 {
2771 has_tearoff_p = 1;
2772 iter = g_list_next (iter);
2773 if (iter) w = GTK_WIDGET (iter->data);
2774 else break;
2775 }
2776
2777 /* Remember first radio button in a group. If we get a mismatch in
2778 a radio group we must rebuild the whole group so that the connections
2779 in GTK becomes correct. */
2780 if (cur->button_type == BUTTON_TYPE_RADIO && ! first_radio)
2781 first_radio = iter;
2782 else if (cur->button_type != BUTTON_TYPE_RADIO
2783 && ! GTK_IS_RADIO_MENU_ITEM (w))
2784 first_radio = 0;
2785
2786 if (GTK_IS_SEPARATOR_MENU_ITEM (w))
2787 {
2788 if (! xg_separator_p (cur->name))
2789 break;
2790 }
2791 else if (GTK_IS_CHECK_MENU_ITEM (w))
2792 {
2793 if (cur->button_type != BUTTON_TYPE_TOGGLE)
2794 break;
2795 xg_update_toggle_item (cur, w);
2796 xg_update_menu_item (cur, w, select_cb, highlight_cb, cl_data);
2797 }
2798 else if (GTK_IS_RADIO_MENU_ITEM (w))
2799 {
2800 if (cur->button_type != BUTTON_TYPE_RADIO)
2801 break;
2802 xg_update_radio_item (cur, w);
2803 xg_update_menu_item (cur, w, select_cb, highlight_cb, cl_data);
2804 }
2805 else if (GTK_IS_MENU_ITEM (w))
2806 {
2807 GtkMenuItem *witem = GTK_MENU_ITEM (w);
2808 GtkWidget *sub;
2809
2810 if (cur->button_type != BUTTON_TYPE_NONE ||
2811 xg_separator_p (cur->name))
2812 break;
2813
2814 xg_update_menu_item (cur, w, select_cb, highlight_cb, cl_data);
2815
2816 sub = gtk_menu_item_get_submenu (witem);
2817 if (sub && ! cur->contents)
2818 {
2819 /* Not a submenu anymore. */
2820 gtk_widget_ref (sub);
2821 gtk_menu_item_remove_submenu (witem);
2822 gtk_widget_destroy (sub);
2823 }
2824 else if (cur->contents)
2825 {
2826 GtkWidget *nsub;
2827
2828 nsub = xg_update_submenu (sub, f, cur->contents,
2829 select_cb, deactivate_cb,
2830 highlight_cb, cl_data);
2831
2832 /* If this item just became a submenu, we must set it. */
2833 if (nsub != sub)
2834 gtk_menu_item_set_submenu (witem, nsub);
2835 }
2836 }
2837 else
2838 {
2839 /* Structural difference. Remove everything from here and down
2840 in SUBMENU. */
2841 break;
2842 }
2843 }
2844
2845 /* Remove widgets from first structual change. */
2846 if (iter)
2847 {
2848 /* If we are adding new menu items below, we must remove from
2849 first radio button so that radio groups become correct. */
2850 if (cur && first_radio) xg_destroy_widgets (first_radio);
2851 else xg_destroy_widgets (iter);
2852 }
2853
2854 if (cur)
2855 {
2856 /* More items added. Create them. */
2857 newsub = create_menus (cur,
2858 f,
2859 select_cb,
2860 deactivate_cb,
2861 highlight_cb,
2862 0,
2863 0,
2864 ! has_tearoff_p,
2865 submenu,
2866 cl_data,
2867 0);
2868 }
2869
2870 if (list) g_list_free (list);
2871
2872 return newsub;
2873 }
2874
2875 /* Update the MENUBAR.
2876 F is the frame the menu bar belongs to.
2877 VAL describes the contents of the menu bar.
2878 If DEEP_P is non-zero, rebuild all but the top level menu names in
2879 the MENUBAR. If DEEP_P is zero, just rebuild the names in the menubar.
2880 SELECT_CB is the callback to use when a menu item is selected.
2881 DEACTIVATE_CB is the callback to use when a sub menu is not shown anymore.
2882 HIGHLIGHT_CB is the callback to call when entering/leaving menu items. */
2883
2884 void
2885 xg_modify_menubar_widgets (menubar, f, val, deep_p,
2886 select_cb, deactivate_cb, highlight_cb)
2887 GtkWidget *menubar;
2888 FRAME_PTR f;
2889 widget_value *val;
2890 int deep_p;
2891 GCallback select_cb;
2892 GCallback deactivate_cb;
2893 GCallback highlight_cb;
2894 {
2895 xg_menu_cb_data *cl_data;
2896 GList *list = gtk_container_get_children (GTK_CONTAINER (menubar));
2897
2898 if (! list) return;
2899
2900 cl_data = (xg_menu_cb_data*) g_object_get_data (G_OBJECT (menubar),
2901 XG_FRAME_DATA);
2902
2903 xg_update_menubar (menubar, f, &list, list, 0, val->contents,
2904 select_cb, deactivate_cb, highlight_cb, cl_data);
2905
2906 if (deep_p)
2907 {
2908 widget_value *cur;
2909
2910 /* Update all sub menus.
2911 We must keep the submenus (GTK menu item widgets) since the
2912 X Window in the XEvent that activates the menu are those widgets. */
2913
2914 /* Update cl_data, menu_item things in F may have changed. */
2915 update_cl_data (cl_data, f, highlight_cb);
2916
2917 for (cur = val->contents; cur; cur = cur->next)
2918 {
2919 GList *iter;
2920 GtkWidget *sub = 0;
2921 GtkWidget *newsub;
2922 GtkMenuItem *witem;
2923
2924 /* Find sub menu that corresponds to val and update it. */
2925 for (iter = list ; iter; iter = g_list_next (iter))
2926 {
2927 witem = GTK_MENU_ITEM (iter->data);
2928 if (xg_item_label_same_p (witem, cur->name))
2929 {
2930 sub = gtk_menu_item_get_submenu (witem);
2931 break;
2932 }
2933 }
2934
2935 newsub = xg_update_submenu (sub,
2936 f,
2937 cur->contents,
2938 select_cb,
2939 deactivate_cb,
2940 highlight_cb,
2941 cl_data);
2942 /* sub may still be NULL. If we just updated non deep and added
2943 a new menu bar item, it has no sub menu yet. So we set the
2944 newly created sub menu under witem. */
2945 if (newsub != sub)
2946 {
2947 xg_set_screen (newsub, f);
2948 gtk_menu_item_set_submenu (witem, newsub);
2949 }
2950 }
2951 }
2952
2953 g_list_free (list);
2954 gtk_widget_show_all (menubar);
2955 }
2956
2957 /* Recompute all the widgets of frame F, when the menu bar has been
2958 changed. Value is non-zero if widgets were updated. */
2959
2960 int
2961 xg_update_frame_menubar (f)
2962 FRAME_PTR f;
2963 {
2964 struct x_output *x = f->output_data.x;
2965 GtkRequisition req;
2966
2967 if (!x->menubar_widget || GTK_WIDGET_MAPPED (x->menubar_widget))
2968 return 0;
2969
2970 BLOCK_INPUT;
2971
2972 gtk_box_pack_start (GTK_BOX (x->vbox_widget), x->menubar_widget,
2973 FALSE, FALSE, 0);
2974 gtk_box_reorder_child (GTK_BOX (x->vbox_widget), x->menubar_widget, 0);
2975
2976 gtk_widget_show_all (x->menubar_widget);
2977 gtk_widget_size_request (x->menubar_widget, &req);
2978 FRAME_MENUBAR_HEIGHT (f) = req.height;
2979 xg_height_changed (f);
2980 UNBLOCK_INPUT;
2981
2982 return 1;
2983 }
2984
2985 /* Get rid of the menu bar of frame F, and free its storage.
2986 This is used when deleting a frame, and when turning off the menu bar. */
2987
2988 void
2989 free_frame_menubar (f)
2990 FRAME_PTR f;
2991 {
2992 struct x_output *x = f->output_data.x;
2993
2994 if (x->menubar_widget)
2995 {
2996 BLOCK_INPUT;
2997
2998 gtk_container_remove (GTK_CONTAINER (x->vbox_widget), x->menubar_widget);
2999 /* The menubar and its children shall be deleted when removed from
3000 the container. */
3001 x->menubar_widget = 0;
3002 FRAME_MENUBAR_HEIGHT (f) = 0;
3003 xg_height_changed (f);
3004 UNBLOCK_INPUT;
3005 }
3006 }
3007
3008
3009 \f
3010 /***********************************************************************
3011 Scroll bar functions
3012 ***********************************************************************/
3013
3014
3015 /* Setting scroll bar values invokes the callback. Use this variable
3016 to indicate that callback should do nothing. */
3017
3018 int xg_ignore_gtk_scrollbar;
3019
3020 /* Xlib's `Window' fits in 32 bits. But we want to store pointers, and they
3021 may be larger than 32 bits. Keep a mapping from integer index to widget
3022 pointers to get around the 32 bit limitation. */
3023
3024 static struct
3025 {
3026 GtkWidget **widgets;
3027 int max_size;
3028 int used;
3029 } id_to_widget;
3030
3031 /* Grow this much every time we need to allocate more */
3032
3033 #define ID_TO_WIDGET_INCR 32
3034
3035 /* Store the widget pointer W in id_to_widget and return the integer index. */
3036
3037 static int
3038 xg_store_widget_in_map (w)
3039 GtkWidget *w;
3040 {
3041 int i;
3042
3043 if (id_to_widget.max_size == id_to_widget.used)
3044 {
3045 int new_size = id_to_widget.max_size + ID_TO_WIDGET_INCR;
3046
3047 id_to_widget.widgets = xrealloc (id_to_widget.widgets,
3048 sizeof (GtkWidget *)*new_size);
3049
3050 for (i = id_to_widget.max_size; i < new_size; ++i)
3051 id_to_widget.widgets[i] = 0;
3052 id_to_widget.max_size = new_size;
3053 }
3054
3055 /* Just loop over the array and find a free place. After all,
3056 how many scroll bars are we creating? Should be a small number.
3057 The check above guarantees we will find a free place. */
3058 for (i = 0; i < id_to_widget.max_size; ++i)
3059 {
3060 if (! id_to_widget.widgets[i])
3061 {
3062 id_to_widget.widgets[i] = w;
3063 ++id_to_widget.used;
3064
3065 return i;
3066 }
3067 }
3068
3069 /* Should never end up here */
3070 abort ();
3071 }
3072
3073 /* Remove pointer at IDX from id_to_widget.
3074 Called when scroll bar is destroyed. */
3075
3076 static void
3077 xg_remove_widget_from_map (idx)
3078 int idx;
3079 {
3080 if (idx < id_to_widget.max_size && id_to_widget.widgets[idx] != 0)
3081 {
3082 id_to_widget.widgets[idx] = 0;
3083 --id_to_widget.used;
3084 }
3085 }
3086
3087 /* Get the widget pointer at IDX from id_to_widget. */
3088
3089 static GtkWidget *
3090 xg_get_widget_from_map (idx)
3091 int idx;
3092 {
3093 if (idx < id_to_widget.max_size && id_to_widget.widgets[idx] != 0)
3094 return id_to_widget.widgets[idx];
3095
3096 return 0;
3097 }
3098
3099 /* Return the scrollbar id for X Window WID on display DPY.
3100 Return -1 if WID not in id_to_widget. */
3101
3102 int
3103 xg_get_scroll_id_for_window (dpy, wid)
3104 Display *dpy;
3105 Window wid;
3106 {
3107 int idx;
3108 GtkWidget *w;
3109
3110 w = xg_win_to_widget (dpy, wid);
3111
3112 if (w)
3113 {
3114 for (idx = 0; idx < id_to_widget.max_size; ++idx)
3115 if (id_to_widget.widgets[idx] == w)
3116 return idx;
3117 }
3118
3119 return -1;
3120 }
3121
3122 /* Callback invoked when scroll bar WIDGET is destroyed.
3123 DATA is the index into id_to_widget for WIDGET.
3124 We free pointer to last scroll bar values here and remove the index. */
3125
3126 static void
3127 xg_gtk_scroll_destroy (widget, data)
3128 GtkWidget *widget;
3129 gpointer data;
3130 {
3131 gpointer p;
3132 int id = (int) (EMACS_INT) data; /* The EMACS_INT cast avoids a warning. */
3133
3134 p = g_object_get_data (G_OBJECT (widget), XG_LAST_SB_DATA);
3135 xfree (p);
3136 xg_remove_widget_from_map (id);
3137 }
3138
3139 /* Callback for button press/release events. Used to start timer so that
3140 the scroll bar repetition timer in GTK gets handled.
3141 Also, sets bar->dragging to Qnil when dragging (button release) is done.
3142 WIDGET is the scroll bar widget the event is for (not used).
3143 EVENT contains the event.
3144 USER_DATA points to the struct scrollbar structure.
3145
3146 Returns FALSE to tell GTK that it shall continue propagate the event
3147 to widgets. */
3148
3149 static gboolean
3150 scroll_bar_button_cb (widget, event, user_data)
3151 GtkWidget *widget;
3152 GdkEventButton *event;
3153 gpointer user_data;
3154 {
3155 if (event->type == GDK_BUTTON_PRESS && ! xg_timer)
3156 xg_start_timer ();
3157 else if (event->type == GDK_BUTTON_RELEASE)
3158 {
3159 struct scroll_bar *bar = (struct scroll_bar *) user_data;
3160 if (xg_timer) xg_stop_timer ();
3161 bar->dragging = Qnil;
3162 }
3163
3164 return FALSE;
3165 }
3166
3167 /* Create a scroll bar widget for frame F. Store the scroll bar
3168 in BAR.
3169 SCROLL_CALLBACK is the callback to invoke when the value of the
3170 bar changes.
3171 SCROLL_BAR_NAME is the name we use for the scroll bar. Can be used
3172 to set resources for the widget. */
3173
3174 void
3175 xg_create_scroll_bar (f, bar, scroll_callback, scroll_bar_name)
3176 FRAME_PTR f;
3177 struct scroll_bar *bar;
3178 GCallback scroll_callback;
3179 char *scroll_bar_name;
3180 {
3181 GtkWidget *wscroll;
3182 GtkWidget *webox;
3183 GtkObject *vadj;
3184 int scroll_id;
3185
3186 /* Page, step increment values are not so important here, they
3187 will be corrected in x_set_toolkit_scroll_bar_thumb. */
3188 vadj = gtk_adjustment_new (XG_SB_MIN, XG_SB_MIN, XG_SB_MAX,
3189 0.1, 0.1, 0.1);
3190
3191 wscroll = gtk_vscrollbar_new (GTK_ADJUSTMENT (vadj));
3192 webox = gtk_event_box_new ();
3193 gtk_widget_set_name (wscroll, scroll_bar_name);
3194 gtk_range_set_update_policy (GTK_RANGE (wscroll), GTK_UPDATE_CONTINUOUS);
3195
3196 scroll_id = xg_store_widget_in_map (wscroll);
3197
3198 g_signal_connect (G_OBJECT (wscroll),
3199 "value-changed",
3200 scroll_callback,
3201 (gpointer) bar);
3202 /* The EMACS_INT cast avoids a warning. */
3203 g_signal_connect (G_OBJECT (wscroll),
3204 "destroy",
3205 G_CALLBACK (xg_gtk_scroll_destroy),
3206 (gpointer) (EMACS_INT) scroll_id);
3207
3208 /* Connect to button press and button release to detect if any scroll bar
3209 has the pointer. */
3210 g_signal_connect (G_OBJECT (wscroll),
3211 "button-press-event",
3212 G_CALLBACK (scroll_bar_button_cb),
3213 (gpointer) bar);
3214 g_signal_connect (G_OBJECT (wscroll),
3215 "button-release-event",
3216 G_CALLBACK (scroll_bar_button_cb),
3217 (gpointer) bar);
3218
3219 /* The scroll bar widget does not draw on a window of its own. Instead
3220 it draws on the parent window, in this case the edit widget. So
3221 whenever the edit widget is cleared, the scroll bar needs to redraw
3222 also, which causes flicker. Put an event box between the edit widget
3223 and the scroll bar, so the scroll bar instead draws itself on the
3224 event box window. */
3225 gtk_fixed_put (GTK_FIXED (f->output_data.x->edit_widget), webox, -1, -1);
3226 gtk_container_add (GTK_CONTAINER (webox), wscroll);
3227
3228
3229 /* Set the cursor to an arrow. */
3230 xg_set_cursor (webox, FRAME_X_DISPLAY_INFO (f)->xg_cursor);
3231
3232 bar->x_window = scroll_id;
3233 }
3234
3235 /* Make the scroll bar represented by SCROLLBAR_ID visible. */
3236
3237 void
3238 xg_show_scroll_bar (scrollbar_id)
3239 int scrollbar_id;
3240 {
3241 GtkWidget *w = xg_get_widget_from_map (scrollbar_id);
3242 if (w)
3243 gtk_widget_show_all (gtk_widget_get_parent (w));
3244 }
3245
3246 /* Remove the scroll bar represented by SCROLLBAR_ID from the frame F. */
3247
3248 void
3249 xg_remove_scroll_bar (f, scrollbar_id)
3250 FRAME_PTR f;
3251 int scrollbar_id;
3252 {
3253 GtkWidget *w = xg_get_widget_from_map (scrollbar_id);
3254 if (w)
3255 {
3256 GtkWidget *wparent = gtk_widget_get_parent (w);
3257 gtk_widget_destroy (w);
3258 gtk_widget_destroy (wparent);
3259 SET_FRAME_GARBAGED (f);
3260 }
3261 }
3262
3263 /* Update the position of the vertical scroll bar represented by SCROLLBAR_ID
3264 in frame F.
3265 TOP/LEFT are the new pixel positions where the bar shall appear.
3266 WIDTH, HEIGHT is the size in pixels the bar shall have. */
3267
3268 void
3269 xg_update_scrollbar_pos (f, scrollbar_id, top, left, width, height)
3270 FRAME_PTR f;
3271 int scrollbar_id;
3272 int top;
3273 int left;
3274 int width;
3275 int height;
3276 {
3277
3278 GtkWidget *wscroll = xg_get_widget_from_map (scrollbar_id);
3279
3280 if (wscroll)
3281 {
3282 GtkWidget *wfixed = f->output_data.x->edit_widget;
3283 GtkWidget *wparent = gtk_widget_get_parent (wscroll);
3284
3285 /* Move and resize to new values. */
3286 gtk_fixed_move (GTK_FIXED (wfixed), wparent, left, top);
3287 gtk_widget_set_size_request (wscroll, width, height);
3288 gtk_widget_queue_draw (wparent);
3289 gdk_window_process_all_updates ();
3290 /* GTK does not redraw until the main loop is entered again, but
3291 if there are no X events pending we will not enter it. So we sync
3292 here to get some events. */
3293 x_sync (f);
3294 SET_FRAME_GARBAGED (f);
3295 cancel_mouse_face (f);
3296 }
3297 }
3298
3299 /* Set the thumb size and position of scroll bar BAR. We are currently
3300 displaying PORTION out of a whole WHOLE, and our position POSITION. */
3301
3302 void
3303 xg_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
3304 struct scroll_bar *bar;
3305 int portion, position, whole;
3306 {
3307 GtkWidget *wscroll = xg_get_widget_from_map (bar->x_window);
3308
3309 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
3310
3311 if (wscroll && NILP (bar->dragging))
3312 {
3313 GtkAdjustment *adj;
3314 gdouble shown;
3315 gdouble top;
3316 int size, value;
3317 int new_step;
3318 int changed = 0;
3319
3320 adj = gtk_range_get_adjustment (GTK_RANGE (wscroll));
3321
3322 /* We do the same as for MOTIF in xterm.c, assume 30 chars per line
3323 rather than the real portion value. This makes the thumb less likely
3324 to resize and that looks better. */
3325 portion = WINDOW_TOTAL_LINES (XWINDOW (bar->window)) * 30;
3326 /* When the thumb is at the bottom, position == whole.
3327 So we need to increase `whole' to make space for the thumb. */
3328 whole += portion;
3329
3330 if (whole <= 0)
3331 top = 0, shown = 1;
3332 else
3333 {
3334 top = (gdouble) position / whole;
3335 shown = (gdouble) portion / whole;
3336 }
3337
3338 size = shown * XG_SB_RANGE;
3339 size = min (size, XG_SB_RANGE);
3340 size = max (size, 1);
3341
3342 value = top * XG_SB_RANGE;
3343 value = min (value, XG_SB_MAX - size);
3344 value = max (value, XG_SB_MIN);
3345
3346 /* Assume all lines are of equal size. */
3347 new_step = size / max (1, FRAME_LINES (f));
3348
3349 if ((int) adj->page_size != size
3350 || (int) adj->step_increment != new_step)
3351 {
3352 adj->page_size = size;
3353 adj->step_increment = new_step;
3354 /* Assume a page increment is about 95% of the page size */
3355 adj->page_increment = (int) (0.95*adj->page_size);
3356 changed = 1;
3357 }
3358
3359 if (changed || (int) gtk_range_get_value (GTK_RANGE (wscroll)) != value)
3360 {
3361 GtkWidget *wfixed = f->output_data.x->edit_widget;
3362
3363 BLOCK_INPUT;
3364
3365 /* gtk_range_set_value invokes the callback. Set
3366 ignore_gtk_scrollbar to make the callback do nothing */
3367 xg_ignore_gtk_scrollbar = 1;
3368
3369 if ((int) gtk_range_get_value (GTK_RANGE (wscroll)) != value)
3370 gtk_range_set_value (GTK_RANGE (wscroll), (gdouble)value);
3371 else if (changed)
3372 gtk_adjustment_changed (adj);
3373
3374 xg_ignore_gtk_scrollbar = 0;
3375
3376 UNBLOCK_INPUT;
3377 }
3378 }
3379 }
3380
3381 \f
3382 /***********************************************************************
3383 Tool bar functions
3384 ***********************************************************************/
3385 /* The key for the data we put in the GtkImage widgets. The data is
3386 the image used by Emacs. We use this to see if we need to update
3387 the GtkImage with a new image. */
3388 #define XG_TOOL_BAR_IMAGE_DATA "emacs-tool-bar-image"
3389
3390 /* The key for storing the latest modifiers so the activate callback can
3391 get them. */
3392 #define XG_TOOL_BAR_LAST_MODIFIER "emacs-tool-bar-modifier"
3393
3394 /* The key for storing the button widget in its proxy menu item. */
3395 #define XG_TOOL_BAR_PROXY_BUTTON "emacs-tool-bar-proxy-button"
3396
3397 /* The key for the data we put in the GtkImage widgets. The data is
3398 the stock name used by Emacs. We use this to see if we need to update
3399 the GtkImage with a new image. */
3400 #define XG_TOOL_BAR_STOCK_NAME "emacs-tool-bar-stock-name"
3401
3402 /* As above, but this is used for named theme widgets, as opposed to
3403 stock items. */
3404 #define XG_TOOL_BAR_ICON_NAME "emacs-tool-bar-icon-name"
3405
3406 /* Callback function invoked when a tool bar item is pressed.
3407 W is the button widget in the tool bar that got pressed,
3408 CLIENT_DATA is an integer that is the index of the button in the
3409 tool bar. 0 is the first button. */
3410
3411 static gboolean
3412 xg_tool_bar_button_cb (widget, event, user_data)
3413 GtkWidget *widget;
3414 GdkEventButton *event;
3415 gpointer user_data;
3416 {
3417 /* Casts to avoid warnings when gpointer is 64 bits and int is 32 bits */
3418 gpointer ptr = (gpointer) (EMACS_INT) event->state;
3419 g_object_set_data (G_OBJECT (widget), XG_TOOL_BAR_LAST_MODIFIER, ptr);
3420 return FALSE;
3421 }
3422
3423
3424 /* Callback function invoked when a tool bar item is pressed.
3425 W is the button widget in the tool bar that got pressed,
3426 CLIENT_DATA is an integer that is the index of the button in the
3427 tool bar. 0 is the first button. */
3428
3429 static void
3430 xg_tool_bar_callback (w, client_data)
3431 GtkWidget *w;
3432 gpointer client_data;
3433 {
3434 /* The EMACS_INT cast avoids a warning. */
3435 int idx = (int) (EMACS_INT) client_data;
3436 int mod = (int) (EMACS_INT) g_object_get_data (G_OBJECT (w),
3437 XG_TOOL_BAR_LAST_MODIFIER);
3438
3439 FRAME_PTR f = (FRAME_PTR) g_object_get_data (G_OBJECT (w), XG_FRAME_DATA);
3440 Lisp_Object key, frame;
3441 struct input_event event;
3442 EVENT_INIT (event);
3443
3444 if (! f || ! f->n_tool_bar_items || NILP (f->tool_bar_items))
3445 return;
3446
3447 idx *= TOOL_BAR_ITEM_NSLOTS;
3448
3449 key = AREF (f->tool_bar_items, idx + TOOL_BAR_ITEM_KEY);
3450 XSETFRAME (frame, f);
3451
3452 /* We generate two events here. The first one is to set the prefix
3453 to `(tool_bar)', see keyboard.c. */
3454 event.kind = TOOL_BAR_EVENT;
3455 event.frame_or_window = frame;
3456 event.arg = frame;
3457 kbd_buffer_store_event (&event);
3458
3459 event.kind = TOOL_BAR_EVENT;
3460 event.frame_or_window = frame;
3461 event.arg = key;
3462 /* Convert between the modifier bits GDK uses and the modifier bits
3463 Emacs uses. This assumes GDK and X masks are the same, which they are when
3464 this is written. */
3465 event.modifiers = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f), mod);
3466 kbd_buffer_store_event (&event);
3467
3468 /* Return focus to the frame after we have clicked on a detached
3469 tool bar button. */
3470 Fx_focus_frame (frame);
3471 }
3472
3473 /* Callback function invoked when a tool bar item is pressed in a detached
3474 tool bar or the overflow drop down menu.
3475 We just call xg_tool_bar_callback.
3476 W is the menu item widget 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. */
3479
3480 static void
3481 xg_tool_bar_proxy_callback (w, client_data)
3482 GtkWidget *w;
3483 gpointer client_data;
3484 {
3485 GtkWidget *wbutton = GTK_WIDGET (g_object_get_data (G_OBJECT (w),
3486 XG_TOOL_BAR_PROXY_BUTTON));
3487 xg_tool_bar_callback (wbutton, client_data);
3488 }
3489
3490
3491 static gboolean
3492 xg_tool_bar_help_callback P_ ((GtkWidget *w,
3493 GdkEventCrossing *event,
3494 gpointer client_data));
3495
3496 /* This callback is called when a help is to be shown for an item in
3497 the detached tool bar when the detached tool bar it is not expanded. */
3498
3499 static gboolean
3500 xg_tool_bar_proxy_help_callback (w, event, client_data)
3501 GtkWidget *w;
3502 GdkEventCrossing *event;
3503 gpointer client_data;
3504 {
3505 GtkWidget *wbutton = GTK_WIDGET (g_object_get_data (G_OBJECT (w),
3506 XG_TOOL_BAR_PROXY_BUTTON));
3507
3508 xg_tool_bar_help_callback (wbutton, event, client_data);
3509 }
3510
3511
3512 /* This callback is called when a tool item should create a proxy item,
3513 such as for the overflow menu. Also called when the tool bar is detached.
3514 If we don't create a proxy menu item, the detached tool bar will be
3515 blank. */
3516
3517 static gboolean
3518 xg_tool_bar_menu_proxy (toolitem, user_data)
3519 GtkToolItem *toolitem;
3520 gpointer user_data;
3521 {
3522 GtkWidget *weventbox = gtk_bin_get_child (GTK_BIN (toolitem));
3523 GtkButton *wbutton = GTK_BUTTON (gtk_bin_get_child (GTK_BIN (weventbox)));
3524 GtkWidget *wmenuitem = gtk_image_menu_item_new_with_label ("");
3525 GtkWidget *wmenuimage;
3526
3527 if (gtk_button_get_use_stock (wbutton))
3528 wmenuimage = gtk_image_new_from_stock (gtk_button_get_label (wbutton),
3529 GTK_ICON_SIZE_MENU);
3530 else
3531 {
3532 GtkImage *wimage = GTK_IMAGE (gtk_bin_get_child (GTK_BIN (wbutton)));
3533 GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (wbutton));
3534 GtkImageType store_type = gtk_image_get_storage_type (wimage);
3535
3536 if (store_type == GTK_IMAGE_STOCK)
3537 {
3538 gchar *stock_id;
3539 gtk_image_get_stock (wimage, &stock_id, NULL);
3540 wmenuimage = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_MENU);
3541 }
3542 else if (store_type == GTK_IMAGE_ICON_SET)
3543 {
3544 GtkIconSet *icon_set;
3545 gtk_image_get_icon_set (wimage, &icon_set, NULL);
3546 wmenuimage = gtk_image_new_from_icon_set (icon_set,
3547 GTK_ICON_SIZE_MENU);
3548 }
3549 else if (store_type == GTK_IMAGE_PIXBUF)
3550 {
3551 gint width, height;
3552
3553 if (settings &&
3554 gtk_icon_size_lookup_for_settings (settings, GTK_ICON_SIZE_MENU,
3555 &width, &height))
3556 {
3557 GdkPixbuf *src_pixbuf, *dest_pixbuf;
3558
3559 src_pixbuf = gtk_image_get_pixbuf (wimage);
3560 dest_pixbuf = gdk_pixbuf_scale_simple (src_pixbuf, width, height,
3561 GDK_INTERP_BILINEAR);
3562
3563 wmenuimage = gtk_image_new_from_pixbuf (dest_pixbuf);
3564 }
3565 else
3566 {
3567 fprintf (stderr, "internal error: GTK_IMAGE_PIXBUF failed\n");
3568 abort ();
3569 }
3570 }
3571 else if (store_type == GTK_IMAGE_ICON_NAME)
3572 {
3573 const gchar *icon_name;
3574 GtkIconSize icon_size;
3575
3576 gtk_image_get_icon_name (wimage, &icon_name, &icon_size);
3577 wmenuimage = gtk_image_new_from_icon_name (icon_name,
3578 GTK_ICON_SIZE_MENU);
3579 }
3580 else
3581 {
3582 fprintf (stderr, "internal error: store_type is %d\n", store_type);
3583 abort ();
3584 }
3585 }
3586 if (wmenuimage)
3587 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (wmenuitem), wmenuimage);
3588
3589 g_signal_connect (G_OBJECT (wmenuitem),
3590 "activate",
3591 G_CALLBACK (xg_tool_bar_proxy_callback),
3592 user_data);
3593
3594
3595 g_object_set_data (G_OBJECT (wmenuitem), XG_TOOL_BAR_PROXY_BUTTON,
3596 (gpointer) wbutton);
3597 gtk_tool_item_set_proxy_menu_item (toolitem, "Emacs toolbar item", wmenuitem);
3598 gtk_widget_set_sensitive (wmenuitem, GTK_WIDGET_SENSITIVE (wbutton));
3599
3600 /* Use enter/leave notify to show help. We use the events
3601 rather than the GtkButton specific signals "enter" and
3602 "leave", so we can have only one callback. The event
3603 will tell us what kind of event it is. */
3604 g_signal_connect (G_OBJECT (wmenuitem),
3605 "enter-notify-event",
3606 G_CALLBACK (xg_tool_bar_proxy_help_callback),
3607 user_data);
3608 g_signal_connect (G_OBJECT (wmenuitem),
3609 "leave-notify-event",
3610 G_CALLBACK (xg_tool_bar_proxy_help_callback),
3611 user_data);
3612
3613 return TRUE;
3614 }
3615
3616 /* This callback is called when a tool bar is detached. We must set
3617 the height of the tool bar to zero when this happens so frame sizes
3618 are correctly calculated.
3619 WBOX is the handle box widget that enables detach/attach of the tool bar.
3620 W is the tool bar widget.
3621 CLIENT_DATA is a pointer to the frame the tool bar belongs to. */
3622
3623 static void
3624 xg_tool_bar_detach_callback (wbox, w, client_data)
3625 GtkHandleBox *wbox;
3626 GtkWidget *w;
3627 gpointer client_data;
3628 {
3629 FRAME_PTR f = (FRAME_PTR) client_data;
3630 extern int x_gtk_whole_detached_tool_bar;
3631
3632 g_object_set (G_OBJECT (w), "show-arrow", !x_gtk_whole_detached_tool_bar,
3633 NULL);
3634
3635 if (f)
3636 {
3637 FRAME_X_OUTPUT (f)->toolbar_detached = 1;
3638
3639 /* When detaching a tool bar, not everything dissapear. There are
3640 a few pixels left that are used to drop the tool bar back into
3641 place. */
3642 FRAME_TOOLBAR_HEIGHT (f) = 4;
3643 xg_height_changed (f);
3644 }
3645 }
3646
3647 /* This callback is called when a tool bar is reattached. We must set
3648 the height of the tool bar when this happens so frame sizes
3649 are correctly calculated.
3650 WBOX is the handle box widget that enables detach/attach of the tool bar.
3651 W is the tool bar widget.
3652 CLIENT_DATA is a pointer to the frame the tool bar belongs to. */
3653
3654 static void
3655 xg_tool_bar_attach_callback (wbox, w, client_data)
3656 GtkHandleBox *wbox;
3657 GtkWidget *w;
3658 gpointer client_data;
3659 {
3660 FRAME_PTR f = (FRAME_PTR) client_data;
3661 g_object_set (G_OBJECT (w), "show-arrow", TRUE, NULL);
3662
3663 if (f)
3664 {
3665 GtkRequisition req;
3666
3667 FRAME_X_OUTPUT (f)->toolbar_detached = 0;
3668
3669 gtk_widget_size_request (w, &req);
3670 FRAME_TOOLBAR_HEIGHT (f) = req.height;
3671 xg_height_changed (f);
3672 }
3673 }
3674
3675 /* This callback is called when the mouse enters or leaves a tool bar item.
3676 It is used for displaying and hiding the help text.
3677 W is the tool bar item, a button.
3678 EVENT is either an enter event or leave event.
3679 CLIENT_DATA is an integer that is the index of the button in the
3680 tool bar. 0 is the first button.
3681
3682 Returns FALSE to tell GTK to keep processing this event. */
3683
3684 static gboolean
3685 xg_tool_bar_help_callback (w, event, client_data)
3686 GtkWidget *w;
3687 GdkEventCrossing *event;
3688 gpointer client_data;
3689 {
3690 /* The EMACS_INT cast avoids a warning. */
3691 int idx = (int) (EMACS_INT) client_data;
3692 FRAME_PTR f = (FRAME_PTR) g_object_get_data (G_OBJECT (w), XG_FRAME_DATA);
3693 Lisp_Object help, frame;
3694
3695 if (! f || ! f->n_tool_bar_items || NILP (f->tool_bar_items))
3696 return FALSE;
3697
3698 if (event->type == GDK_ENTER_NOTIFY)
3699 {
3700 idx *= TOOL_BAR_ITEM_NSLOTS;
3701 help = AREF (f->tool_bar_items, idx + TOOL_BAR_ITEM_HELP);
3702
3703 if (NILP (help))
3704 help = AREF (f->tool_bar_items, idx + TOOL_BAR_ITEM_CAPTION);
3705 }
3706 else
3707 help = Qnil;
3708
3709 XSETFRAME (frame, f);
3710 kbd_buffer_store_help_event (frame, help);
3711
3712 return FALSE;
3713 }
3714
3715
3716 /* This callback is called when a tool bar item shall be redrawn.
3717 It modifies the expose event so that the GtkImage widget redraws the
3718 whole image. This to overcome a bug that makes GtkImage draw the image
3719 in the wrong place when it tries to redraw just a part of the image.
3720 W is the GtkImage to be redrawn.
3721 EVENT is the expose event for W.
3722 CLIENT_DATA is unused.
3723
3724 Returns FALSE to tell GTK to keep processing this event. */
3725
3726 static gboolean
3727 xg_tool_bar_item_expose_callback (w, event, client_data)
3728 GtkWidget *w;
3729 GdkEventExpose *event;
3730 gpointer client_data;
3731 {
3732 gint width, height;
3733
3734 gdk_drawable_get_size (event->window, &width, &height);
3735
3736 event->area.x -= width > event->area.width ? width-event->area.width : 0;
3737 event->area.y -= height > event->area.height ? height-event->area.height : 0;
3738
3739 event->area.x = max (0, event->area.x);
3740 event->area.y = max (0, event->area.y);
3741
3742 event->area.width = max (width, event->area.width);
3743 event->area.height = max (height, event->area.height);
3744
3745 return FALSE;
3746 }
3747
3748 /* Attach a tool bar to frame F. */
3749
3750 static void
3751 xg_pack_tool_bar (f)
3752 FRAME_PTR f;
3753 {
3754 struct x_output *x = f->output_data.x;
3755 int vbox_pos = x->menubar_widget ? 1 : 0;
3756
3757 x->handlebox_widget = gtk_handle_box_new ();
3758 g_signal_connect (G_OBJECT (x->handlebox_widget), "child-detached",
3759 G_CALLBACK (xg_tool_bar_detach_callback), f);
3760 g_signal_connect (G_OBJECT (x->handlebox_widget), "child-attached",
3761 G_CALLBACK (xg_tool_bar_attach_callback), f);
3762
3763 gtk_container_add (GTK_CONTAINER (x->handlebox_widget),
3764 x->toolbar_widget);
3765
3766 gtk_box_pack_start (GTK_BOX (x->vbox_widget), x->handlebox_widget,
3767 FALSE, FALSE, 0);
3768
3769 gtk_box_reorder_child (GTK_BOX (x->vbox_widget), x->handlebox_widget,
3770 vbox_pos);
3771 gtk_widget_show_all (x->handlebox_widget);
3772 }
3773
3774 /* Create a tool bar for frame F. */
3775
3776 static void
3777 xg_create_tool_bar (f)
3778 FRAME_PTR f;
3779 {
3780 struct x_output *x = f->output_data.x;
3781 GtkRequisition req;
3782
3783 x->toolbar_widget = gtk_toolbar_new ();
3784 x->toolbar_detached = 0;
3785
3786 gtk_widget_set_name (x->toolbar_widget, "emacs-toolbar");
3787
3788 /* We only have icons, so override any user setting. We could
3789 use the caption property of the toolbar item (see update_frame_tool_bar
3790 below), but some of those strings are long, making the toolbar so
3791 long it does not fit on the screen. The GtkToolbar widget makes every
3792 item equal size, so the longest caption determine the size of every
3793 tool bar item. I think the creators of the GtkToolbar widget
3794 counted on 4 or 5 character long strings. */
3795 gtk_toolbar_set_style (GTK_TOOLBAR (x->toolbar_widget), GTK_TOOLBAR_ICONS);
3796 gtk_toolbar_set_orientation (GTK_TOOLBAR (x->toolbar_widget),
3797 GTK_ORIENTATION_HORIZONTAL);
3798 }
3799
3800
3801 #define PROP(IDX) AREF (f->tool_bar_items, i * TOOL_BAR_ITEM_NSLOTS + (IDX))
3802
3803 /* Find the right-to-left image named by RTL in the tool bar images for F.
3804 Returns IMAGE if RTL is not found. */
3805
3806 static Lisp_Object
3807 find_rtl_image (f, image, rtl)
3808 FRAME_PTR f;
3809 Lisp_Object image;
3810 Lisp_Object rtl;
3811 {
3812 int i;
3813 Lisp_Object file, rtl_name;
3814 struct gcpro gcpro1, gcpro2;
3815 GCPRO2 (file, rtl_name);
3816
3817 rtl_name = Ffile_name_nondirectory (rtl);
3818
3819 for (i = 0; i < f->n_tool_bar_items; ++i)
3820 {
3821 Lisp_Object rtl_image = PROP (TOOL_BAR_ITEM_IMAGES);
3822 if (!NILP (file = file_for_image (rtl_image)))
3823 {
3824 file = call1 (intern ("file-name-sans-extension"),
3825 Ffile_name_nondirectory (file));
3826 if (EQ (Fequal (file, rtl_name), Qt))
3827 {
3828 image = rtl_image;
3829 break;
3830 }
3831 }
3832 }
3833
3834 return image;
3835 }
3836
3837 /* Update the tool bar for frame F. Add new buttons and remove old. */
3838
3839 extern Lisp_Object Qx_gtk_map_stock;
3840
3841 void
3842 update_frame_tool_bar (f)
3843 FRAME_PTR f;
3844 {
3845 int i;
3846 GtkRequisition old_req, new_req;
3847 struct x_output *x = f->output_data.x;
3848 int hmargin = 0, vmargin = 0;
3849 GtkToolbar *wtoolbar;
3850 GtkToolItem *ti;
3851 GtkTextDirection dir;
3852 int pack_tool_bar = x->handlebox_widget == NULL;
3853
3854 if (! FRAME_GTK_WIDGET (f))
3855 return;
3856
3857 BLOCK_INPUT;
3858
3859 if (INTEGERP (Vtool_bar_button_margin)
3860 && XINT (Vtool_bar_button_margin) > 0)
3861 {
3862 hmargin = XFASTINT (Vtool_bar_button_margin);
3863 vmargin = XFASTINT (Vtool_bar_button_margin);
3864 }
3865 else if (CONSP (Vtool_bar_button_margin))
3866 {
3867 if (INTEGERP (XCAR (Vtool_bar_button_margin))
3868 && XINT (XCAR (Vtool_bar_button_margin)) > 0)
3869 hmargin = XFASTINT (XCAR (Vtool_bar_button_margin));
3870
3871 if (INTEGERP (XCDR (Vtool_bar_button_margin))
3872 && XINT (XCDR (Vtool_bar_button_margin)) > 0)
3873 vmargin = XFASTINT (XCDR (Vtool_bar_button_margin));
3874 }
3875
3876 /* The natural size (i.e. when GTK uses 0 as margin) looks best,
3877 so take DEFAULT_TOOL_BAR_BUTTON_MARGIN to mean "default for GTK",
3878 i.e. zero. This means that margins less than
3879 DEFAULT_TOOL_BAR_BUTTON_MARGIN has no effect. */
3880 hmargin = max (0, hmargin - DEFAULT_TOOL_BAR_BUTTON_MARGIN);
3881 vmargin = max (0, vmargin - DEFAULT_TOOL_BAR_BUTTON_MARGIN);
3882
3883 if (! x->toolbar_widget)
3884 xg_create_tool_bar (f);
3885
3886 wtoolbar = GTK_TOOLBAR (x->toolbar_widget);
3887 gtk_widget_size_request (GTK_WIDGET (wtoolbar), &old_req);
3888 dir = gtk_widget_get_direction (x->toolbar_widget);
3889
3890 for (i = 0; i < f->n_tool_bar_items; ++i)
3891 {
3892 int enabled_p = !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P));
3893 int selected_p = !NILP (PROP (TOOL_BAR_ITEM_SELECTED_P));
3894 int idx;
3895 int img_id;
3896 int icon_size = 0;
3897 struct image *img = NULL;
3898 Lisp_Object image;
3899 Lisp_Object stock = Qnil;
3900 GtkStockItem stock_item;
3901 char *stock_name = NULL;
3902 char *icon_name = NULL;
3903 Lisp_Object rtl;
3904 GtkWidget *wbutton = NULL;
3905 GtkWidget *weventbox;
3906 Lisp_Object specified_file;
3907
3908 ti = gtk_toolbar_get_nth_item (GTK_TOOLBAR (x->toolbar_widget), i);
3909
3910 if (ti)
3911 {
3912 weventbox = gtk_bin_get_child (GTK_BIN (ti));
3913 wbutton = gtk_bin_get_child (GTK_BIN (weventbox));
3914 }
3915
3916 image = PROP (TOOL_BAR_ITEM_IMAGES);
3917
3918 /* Ignore invalid image specifications. */
3919 if (!valid_image_p (image))
3920 {
3921 if (wbutton) gtk_widget_hide (wbutton);
3922 continue;
3923 }
3924
3925 specified_file = file_for_image (image);
3926 if (!NILP (specified_file) && !NILP (Ffboundp (Qx_gtk_map_stock)))
3927 stock = call1 (Qx_gtk_map_stock, specified_file);
3928
3929 if (STRINGP (stock))
3930 {
3931 stock_name = SSDATA (stock);
3932 if (stock_name[0] == 'n' && stock_name[1] == ':')
3933 {
3934 GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (wtoolbar));
3935 GtkIconTheme *icon_theme = gtk_icon_theme_get_for_screen (screen);
3936
3937 icon_name = stock_name + 2;
3938 stock_name = NULL;
3939 stock = Qnil;
3940
3941 if (! gtk_icon_theme_has_icon (icon_theme, icon_name))
3942 icon_name = NULL;
3943 else
3944 icon_size = gtk_toolbar_get_icon_size (wtoolbar);
3945 }
3946 else if (gtk_stock_lookup (SSDATA (stock), &stock_item))
3947 icon_size = gtk_toolbar_get_icon_size (wtoolbar);
3948 else
3949 {
3950 stock = Qnil;
3951 stock_name = NULL;
3952 }
3953 }
3954
3955 if (stock_name == NULL && icon_name == NULL)
3956 {
3957 /* No stock image, or stock item not known. Try regular image. */
3958
3959 /* If image is a vector, choose the image according to the
3960 button state. */
3961 if (dir == GTK_TEXT_DIR_RTL
3962 && !NILP (rtl = PROP (TOOL_BAR_ITEM_RTL_IMAGE))
3963 && STRINGP (rtl))
3964 {
3965 image = find_rtl_image (f, image, rtl);
3966 }
3967
3968 if (VECTORP (image))
3969 {
3970 if (enabled_p)
3971 idx = (selected_p
3972 ? TOOL_BAR_IMAGE_ENABLED_SELECTED
3973 : TOOL_BAR_IMAGE_ENABLED_DESELECTED);
3974 else
3975 idx = (selected_p
3976 ? TOOL_BAR_IMAGE_DISABLED_SELECTED
3977 : TOOL_BAR_IMAGE_DISABLED_DESELECTED);
3978
3979 xassert (ASIZE (image) >= idx);
3980 image = AREF (image, idx);
3981 }
3982 else
3983 idx = -1;
3984
3985 img_id = lookup_image (f, image);
3986 img = IMAGE_FROM_ID (f, img_id);
3987 prepare_image_for_display (f, img);
3988
3989 if (img->load_failed_p || img->pixmap == None)
3990 {
3991 if (ti)
3992 gtk_widget_hide_all (GTK_WIDGET (ti));
3993 else
3994 {
3995 /* Insert an empty (non-image) button */
3996 weventbox = gtk_event_box_new ();
3997 wbutton = gtk_button_new ();
3998 gtk_button_set_focus_on_click (GTK_BUTTON (wbutton), FALSE);
3999 gtk_button_set_relief (GTK_BUTTON (wbutton),
4000 GTK_RELIEF_NONE);
4001 gtk_container_add (GTK_CONTAINER (weventbox), wbutton);
4002 ti = gtk_tool_item_new ();
4003 gtk_container_add (GTK_CONTAINER (ti), weventbox);
4004 gtk_toolbar_insert (GTK_TOOLBAR (x->toolbar_widget), ti, -1);
4005 }
4006 continue;
4007 }
4008 }
4009
4010 if (ti == NULL)
4011 {
4012 GtkWidget *w;
4013 if (stock_name)
4014 {
4015 w = gtk_image_new_from_stock (stock_name, icon_size);
4016 g_object_set_data_full (G_OBJECT (w), XG_TOOL_BAR_STOCK_NAME,
4017 (gpointer) xstrdup (stock_name),
4018 (GDestroyNotify) xfree);
4019 }
4020 else if (icon_name)
4021 {
4022 w = gtk_image_new_from_icon_name (icon_name, icon_size);
4023 g_object_set_data_full (G_OBJECT (w), XG_TOOL_BAR_ICON_NAME,
4024 (gpointer) xstrdup (icon_name),
4025 (GDestroyNotify) xfree);
4026 }
4027 else
4028 {
4029 w = xg_get_image_for_pixmap (f, img, x->widget, NULL);
4030 /* Save the image so we can see if an update is needed when
4031 this function is called again. */
4032 g_object_set_data (G_OBJECT (w), XG_TOOL_BAR_IMAGE_DATA,
4033 (gpointer)img->pixmap);
4034 }
4035
4036 gtk_misc_set_padding (GTK_MISC (w), hmargin, vmargin);
4037 wbutton = gtk_button_new ();
4038 gtk_button_set_focus_on_click (GTK_BUTTON (wbutton), FALSE);
4039 gtk_button_set_relief (GTK_BUTTON (wbutton), GTK_RELIEF_NONE);
4040 gtk_container_add (GTK_CONTAINER (wbutton), w);
4041 weventbox = gtk_event_box_new ();
4042 gtk_container_add (GTK_CONTAINER (weventbox), wbutton);
4043 ti = gtk_tool_item_new ();
4044 gtk_container_add (GTK_CONTAINER (ti), weventbox);
4045 gtk_toolbar_insert (GTK_TOOLBAR (x->toolbar_widget), ti, -1);
4046
4047
4048 /* The EMACS_INT cast avoids a warning. */
4049 g_signal_connect (G_OBJECT (ti), "create-menu-proxy",
4050 G_CALLBACK (xg_tool_bar_menu_proxy),
4051 (gpointer) (EMACS_INT) i);
4052
4053 g_signal_connect (G_OBJECT (wbutton), "clicked",
4054 G_CALLBACK (xg_tool_bar_callback),
4055 (gpointer) (EMACS_INT) i);
4056
4057 gtk_widget_show_all (GTK_WIDGET (ti));
4058
4059
4060 g_object_set_data (G_OBJECT (weventbox), XG_FRAME_DATA, (gpointer)f);
4061
4062 /* Catch expose events to overcome an annoying redraw bug, see
4063 comment for xg_tool_bar_item_expose_callback. */
4064 g_signal_connect (G_OBJECT (ti),
4065 "expose-event",
4066 G_CALLBACK (xg_tool_bar_item_expose_callback),
4067 0);
4068
4069 gtk_widget_set_sensitive (wbutton, enabled_p);
4070 gtk_tool_item_set_homogeneous (ti, FALSE);
4071
4072 /* Callback to save modifyer mask (Shift/Control, etc). GTK makes
4073 no distinction based on modifiers in the activate callback,
4074 so we have to do it ourselves. */
4075 g_signal_connect (wbutton, "button-release-event",
4076 G_CALLBACK (xg_tool_bar_button_cb),
4077 NULL);
4078
4079 g_object_set_data (G_OBJECT (wbutton), XG_FRAME_DATA, (gpointer)f);
4080
4081 /* Use enter/leave notify to show help. We use the events
4082 rather than the GtkButton specific signals "enter" and
4083 "leave", so we can have only one callback. The event
4084 will tell us what kind of event it is. */
4085 /* The EMACS_INT cast avoids a warning. */
4086 g_signal_connect (G_OBJECT (weventbox),
4087 "enter-notify-event",
4088 G_CALLBACK (xg_tool_bar_help_callback),
4089 (gpointer) (EMACS_INT) i);
4090 g_signal_connect (G_OBJECT (weventbox),
4091 "leave-notify-event",
4092 G_CALLBACK (xg_tool_bar_help_callback),
4093 (gpointer) (EMACS_INT) i);
4094 }
4095 else
4096 {
4097 GtkWidget *wimage = gtk_bin_get_child (GTK_BIN (wbutton));
4098 Pixmap old_img = (Pixmap)g_object_get_data (G_OBJECT (wimage),
4099 XG_TOOL_BAR_IMAGE_DATA);
4100 gpointer old_stock_name = g_object_get_data (G_OBJECT (wimage),
4101 XG_TOOL_BAR_STOCK_NAME);
4102 gpointer old_icon_name = g_object_get_data (G_OBJECT (wimage),
4103 XG_TOOL_BAR_ICON_NAME);
4104 if (stock_name &&
4105 (! old_stock_name || strcmp (old_stock_name, stock_name) != 0))
4106 {
4107 gtk_image_set_from_stock (GTK_IMAGE (wimage),
4108 stock_name, icon_size);
4109 g_object_set_data_full (G_OBJECT (wimage), XG_TOOL_BAR_STOCK_NAME,
4110 (gpointer) xstrdup (stock_name),
4111 (GDestroyNotify) xfree);
4112 g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_IMAGE_DATA,
4113 NULL);
4114 g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_ICON_NAME, NULL);
4115 }
4116 else if (icon_name &&
4117 (! old_icon_name || strcmp (old_icon_name, icon_name) != 0))
4118 {
4119 gtk_image_set_from_icon_name (GTK_IMAGE (wimage),
4120 icon_name, icon_size);
4121 g_object_set_data_full (G_OBJECT (wimage), XG_TOOL_BAR_ICON_NAME,
4122 (gpointer) xstrdup (icon_name),
4123 (GDestroyNotify) xfree);
4124 g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_IMAGE_DATA,
4125 NULL);
4126 g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_STOCK_NAME,
4127 NULL);
4128 }
4129 else if (img && old_img != img->pixmap)
4130 {
4131 (void) xg_get_image_for_pixmap (f, img, x->widget, wimage);
4132 g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_IMAGE_DATA,
4133 (gpointer)img->pixmap);
4134
4135 g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_STOCK_NAME,
4136 NULL);
4137 g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_ICON_NAME, NULL);
4138 }
4139
4140 gtk_misc_set_padding (GTK_MISC (wimage), hmargin, vmargin);
4141
4142 gtk_widget_set_sensitive (wbutton, enabled_p);
4143 gtk_widget_show_all (GTK_WIDGET (ti));
4144 }
4145
4146 #undef PROP
4147 }
4148
4149 /* Remove buttons not longer needed. We just hide them so they
4150 can be reused later on. */
4151 do
4152 {
4153 ti = gtk_toolbar_get_nth_item (GTK_TOOLBAR (x->toolbar_widget), i++);
4154 if (ti) gtk_widget_hide_all (GTK_WIDGET (ti));
4155 } while (ti != NULL);
4156
4157 new_req.height = 0;
4158 if (pack_tool_bar && f->n_tool_bar_items != 0)
4159 xg_pack_tool_bar (f);
4160
4161
4162 gtk_widget_size_request (GTK_WIDGET (x->toolbar_widget), &new_req);
4163 if (old_req.height != new_req.height
4164 && ! FRAME_X_OUTPUT (f)->toolbar_detached)
4165 {
4166 FRAME_TOOLBAR_HEIGHT (f) = new_req.height;
4167 xg_height_changed (f);
4168 }
4169 UNBLOCK_INPUT;
4170 }
4171
4172 /* Deallocate all resources for the tool bar on frame F.
4173 Remove the tool bar. */
4174
4175 void
4176 free_frame_tool_bar (f)
4177 FRAME_PTR f;
4178 {
4179 struct x_output *x = f->output_data.x;
4180
4181 if (x->toolbar_widget)
4182 {
4183 int is_packed = x->handlebox_widget != 0;
4184 BLOCK_INPUT;
4185 /* We may have created the toolbar_widget in xg_create_tool_bar, but
4186 not the x->handlebox_widget which is created in xg_pack_tool_bar. */
4187 if (is_packed)
4188 gtk_container_remove (GTK_CONTAINER (x->vbox_widget),
4189 x->handlebox_widget);
4190 else
4191 gtk_widget_destroy (x->toolbar_widget);
4192
4193 x->toolbar_widget = 0;
4194 x->handlebox_widget = 0;
4195 FRAME_TOOLBAR_HEIGHT (f) = 0;
4196 xg_height_changed (f);
4197
4198 UNBLOCK_INPUT;
4199 }
4200 }
4201
4202
4203 \f
4204 /***********************************************************************
4205 Initializing
4206 ***********************************************************************/
4207 void
4208 xg_initialize ()
4209 {
4210 GtkBindingSet *binding_set;
4211
4212 #if HAVE_XFT
4213 /* Work around a bug with corrupted data if libXft gets unloaded. This way
4214 we keep it permanently linked in. */
4215 XftInit (0);
4216 #endif
4217
4218 gdpy_def = NULL;
4219 xg_ignore_gtk_scrollbar = 0;
4220 xg_detached_menus = 0;
4221 xg_menu_cb_list.prev = xg_menu_cb_list.next =
4222 xg_menu_item_cb_list.prev = xg_menu_item_cb_list.next = 0;
4223
4224 id_to_widget.max_size = id_to_widget.used = 0;
4225 id_to_widget.widgets = 0;
4226
4227 /* Remove F10 as a menu accelerator, it does not mix well with Emacs key
4228 bindings. It doesn't seem to be any way to remove properties,
4229 so we set it to VoidSymbol which in X means "no key". */
4230 gtk_settings_set_string_property (gtk_settings_get_default (),
4231 "gtk-menu-bar-accel",
4232 "VoidSymbol",
4233 EMACS_CLASS);
4234
4235 /* Make GTK text input widgets use Emacs style keybindings. This is
4236 Emacs after all. */
4237 gtk_settings_set_string_property (gtk_settings_get_default (),
4238 "gtk-key-theme-name",
4239 "Emacs",
4240 EMACS_CLASS);
4241
4242 /* Make dialogs close on C-g. Since file dialog inherits from
4243 dialog, this works for them also. */
4244 binding_set = gtk_binding_set_by_class (g_type_class_ref (GTK_TYPE_DIALOG));
4245 gtk_binding_entry_add_signal (binding_set, GDK_g, GDK_CONTROL_MASK,
4246 "close", 0);
4247
4248 /* Make menus close on C-g. */
4249 binding_set = gtk_binding_set_by_class (g_type_class_ref
4250 (GTK_TYPE_MENU_SHELL));
4251 gtk_binding_entry_add_signal (binding_set, GDK_g, GDK_CONTROL_MASK,
4252 "cancel", 0);
4253 }
4254
4255 #endif /* USE_GTK */
4256
4257 /* arch-tag: fe7104da-bc1e-4aba-9bd1-f349c528f7e3
4258 (do not change this comment) */