]> code.delx.au - gnu-emacs/blobdiff - src/gtkutil.c
(c-basic-common-initc-font-lock-init, c-font-lock-init): Eliminate obsolete make...
[gnu-emacs] / src / gtkutil.c
index 3c4c06a9a53aaa94d5f3ce64c4882d99d493121b..f5f05709e48fce005ccd0d12eeeea79ce1dc5ec9 100644 (file)
@@ -48,6 +48,7 @@ Boston, MA 02111-1307, USA.  */
 #ifdef HAVE_GTK_MULTIDISPLAY
 
 /* Return the GdkDisplay that corresponds to the X display DPY.  */
+
 static GdkDisplay *
 xg_get_gdk_display (dpy)
      Display *dpy;
@@ -58,6 +59,7 @@ xg_get_gdk_display (dpy)
 /* When the GTK widget W is to be created on a display for F that
    is not the default display, set the display for W.
    W can be a GtkMenu or a GtkWindow widget.  */
+
 static void
 xg_set_screen (w, f)
      GtkWidget *w;
@@ -80,6 +82,7 @@ xg_set_screen (w, f)
 
 /* Make some defines so we can use the GTK 2.2 functions when
    compiling with GTK 2.0.  */
+
 #define xg_set_screen(w, f)
 #define gdk_xid_table_lookup_for_display(dpy, w)    gdk_xid_table_lookup (w)
 #define gdk_pixmap_foreign_new_for_display(dpy, p)  gdk_pixmap_foreign_new (p)
@@ -95,6 +98,7 @@ xg_set_screen (w, f)
    Returns non-zero if display could be opened, zero if display could not
    be opened, and less than zero if the GTK version doesn't support
    multipe displays.  */
+
 int
 xg_display_open (display_name, dpy)
      char *display_name;
@@ -115,6 +119,8 @@ xg_display_open (display_name, dpy)
 }
 
 
