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