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