+/* Close display DPY.  */
+
 void
 xg_display_close (Display *dpy)
 {
@@ -176,6 +182,7 @@ static int malloc_cpt;
    widget_value_free_list or by malloc:ing a new one.
 
    Return a pointer to the allocated structure.  */
+
 widget_value *
 malloc_widget_value ()
 {
@@ -197,6 +204,7 @@ malloc_widget_value ()
 
 /* This is analogous to free.  It frees only what was allocated
    by malloc_widget_value, and no substructures.  */
+
 void
 free_widget_value (wv)
      widget_value *wv;
@@ -221,6 +229,7 @@ free_widget_value (wv)
 
 /* Create and return the cursor to be used for popup menus and
    scroll bars on display DPY.  */
+
 GdkCursor *
 xg_create_default_cursor (dpy)
      Display *dpy;
@@ -239,6 +248,7 @@ xg_create_default_cursor (dpy)
    WIDGET is used to find the GdkColormap to use for the GdkPixbuf.
    If OLD_WIDGET is NULL, a new widget is constructed and returned.
    If OLD_WIDGET is not NULL, that widget is modified.  */
+
 static GtkWidget *
 xg_get_image_for_pixmap (f, img, widget, old_widget)
      FRAME_PTR f;
@@ -248,8 +258,46 @@ xg_get_image_for_pixmap (f, img, widget, old_widget)
 {
   GdkPixmap *gpix;
   GdkPixmap *gmask;
-  GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (FRAME_X_DISPLAY (f));
+  GdkDisplay *gdpy;
+
+  /* If we are on a one bit display, let GTK do all the image handling.
+     This seems to be the only way to make insensitive and activated icons
+     look good.  */
+  if (x_screen_planes (f) == 1)
+    {
+      Lisp_Object specified_file = Qnil;
+      Lisp_Object tail;
+      extern Lisp_Object QCfile;
+
+      for (tail = XCDR (img->spec);
+          NILP (specified_file) && CONSP (tail) && CONSP (XCDR (tail));
+          tail = XCDR (XCDR (tail)))
+       if (EQ (XCAR (tail), QCfile))
+         specified_file = XCAR (XCDR (tail));
 
+       if (STRINGP (specified_file))
+         {
+
+           Lisp_Object file = Qnil;
+           struct gcpro gcpro1;
+           GCPRO1 (file);
+
+           file = x_find_image_file (specified_file);
+           /* We already loaded the image once before calling this
+              function, so this should not fail.  */
+           xassert (STRINGP (file) != 0);
+
+           if (! old_widget)
+             old_widget = GTK_IMAGE (gtk_image_new_from_file (SDATA (file)));
+           else
+             gtk_image_set_from_file (old_widget, SDATA (file));
+
+           UNGCPRO;
+           return GTK_WIDGET (old_widget);
+         }
+    }
+
+  gdpy = gdk_x11_lookup_xdisplay (FRAME_X_DISPLAY (f));
   gpix = gdk_pixmap_foreign_new_for_display (gdpy, img->pixmap);
   gmask = img->mask ? gdk_pixmap_foreign_new_for_display (gdpy, img->mask) : 0;
 
@@ -262,6 +310,12 @@ xg_get_image_for_pixmap (f, img, widget, old_widget)
     }
   else
     {
+      /* This is a workaround to make icons look good on pseudo color
+         displays.  Apparently GTK expects the images to have an alpha
+         channel.  If they don't, insensitive and activated icons will
+         look bad.  This workaround does not work on monochrome displays,
+         and is not needed on true color/static color displays (i.e.
+         16 bits and higher).  */
       int x, y, width, height, rowstride, mask_rowstride;
       GdkPixbuf *icon_buf, *tmp_buf;
       guchar *pixels;
@@ -329,6 +383,7 @@ xg_get_image_for_pixmap (f, img, widget, old_widget)
 /* Set CURSOR on W and all widgets W contain.  We must do like this
    for scroll bars and menu because they create widgets internally,
    and it is those widgets that are visible.  */
+
 static void
 xg_set_cursor (w, cursor)
      GtkWidget *w;
@@ -356,6 +411,7 @@ xg_set_cursor (w, cursor)
     has expired by calling the GTK event loop.
     Also, when a menu is active, it has a small timeout before it
     pops down the sub menu under it.  */
+
 static void
 xg_process_timeouts (timer)
      struct atimer *timer;
@@ -371,6 +427,7 @@ xg_process_timeouts (timer)
 /* Start the xg_timer with an interval of 0.1 seconds, if not already started.
    xg_process_timeouts is called when the timer expires.  The timer
    started is continuous, i.e. runs until xg_stop_timer is called.  */
+
 static void
 xg_start_timer ()
 {
@@ -386,6 +443,7 @@ xg_start_timer ()
 }
 
 /* Stop the xg_timer if started.  */
+
 static void
 xg_stop_timer ()
 {
@@ -397,6 +455,7 @@ xg_stop_timer ()
 }
 
 /* Insert NODE into linked LIST.  */
+
 static void
 xg_list_insert (xg_list_node *list, xg_list_node *node)
 {
@@ -409,6 +468,7 @@ xg_list_insert (xg_list_node *list, xg_list_node *node)
 }
 
 /* Remove NODE from linked LIST.  */
+
 static void
 xg_list_remove (xg_list_node *list, xg_list_node *node)
 {
@@ -429,6 +489,7 @@ xg_list_remove (xg_list_node *list, xg_list_node *node)
    utf8 or NULL, just return STR.
    If not, a new string is allocated and the caller must free the result
    with g_free.  */
+
 static char *
 get_utf8_string (str)
      char *str;
@@ -452,6 +513,7 @@ get_utf8_string (str)
    only way to get geometry position right if the user explicitly
    asked for a position when starting Emacs.
    F is the frame we shall set geometry for.  */
+
 static void
 xg_set_geometry (f)
      FRAME_PTR f;
@@ -485,6 +547,7 @@ xg_set_geometry (f)
 /* Resize the outer window of frame F after chainging the height.
    This happend when the menu bar or the tool bar is added or removed.
    COLUMNS/ROWS is the size the edit area shall have after the resize.  */
+
 static void
 xg_resize_outer_widget (f, columns, rows)
      FRAME_PTR f;
@@ -506,29 +569,12 @@ xg_resize_outer_widget (f, columns, rows)
   gdk_window_process_all_updates ();
 }
 
-/* This gets called after the frame F has been cleared.  Since that is
-   done with X calls, we need to redraw GTK widget (scroll bars).  */
-void
-xg_frame_cleared (f)
-     FRAME_PTR f;
-{
-  GtkWidget *w = f->output_data.x->widget;
-
-  if (w)
-    {
-      gtk_container_set_reallocate_redraws (GTK_CONTAINER (w), TRUE);
-      gtk_container_foreach (GTK_CONTAINER (w),
-                             (GtkCallback) gtk_widget_queue_draw,
-                             0);
-      gdk_window_process_all_updates ();
-    }
-}
-
 /* Function to handle resize of our widgets.  Since Emacs has some layouts
    that does not fit well with GTK standard containers, we do most layout
    manually.
    F is the frame to resize.
    PIXELWIDTH, PIXELHEIGHT is the new size in pixels.  */
+
 void
 xg_resize_widgets (f, pixelwidth, pixelheight)
      FRAME_PTR f;
@@ -541,8 +587,10 @@ xg_resize_widgets (f, pixelwidth, pixelheight)
   int columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, pixelwidth);
 
   if (FRAME_GTK_WIDGET (f)
-      && (columns != FRAME_COLS (f) || rows != FRAME_LINES (f)
-          || pixelwidth != FRAME_PIXEL_WIDTH (f) || pixelheight != FRAME_PIXEL_HEIGHT (f)))
+      && (columns != FRAME_COLS (f) 
+         || rows != FRAME_LINES (f)
+          || pixelwidth != FRAME_PIXEL_WIDTH (f) 
+         || pixelheight != FRAME_PIXEL_HEIGHT (f)))
     {
       struct x_output *x = f->output_data.x;
       GtkAllocation all;
@@ -563,6 +611,7 @@ xg_resize_widgets (f, pixelwidth, pixelheight)
 
 
 /* Update our widget size to be COLS/ROWS characters for frame F.  */
+
 void
 xg_frame_set_char_size (f, cols, rows)
      FRAME_PTR f;
@@ -602,6 +651,7 @@ xg_frame_set_char_size (f, cols, rows)
    X Window that aren't accessible.
 
    Return 0 if no widget match WDESC.  */
+
 GtkWidget *
 xg_win_to_widget (dpy, wdesc)
      Display *dpy;
@@ -627,6 +677,7 @@ xg_win_to_widget (dpy, wdesc)
 
 /* Fill in the GdkColor C so that it represents PIXEL.
    W is the widget that color will be used for.  Used to find colormap.  */
+
 static void
 xg_pix_to_gcolor (w, pixel, c)
      GtkWidget *w;
@@ -637,56 +688,9 @@ xg_pix_to_gcolor (w, pixel, c)
   gdk_colormap_query_color (map, pixel, c);
 }
 
-/* Turning off double buffering for our GtkFixed widget has the side
-   effect of turning it off also for its children (scroll bars).
-   But we want those to be double buffered to not flicker so handle
-   expose manually here.
-   WIDGET is the GtkFixed widget that gets exposed.
-   EVENT is the expose event.
-   USER_DATA is unused.
-
-   Return TRUE to tell GTK that this expose event has been fully handeled
-   and that GTK shall do nothing more with it.  */
-static gboolean
-xg_fixed_handle_expose (GtkWidget *widget,
-                        GdkEventExpose *event,
-                        gpointer user_data)
-{
-  GList *iter;
-
-  for (iter = GTK_FIXED (widget)->children; iter; iter = g_list_next (iter))
-    {
-      GtkFixedChild *child_data = (GtkFixedChild *) iter->data;
-      GtkWidget *child = child_data->widget;
-      GdkWindow *window = child->window;
-      GdkRegion *region = gtk_widget_region_intersect (child, event->region);
-
-      if (! gdk_region_empty (region))
-        {
-          GdkEvent child_event;
-          child_event.expose = *event;
-          child_event.expose.region = region;
-
-          /* Turn on double buffering, i.e. draw to an off screen area.  */
-          gdk_window_begin_paint_region (window, region);
-
-          /* Tell child to redraw itself.  */
-          gdk_region_get_clipbox (region, &child_event.expose.area);
-          gtk_widget_send_expose (child, &child_event);
-          gdk_window_process_updates (window, TRUE);
-
-          /* Copy off screen area to the window.  */
-          gdk_window_end_paint (window);
-        }
-
-      gdk_region_destroy (region);
-     }
-
-  return TRUE;
-}
-
 /* Create and set up the GTK widgets for frame F.
    Return 0 if creation failed, non-zero otherwise.  */
+
 int
 xg_create_frame_widgets (f)
      FRAME_PTR f;
@@ -749,7 +753,7 @@ xg_create_frame_widgets (f)
      up in the wrong place as tool bar height has not been taken into account.
      So we cheat a bit by setting a height that is what it will have
      later on when tool bar items are added.  */
-  if (FRAME_EXTERNAL_TOOL_BAR (f) && FRAME_TOOLBAR_HEIGHT (f) == 0)
+  if (FRAME_EXTERNAL_TOOL_BAR (f) && f->n_tool_bar_items == 0)
     FRAME_TOOLBAR_HEIGHT (f) = 34;
 
 
@@ -760,12 +764,6 @@ xg_create_frame_widgets (f)
      a lot, so we turn off double buffering.  */
   gtk_widget_set_double_buffered (wfixed, FALSE);
 
-  /* Turning off double buffering above has the side effect of turning
-     it off also for its children (scroll bars).  But we want those
-     to be double buffered to not flicker so handle expose manually.  */
-  g_signal_connect (G_OBJECT (wfixed), "expose-event",
-                    G_CALLBACK (xg_fixed_handle_expose), 0);
-
   /* GTK documents says use gtk_window_set_resizable.  But then a user
      can't shrink the window from its starting size.  */
   gtk_window_set_policy (GTK_WINDOW (wtop), TRUE, TRUE, TRUE);
@@ -828,6 +826,7 @@ xg_create_frame_widgets (f)
    that the window now has.
    If USER_POSITION is nonzero, we set the User Position
    flag (this is useful when FLAGS is 0).  */
+
 void
 x_wm_set_size_hint (f, flags, user_position)
      FRAME_PTR f;
@@ -926,6 +925,7 @@ x_wm_set_size_hint (f, flags, user_position)
    keep the GTK and X colors in sync.
    F is the frame to change,
    BG is the pixel value to change to.  */
+
 void
 xg_set_background_color (f, bg)
      FRAME_PTR f;
@@ -949,6 +949,7 @@ xg_set_background_color (f, bg)
  ***********************************************************************/
 /* Return the dialog title to use for a dialog of type KEY.
    This is the encoding used by lwlib.  We use the same for GTK.  */
+
 static char *
 get_dialog_title (char key)
 {
@@ -989,6 +990,7 @@ get_dialog_title (char key)
    user_data is NULL (not used).
 
    Returns TRUE to end propagation of event.  */
+
 static gboolean
 dialog_delete_callback (w, event, user_data)
      GtkWidget *w;
@@ -1005,6 +1007,7 @@ dialog_delete_callback (w, event, user_data)
    DEACTIVATE_CB is the callback to use when the dialog pops down.
 
    Returns the GTK dialog widget.  */
+
 static GtkWidget *
 create_dialog (wv, select_cb, deactivate_cb)
      widget_value *wv;
@@ -1115,6 +1118,10 @@ create_dialog (wv, select_cb, deactivate_cb)
 }
 
 
+\f
+/***********************************************************************
+                      File dialog functions
+ ***********************************************************************/
 enum
 {
   XG_FILE_NOT_DONE,
@@ -1123,10 +1130,90 @@ enum
   XG_FILE_DESTROYED,
 };
 
+#ifdef HAVE_GTK_FILE_BOTH
+int use_old_gtk_file_dialog;
+#endif
+
+
+#ifdef HAVE_GTK_FILE_CHOOSER_DIALOG_NEW
+/* Read a file name from the user using a file chooser dialog.
+   F is the current frame.
+   PROMPT is a prompt to show to the user.  May not be NULL.
+   DEFAULT_FILENAME is a default selection to be displayed.  May be NULL.
+   If MUSTMATCH_P is non-zero, the returned file name must be an existing
+   file.
+
+   Returns a file name or NULL if no file was selected.
+   The returned string must be freed by the caller.  */
+
+static char *
+xg_get_file_with_chooser (f, prompt, default_filename, mustmatch_p, only_dir_p)
+     FRAME_PTR f;
+     char *prompt;
+     char *default_filename;
+     int mustmatch_p, only_dir_p;
+{
+  GtkWidget *filewin;
+  GtkWindow *gwin = GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f));
+
+  char *fn = 0;
+  GtkFileChooserAction action = (mustmatch_p ?
+                                 GTK_FILE_CHOOSER_ACTION_OPEN :
+                                 GTK_FILE_CHOOSER_ACTION_SAVE);
+
+  if (only_dir_p)
+    action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
+
+  filewin = gtk_file_chooser_dialog_new (prompt, gwin, action,
+                                         GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                                         (mustmatch_p || only_dir_p ?
+                                          GTK_STOCK_OPEN : GTK_STOCK_OK),
+                                         GTK_RESPONSE_OK,
+                                         NULL);
+
+  xg_set_screen (filewin, f);
+  gtk_widget_set_name (filewin, "emacs-filedialog");
+  gtk_window_set_transient_for (GTK_WINDOW (filewin), gwin);
+  gtk_window_set_destroy_with_parent (GTK_WINDOW (filewin), TRUE);
+
+
+  if (default_filename)
+    {
+      Lisp_Object file;
+      struct gcpro gcpro1;
+      GCPRO1 (file);
+
+      /* File chooser does not understand ~/... in the file name.  It must be
+         an absolute name starting with /.  */
+      if (default_filename[0] != '/')
+        {
+          file = Fexpand_file_name (build_string (default_filename), Qnil);
+          default_filename = SDATA (file);
+        }
+
+      gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (filewin),
+                                     default_filename);
+
+      UNGCPRO;
+    }
+
+  gtk_widget_show (filewin);
+
+  if (gtk_dialog_run (GTK_DIALOG (filewin)) == GTK_RESPONSE_OK)
+    fn = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (filewin));
+
+  gtk_widget_destroy (filewin);
+
+  return fn;
+}
+#endif /* HAVE_GTK_FILE_CHOOSER_DIALOG_NEW */
+
+#ifdef HAVE_GTK_FILE_SELECTION_NEW
 /* Callback function invoked when the Ok button is pressed in
    a file dialog.
    W is the file dialog widget,
    ARG points to an integer where we record what has happend.  */
