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