+
 static void
 xg_file_sel_ok (w, arg)
      GtkWidget *w;
@@ -1139,6 +1226,7 @@ xg_file_sel_ok (w, arg)
    a file dialog.
    W is the file dialog widget,
    ARG points to an integer where we record what has happend.  */
+
 static void
 xg_file_sel_cancel (w, arg)
      GtkWidget *w;
@@ -1153,6 +1241,7 @@ xg_file_sel_cancel (w, arg)
    the dialog is popped down, but the dialog widget is not destroyed.
    W is the file dialog widget,
    ARG points to an integer where we record what has happend.  */
+
 static void
 xg_file_sel_destroy (w, arg)
      GtkWidget *w;
@@ -1161,7 +1250,7 @@ xg_file_sel_destroy (w, arg)
   *(int*)arg = XG_FILE_DESTROYED;
 }
 
-/* Read a file name from the user using a file dialog.
+/* Read a file name from the user using a file selection dialog.
    F is the current frame.
    PROMPT is a prompt to show to the user.  May not be NULL.
    DEFAULT_FILENAME is a default selection to be displayed.  May be NULL.
@@ -1170,12 +1259,14 @@ xg_file_sel_destroy (w, arg)
 
    Returns a file name or NULL if no file was selected.
    The returned string must be freed by the caller.  */
-char *
-xg_get_file_name (f, prompt, default_filename, mustmatch_p)
+
+static char *
+xg_get_file_with_selection (f, prompt, default_filename,
+                            mustmatch_p, only_dir_p)
      FRAME_PTR f;
      char *prompt;
      char *default_filename;
-     int mustmatch_p;
+     int mustmatch_p, only_dir_p;
 {
   GtkWidget *filewin;
   GtkFileSelection *filesel;
@@ -1186,9 +1277,7 @@ xg_get_file_name (f, prompt, default_filename, mustmatch_p)
   filesel = GTK_FILE_SELECTION (filewin);
 
   xg_set_screen (filewin, f);
-
   gtk_widget_set_name (filewin, "emacs-filedialog");
-
   gtk_window_set_transient_for (GTK_WINDOW (filewin),
                                 GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)));
   gtk_window_set_destroy_with_parent (GTK_WINDOW (filewin), TRUE);
@@ -1230,6 +1319,49 @@ xg_get_file_name (f, prompt, default_filename, mustmatch_p)
 
   return fn;
 }
+#endif /* HAVE_GTK_FILE_SELECTION_NEW */
+
+/* Read a file name from the user using a file dialog, either the old
+   file selection dialog, or the new file chooser dialog.  Which to use
+   depends on what the GTK version used has, and what the value of
+   gtk-use-old-file-dialog.
+   F is the current frame.
+   PROMPT is a prompt to show to the user.  May not be NULL.
+   DEFAULT_FILENAME is a default selection to be displayed.  May be NULL.
+   If MUSTMATCH_P is non-zero, the returned file name must be an existing
+   file.
+
+   Returns a file name or NULL if no file was selected.
+   The returned string must be freed by the caller.  */
+
+char *
+xg_get_file_name (f, prompt, default_filename, mustmatch_p, only_dir_p)
+     FRAME_PTR f;
+     char *prompt;
+     char *default_filename;
+     int mustmatch_p, only_dir_p;
+{
+#ifdef HAVE_GTK_FILE_BOTH
+  if (use_old_gtk_file_dialog)
+    return xg_get_file_with_selection (f, prompt, default_filename,
+                                       mustmatch_p, only_dir_p);
+  return xg_get_file_with_chooser (f, prompt, default_filename,
+                                   mustmatch_p, only_dir_p);
+
+#else /* not HAVE_GTK_FILE_BOTH */
+
+#ifdef HAVE_GTK_FILE_SELECTION_DIALOG_NEW
+  return xg_get_file_with_selection (f, prompt, default_filename,
+                                     mustmatch_p, only_dir_p);
+#endif
+#ifdef HAVE_GTK_FILE_CHOOSER_DIALOG_NEW
+  return xg_get_file_with_chooser (f, prompt, default_filename,
+                                   mustmatch_p, only_dir_p);
+#endif
+
+#endif /* HAVE_GTK_FILE_BOTH */
+  return 0;
+}
 
 \f
 /***********************************************************************
@@ -1260,6 +1392,7 @@ static xg_list_node xg_menu_item_cb_list;
 
    Returns CL_DATA if CL_DATA is not NULL,  or a pointer to a newly
    allocated xg_menu_cb_data if CL_DATA is NULL.  */
+
 static xg_menu_cb_data *
 make_cl_data (cl_data, f, highlight_cb)
      xg_menu_cb_data *cl_data;
@@ -1293,6 +1426,7 @@ make_cl_data (cl_data, f, highlight_cb)
    HIGHLIGHT_CB could change, there is no check that the same
    function is given when modifying a menu bar as was given when
    creating the menu bar.  */
+
 static void
 update_cl_data (cl_data, f, highlight_cb)
      xg_menu_cb_data *cl_data;
@@ -1310,6 +1444,7 @@ update_cl_data (cl_data, f, highlight_cb)
 
 /* Decrease reference count for CL_DATA.
    If reference count is zero, free CL_DATA.  */
+
 static void
 unref_cl_data (cl_data)
      xg_menu_cb_data *cl_data;
@@ -1326,6 +1461,7 @@ unref_cl_data (cl_data)
 }
 
 /* Function that marks all lisp data during GC.  */
+
 void
 xg_mark_data ()
 {
@@ -1347,6 +1483,7 @@ xg_mark_data ()
 /* Callback called when a menu item is destroyed.  Used to free data.
    W is the widget that is being destroyed (not used).
    CLIENT_DATA points to the xg_menu_item_cb_data associated with the W.  */
+
 static void
 menuitem_destroy_callback (w, client_data)
      GtkWidget *w;
@@ -1366,6 +1503,7 @@ menuitem_destroy_callback (w, client_data)
    CLIENT_DATA points to the xg_menu_item_cb_data associated with the W.
 
    Returns FALSE to tell GTK to keep processing this event.  */
+
 static gboolean
 menuitem_highlight_callback (w, event, client_data)
      GtkWidget *w;
@@ -1390,6 +1528,7 @@ menuitem_highlight_callback (w, event, client_data)
 /* Callback called when a menu is destroyed.  Used to free data.
    W is the widget that is being destroyed (not used).
    CLIENT_DATA points to the xg_menu_cb_data associated with W.  */
+
 static void
 menu_destroy_callback (w, client_data)
      GtkWidget *w;
@@ -1405,6 +1544,7 @@ menu_destroy_callback (w, client_data)
    W is the widget that does the grab (not used).
    UNGRAB_P is TRUE if this is an ungrab, FALSE if it is a grab.
    CLIENT_DATA is NULL (not used).  */
+
 static void
 menu_grab_callback (GtkWidget *widget,
                     gboolean ungrab_p,
@@ -1424,6 +1564,7 @@ menu_grab_callback (GtkWidget *widget,
    must be non-NULL) and can be inserted into a menu item.
 
    Returns the GtkHBox.  */
+
 static GtkWidget *
 make_widget_for_menu_item (utf8_label, utf8_key)
      char *utf8_label;
@@ -1463,6 +1604,7 @@ make_widget_for_menu_item (utf8_label, utf8_key)
 
    Unfortunately, keys don't line up as nicely as in Motif,
    but the MacOS X version doesn't either, so I guess that is OK.  */
+
 static GtkWidget *
 make_menu_item (utf8_label, utf8_key, item, group)
      char *utf8_label;
@@ -1512,6 +1654,7 @@ make_menu_item (utf8_label, utf8_key, item, group)
 
 /* Return non-zero if LABEL specifies a separator (GTK only has one
    separator type)  */
+
 static int
 xg_separator_p (char *label)
 {
@@ -1560,6 +1703,7 @@ xg_separator_p (char *label)
 static int xg_detached_menus;
 
 /* Returns non-zero if there are detached menus.  */
+
 int
 xg_have_tear_offs ()
 {
@@ -1570,6 +1714,7 @@ xg_have_tear_offs ()
    decrease the xg_detached_menus count.
    WIDGET is the top level window that is removed (the parent of the menu).
    CLIENT_DATA is not used.  */
+
 static void
 tearoff_remove (widget, client_data)
      GtkWidget *widget;
@@ -1582,6 +1727,7 @@ tearoff_remove (widget, client_data)
    xg_detached_menus count.
    WIDGET is the GtkTearoffMenuItem.
    CLIENT_DATA is not used.  */
+
 static void
 tearoff_activate (widget, client_data)
      GtkWidget *widget;
@@ -1611,6 +1757,7 @@ tearoff_activate (widget, client_data)
    in the group.  On exit, *GROUP contains the radio item group.
 
    Returns the created GtkWidget.  */
+
 static GtkWidget *
 xg_create_one_menuitem (item, f, select_cb, highlight_cb, cl_data, group)
      widget_value *item;
@@ -1828,6 +1975,7 @@ create_menus (data, f, select_cb, deactivate_cb, highlight_cb,
    HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
 
    Returns the widget created.  */
+
 GtkWidget *
 xg_create_widget (type, name, f, val,
                   select_cb, deactivate_cb, highlight_cb)
@@ -1885,6 +2033,7 @@ xg_create_widget (type, name, f, val,
 }
 
 /* Return the label for menu item WITEM.  */
+
 static const char *
 xg_get_menu_item_label (witem)
      GtkMenuItem *witem;
@@ -1894,6 +2043,7 @@ xg_get_menu_item_label (witem)
 }
 
 /* Return non-zero if the menu item WITEM has the text LABEL.  */
+
 static int
 xg_item_label_same_p (witem, label)
      GtkMenuItem *witem;
@@ -1913,10 +2063,10 @@ xg_item_label_same_p (witem, label)
   return is_same;
 }
 
-/* Remove widgets in LIST from container WCONT.  */
+/* Destroy widgets in LIST.  */
+
 static void
-remove_from_container (wcont, list)
-     GtkWidget *wcont;
+xg_destroy_widgets (list)
      GList *list;
 {
   GList *iter;
@@ -1925,15 +2075,7 @@ remove_from_container (wcont, list)
     {
       GtkWidget *w = GTK_WIDGET (iter->data);
 
-      /* Add a ref to w so we can explicitly destroy it later.  */
-      gtk_widget_ref (w);
-      gtk_container_remove (GTK_CONTAINER (wcont), w);
-
-      /* If there is a menu under this widget that has been detached,
-         there is a reference to it, and just removing w from the
-         container does not destroy the submenu.  By explicitly
-         destroying w we make sure the submenu is destroyed, thus
-         removing the detached window also if there was one.  */
+      /* Destroying the widget will remove it from the container it is in.  */
       gtk_widget_destroy (w);
     }
 }
@@ -1949,6 +2091,7 @@ remove_from_container (wcont, list)
    CL_DATA points to the callback data to be used for this menu bar.
 
    This function calls itself to walk through the menu bar names.  */
+
 static void
 xg_update_menubar (menubar, f, list, iter, pos, val,
                    select_cb, highlight_cb, cl_data)
@@ -1967,7 +2110,7 @@ xg_update_menubar (menubar, f, list, iter, pos, val,
   else if (iter && ! val)
     {
       /* Item(s) have been removed.  Remove all remaining items.  */
-      remove_from_container (menubar, iter);
+      xg_destroy_widgets (iter);
 
       /* All updated.  */
       val = 0;
@@ -2121,6 +2264,7 @@ xg_update_menubar (menubar, f, list, iter, pos, val,
    SELECT_CB is the callback to use when a menu item is selected.
    HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
    CL_DATA is the data to set in the widget for menu invokation.  */
+
 static void
 xg_update_menu_item (val, w, select_cb, highlight_cb, cl_data)
      widget_value *val;
@@ -2255,6 +2399,7 @@ xg_update_menu_item (val, w, select_cb, highlight_cb, cl_data)
 }
 
 /* Update the toggle menu item W so it corresponds to VAL.  */
+
 static void
 xg_update_toggle_item (val, w)
      widget_value *val;
@@ -2264,6 +2409,7 @@ xg_update_toggle_item (val, w)
 }
 
 /* Update the radio menu item W so it corresponds to VAL.  */
+
 static void
 xg_update_radio_item (val, w)
      widget_value *val;
@@ -2393,8 +2539,8 @@ xg_update_submenu (submenu, f, val,
     {
       /* If we are adding new menu items below, we must remove from
          first radio button so that radio groups become correct.  */
-      if (cur && first_radio) remove_from_container (submenu, first_radio);
-      else remove_from_container (submenu, iter);
+      if (cur && first_radio) xg_destroy_widgets (first_radio);
+      else xg_destroy_widgets (iter);
     }
 
   if (cur)
@@ -2426,6 +2572,7 @@ xg_update_submenu (submenu, f, val,
    SELECT_CB is the callback to use when a menu item is selected.
    DEACTIVATE_CB is the callback to use when a sub menu is not shown anymore.
    HIGHLIGHT_CB is the callback to call when entering/leaving menu items.  */
+
 void
 xg_modify_menubar_widgets (menubar, f, val, deep_p,
                            select_cb, deactivate_cb, highlight_cb)
@@ -2570,12 +2717,14 @@ free_frame_menubar (f)
 
 /* Setting scroll bar values invokes the callback.  Use this variable
    to indicate that callback should do nothing.  */
+
 int xg_ignore_gtk_scrollbar;
 
 /* SET_SCROLL_BAR_X_WINDOW assumes the second argument fits in
    32 bits.  But we want to store pointers, and they may be larger
    than 32 bits.  Keep a mapping from integer index to widget pointers
    to get around the 32 bit limitation.  */
+
 static struct
 {
   GtkWidget **widgets;
@@ -2584,9 +2733,11 @@ static struct
 } id_to_widget;
 
 /* Grow this much every time we need to allocate more  */
+
 #define ID_TO_WIDGET_INCR  32
 
 /* Store the widget pointer W in id_to_widget and return the integer index.  */
+
 static int
 xg_store_widget_in_map (w)
      GtkWidget *w;
@@ -2625,6 +2776,7 @@ xg_store_widget_in_map (w)
 
 /* Remove pointer at IDX from id_to_widget.
    Called when scroll bar is destroyed.  */
+
 static void
 xg_remove_widget_from_map (idx)
      int idx;
@@ -2637,6 +2789,7 @@ xg_remove_widget_from_map (idx)
 }
 
 /* Get the widget pointer at IDX from id_to_widget. */
+
 static GtkWidget *
 xg_get_widget_from_map (idx)
      int idx;
@@ -2649,6 +2802,7 @@ xg_get_widget_from_map (idx)
 
 /* Return the scrollbar id for X Window WID on display DPY.
    Return -1 if WID not in id_to_widget.  */
+
 int
 xg_get_scroll_id_for_window (dpy, wid)
      Display *dpy;
@@ -2672,6 +2826,7 @@ xg_get_scroll_id_for_window (dpy, wid)
 /* Callback invoked when scroll bar WIDGET is destroyed.
    DATA is the index into id_to_widget for WIDGET.
    We free pointer to last scroll bar values here and remove the index.  */
+
 static void
 xg_gtk_scroll_destroy (widget, data)
      GtkWidget *widget;
@@ -2694,6 +2849,7 @@ xg_gtk_scroll_destroy (widget, data)
 
    Returns FALSE to tell GTK that it shall continue propagate the event
    to widgets.  */
+
 static gboolean
 scroll_bar_button_cb (widget, event, user_data)
      GtkWidget *widget;
@@ -2718,6 +2874,7 @@ scroll_bar_button_cb (widget, event, user_data)
    bar changes.
    SCROLL_BAR_NAME is the name we use for the scroll bar.  Can be used
    to set resources for the widget.  */
+
 void
 xg_create_scroll_bar (f, bar, scroll_callback, scroll_bar_name)
      FRAME_PTR f;
@@ -2726,6 +2883,7 @@ xg_create_scroll_bar (f, bar, scroll_callback, scroll_bar_name)
      char *scroll_bar_name;
 {
   GtkWidget *wscroll;
+  GtkWidget *webox;
   GtkObject *vadj;
   int scroll_id;
 
@@ -2735,6 +2893,7 @@ xg_create_scroll_bar (f, bar, scroll_callback, scroll_bar_name)
                              0.1, 0.1, 0.1);
 
   wscroll = gtk_vscrollbar_new (GTK_ADJUSTMENT (vadj));
+  webox = gtk_event_box_new ();
   gtk_widget_set_name (wscroll, scroll_bar_name);
   gtk_range_set_update_policy (GTK_RANGE (wscroll), GTK_UPDATE_CONTINUOUS);
 
@@ -2760,26 +2919,35 @@ xg_create_scroll_bar (f, bar, scroll_callback, scroll_bar_name)
                     G_CALLBACK (scroll_bar_button_cb),
                     (gpointer) bar);
 
-  gtk_fixed_put (GTK_FIXED (f->output_data.x->edit_widget),
-                 wscroll, -1, -1);
+  /* The scroll bar widget does not draw on a window of its own.  Instead
+     it draws on the parent window, in this case the edit widget.  So
+     whenever the edit widget is cleared, the scroll bar needs to redraw
+     also, which causes flicker.  Put an event box between the edit widget
+     and the scroll bar, so the scroll bar instead draws itself on the
+     event box window.  */
+  gtk_fixed_put (GTK_FIXED (f->output_data.x->edit_widget), webox, -1, -1);
+  gtk_container_add (GTK_CONTAINER (webox), wscroll);
+  
 
   /* Set the cursor to an arrow.  */
-  xg_set_cursor (wscroll, FRAME_X_DISPLAY_INFO (f)->xg_cursor);
+  xg_set_cursor (webox, FRAME_X_DISPLAY_INFO (f)->xg_cursor);
 
   SET_SCROLL_BAR_X_WINDOW (bar, scroll_id);
 }
 
 /* Make the scroll bar represented by SCROLLBAR_ID visible.  */
+
 void
 xg_show_scroll_bar (scrollbar_id)
      int scrollbar_id;
 {
   GtkWidget *w = xg_get_widget_from_map (scrollbar_id);
   if (w)
-    gtk_widget_show (w);
+    gtk_widget_show_all (gtk_widget_get_parent (w));
 }
 
 /* Remove the scroll bar represented by SCROLLBAR_ID from the frame F.  */
+
 void
 xg_remove_scroll_bar (f, scrollbar_id)
      FRAME_PTR f;
@@ -2788,42 +2956,20 @@ xg_remove_scroll_bar (f, scrollbar_id)
   GtkWidget *w = xg_get_widget_from_map (scrollbar_id);
   if (w)
     {
+      GtkWidget *wparent = gtk_widget_get_parent (w);
       gtk_widget_destroy (w);
+      gtk_widget_destroy (wparent);
       SET_FRAME_GARBAGED (f);
     }
 }
 
-/* Find left/top for widget W in GtkFixed widget WFIXED.  */
-static void
-xg_find_top_left_in_fixed (w, wfixed, left, top)
-     GtkWidget *w, *wfixed;
-     int *left, *top;
-{
-  GList *iter;
-
-  for (iter = GTK_FIXED (wfixed)->children; iter; iter = g_list_next (iter))
-    {
-      GtkFixedChild *child = (GtkFixedChild *) iter->data;
-
-      if (child->widget == w)
-        {
-          *left = child->x;
-          *top = child->y;
-          return;
-        }
-    }
-
-  /* Shall never end up here.  */
-  abort ();
-}
-
 /* Update the position of the vertical scroll bar represented by SCROLLBAR_ID
    in frame F.
    TOP/LEFT are the new pixel positions where the bar shall appear.
    WIDTH, HEIGHT is the size in pixels the bar shall have.  */
+
 void
-xg_update_scrollbar_pos (f, scrollbar_id, top, left, width, height,
-                         real_left, canon_width)
+xg_update_scrollbar_pos (f, scrollbar_id, top, left, width, height)
      FRAME_PTR f;
      int scrollbar_id;
      int top;
@@ -2837,44 +2983,11 @@ xg_update_scrollbar_pos (f, scrollbar_id, top, left, width, height,
   if (wscroll)
     {
       GtkWidget *wfixed = f->output_data.x->edit_widget;
-
-      gtk_container_set_reallocate_redraws (GTK_CONTAINER (wfixed), TRUE);
+      GtkWidget *wparent = gtk_widget_get_parent (wscroll);
 
       /* Move and resize to new values.  */
-      gtk_fixed_move (GTK_FIXED (wfixed), wscroll, left, top);
       gtk_widget_set_size_request (wscroll, width, height);
-
-      /* Must force out update so changed scroll bars gets redrawn.  */
-      gdk_window_process_all_updates ();
-      
-      /* Scroll bars in GTK has a fixed width, so if we say width 16, it
-         will only be its fixed width (14 is default) anyway, the rest is
-         blank.  We are drawing the mode line across scroll bars when
-         the frame is split:
-                               |bar| |fringe|
-                              ----------------
-                              mode line
-                              ----------------
-                               |bar| |fringe|
-
-         When we "unsplit" the frame:
-
-                               |bar| |fringe|
-                              -|   |-|      |
-                              m¦   |i|      |
-                              -|   |-|      |
-                               |   | |      |
-
-
-         the remains of the mode line can be seen in these blank spaces.
-         So we must clear them explicitly.
-         GTK scroll bars should do that, but they don't.
-         Also, the canonical width may be wider than the width for the
-         scroll bar so that there is some space (typically 1 pixel) between
-         the scroll bar and the edge of the window and between the scroll
-         bar and the fringe.  */
-
-      XClearWindow (FRAME_X_DISPLAY (f), GTK_WIDGET_TO_X_WIN (wscroll));
+      gtk_fixed_move (GTK_FIXED (wfixed), wparent, left, top);
 
       SET_FRAME_GARBAGED (f);
       cancel_mouse_face (f);
@@ -2883,6 +2996,7 @@ xg_update_scrollbar_pos (f, scrollbar_id, top, left, width, height,
 
 /* Set the thumb size and position of scroll bar BAR.  We are currently
    displaying PORTION out of a whole WHOLE, and our position POSITION.  */
+
 void
 xg_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
      struct scroll_bar *bar;
@@ -2975,6 +3089,7 @@ xg_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
    W is the button widget in the tool bar that got pressed,
    CLIENT_DATA is an integer that is the index of the button in the
    tool bar.  0 is the first button.  */
+
 static void
 xg_tool_bar_callback (w, client_data)
      GtkWidget *w;
@@ -3011,6 +3126,7 @@ xg_tool_bar_callback (w, client_data)
    WBOX is the handle box widget that enables detach/attach of the tool bar.
    W is the tool bar widget.
    CLIENT_DATA is a pointer to the frame the tool bar belongs to.  */
+
 static void
 xg_tool_bar_detach_callback (wbox, w, client_data)
      GtkHandleBox *wbox;
@@ -3039,6 +3155,7 @@ xg_tool_bar_detach_callback (wbox, w, client_data)
    WBOX is the handle box widget that enables detach/attach of the tool bar.
    W is the tool bar widget.
    CLIENT_DATA is a pointer to the frame the tool bar belongs to.  */
+
 static void
 xg_tool_bar_attach_callback (wbox, w, client_data)
      GtkHandleBox *wbox;
@@ -3068,6 +3185,7 @@ xg_tool_bar_attach_callback (wbox, w, client_data)
    tool bar.  0 is the first button.
 
    Returns FALSE to tell GTK to keep processing this event.  */
+
 static gboolean
 xg_tool_bar_help_callback (w, event, client_data)
      GtkWidget *w;
@@ -3113,6 +3231,7 @@ xg_tool_bar_help_callback (w, event, client_data)
    CLIENT_DATA is unused.
 
    Returns FALSE to tell GTK to keep processing this event.  */
+
 static gboolean
 xg_tool_bar_item_expose_callback (w, event, client_data)
      GtkWidget *w;
@@ -3143,6 +3262,7 @@ xg_tool_bar_item_expose_callback (w, event, client_data)
    CLIENT_DATA is pointing to the frame for this tool bar.
 
    Returns FALSE to tell GTK to keep processing this event.  */
+
 static gboolean
 xg_tool_bar_expose_callback (w, event, client_data)
      GtkWidget *w;
@@ -3153,6 +3273,8 @@ xg_tool_bar_expose_callback (w, event, client_data)
   return FALSE;
 }
 
+/* Create a tool bar for frame F.  */
+
 static void
 xg_create_tool_bar (f)
      FRAME_PTR f;
@@ -3206,6 +3328,8 @@ xg_create_tool_bar (f)
   SET_FRAME_GARBAGED (f);
 }
 
+/* Update the tool bar for frame F.  Add new buttons and remove old.  */
+
 void
 update_frame_tool_bar (f)
      FRAME_PTR f;
@@ -3373,6 +3497,9 @@ update_frame_tool_bar (f)
   UNBLOCK_INPUT;
 }
 
+/* Deallocate all resources for the tool bar on frame F.
+   Remove the tool bar.  */
+
 void
 free_frame_tool_bar (f)
      FRAME_PTR f;