X-Git-Url: https://git.hcoop.net/bpt/emacs.git/blobdiff_plain/2b5b82db4975fdfa2818d9184a026d041a941263..95df8112a0cbdb06addbac5fbea03b37d4440418:/src/gtkutil.c
diff --git a/src/gtkutil.c b/src/gtkutil.c
index 7a25bbb1e3..6367949a64 100644
--- a/src/gtkutil.c
+++ b/src/gtkutil.c
@@ -1,6 +1,6 @@
/* Functions for creating and updating GTK widgets.
- Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
- Free Software Foundation, Inc.
+
+Copyright (C) 2003-2011 Free Software Foundation, Inc.
This file is part of GNU Emacs.
@@ -20,7 +20,6 @@ along with GNU Emacs. If not, see . */
#include
#ifdef USE_GTK
-#include
#include
#include
#include
@@ -35,6 +34,7 @@ along with GNU Emacs. If not, see . */
#include "charset.h"
#include "coding.h"
#include
+#include "xsettings.h"
#ifdef HAVE_XFT
#include
@@ -43,16 +43,39 @@ along with GNU Emacs. If not, see . */
#define FRAME_TOTAL_PIXEL_HEIGHT(f) \
(FRAME_PIXEL_HEIGHT (f) + FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f))
-/* Avoid "differ in sign" warnings */
-#define SSDATA(x) ((char *) SDATA (x))
+#define FRAME_TOTAL_PIXEL_WIDTH(f) \
+ (FRAME_PIXEL_WIDTH (f) + FRAME_TOOLBAR_WIDTH (f))
+
+#ifndef HAVE_GTK_WIDGET_SET_HAS_WINDOW
+#define gtk_widget_set_has_window(w, b) \
+ (gtk_fixed_set_has_window (GTK_FIXED (w), b))
+#endif
+#ifndef HAVE_GTK_DIALOG_GET_ACTION_AREA
+#define gtk_dialog_get_action_area(w) ((w)->action_area)
+#define gtk_dialog_get_content_area(w) ((w)->vbox)
+#endif
+#ifndef HAVE_GTK_WIDGET_GET_SENSITIVE
+#define gtk_widget_get_sensitive(w) (GTK_WIDGET_SENSITIVE (w))
+#endif
+#ifndef HAVE_GTK_ADJUSTMENT_GET_PAGE_SIZE
+#define gtk_adjustment_set_page_size(w, s) ((w)->page_size = (s))
+#define gtk_adjustment_set_page_increment(w, s) ((w)->page_increment = (s))
+#define gtk_adjustment_get_step_increment(w) ((w)->step_increment)
+#define gtk_adjustment_set_step_increment(w, s) ((w)->step_increment = (s))
+#endif
+#if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 11
+#define remove_submenu(w) gtk_menu_item_set_submenu ((w), NULL)
+#else
+#define remove_submenu(w) gtk_menu_item_remove_submenu ((w))
+#endif
+
+#define XG_BIN_CHILD(x) gtk_bin_get_child (GTK_BIN (x))
/***********************************************************************
Display handling functions
***********************************************************************/
-#ifdef HAVE_GTK_MULTIDISPLAY
-
/* Keep track of the default display, or NULL if there is none. Emacs
may close all its displays. */
@@ -63,9 +86,7 @@ static GdkDisplay *gdpy_def;
W can be a GtkMenu or a GtkWindow widget. */
static void
-xg_set_screen (w, f)
- GtkWidget *w;
- FRAME_PTR f;
+xg_set_screen (GtkWidget *w, FRAME_PTR f)
{
if (FRAME_X_DISPLAY (f) != GDK_DISPLAY ())
{
@@ -80,20 +101,6 @@ xg_set_screen (w, f)
}
-#else /* not HAVE_GTK_MULTIDISPLAY */
-
-/* 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)
-#define gdk_cursor_new_for_display(dpy, c) gdk_cursor_new (c)
-#define gdk_x11_lookup_xdisplay(dpy) 0
-#define GdkDisplay void
-
-#endif /* not HAVE_GTK_MULTIDISPLAY */
-
/* Open a display named by DISPLAY_NAME. The display is returned in *DPY.
*DPY is set to NULL if the display can't be opened.
@@ -101,12 +108,9 @@ xg_set_screen (w, f)
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;
- Display **dpy;
+void
+xg_display_open (char *display_name, Display **dpy)
{
-#ifdef HAVE_GTK_MULTIDISPLAY
GdkDisplay *gdpy;
gdpy = gdk_display_open (display_name);
@@ -118,12 +122,6 @@ xg_display_open (display_name, dpy)
}
*dpy = gdpy ? GDK_DISPLAY_XDISPLAY (gdpy) : NULL;
- return gdpy != NULL;
-
-#else /* not HAVE_GTK_MULTIDISPLAY */
-
- return -1;
-#endif /* not HAVE_GTK_MULTIDISPLAY */
}
@@ -132,7 +130,6 @@ xg_display_open (display_name, dpy)
void
xg_display_close (Display *dpy)
{
-#ifdef HAVE_GTK_MULTIDISPLAY
GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (dpy);
/* If this is the default display, try to change it before closing.
@@ -164,7 +161,6 @@ xg_display_close (Display *dpy)
/* This seems to be fixed in GTK 2.10. */
gdk_display_close (gdpy);
#endif
-#endif /* HAVE_GTK_MULTIDISPLAY */
}
@@ -181,7 +177,7 @@ static int malloc_cpt;
Return a pointer to the allocated structure. */
widget_value *
-malloc_widget_value ()
+malloc_widget_value (void)
{
widget_value *wv;
if (widget_value_free_list)
@@ -203,8 +199,7 @@ malloc_widget_value ()
by malloc_widget_value, and no substructures. */
void
-free_widget_value (wv)
- widget_value *wv;
+free_widget_value (widget_value *wv)
{
if (wv->free_list)
abort ();
@@ -228,8 +223,7 @@ free_widget_value (wv)
scroll bars on display DPY. */
GdkCursor *
-xg_create_default_cursor (dpy)
- Display *dpy;
+xg_create_default_cursor (Display *dpy)
{
GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (dpy);
return gdk_cursor_new_for_display (gdpy, GDK_LEFT_PTR);
@@ -238,10 +232,9 @@ xg_create_default_cursor (dpy)
/* Apply GMASK to GPIX and return a GdkPixbuf with an alpha channel. */
static GdkPixbuf *
-xg_get_pixbuf_from_pix_and_mask (gpix, gmask, cmap)
- GdkPixmap *gpix;
- GdkPixmap *gmask;
- GdkColormap *cmap;
+xg_get_pixbuf_from_pix_and_mask (GdkPixmap *gpix,
+ GdkPixmap *gmask,
+ GdkColormap *cmap)
{
int width, height;
GdkPixbuf *icon_buf, *tmp_buf;
@@ -292,12 +285,10 @@ xg_get_pixbuf_from_pix_and_mask (gpix, gmask, cmap)
}
static Lisp_Object
-file_for_image (image)
- Lisp_Object image;
+file_for_image (Lisp_Object image)
{
Lisp_Object specified_file = Qnil;
Lisp_Object tail;
- extern Lisp_Object QCfile;
for (tail = XCDR (image);
NILP (specified_file) && CONSP (tail) && CONSP (XCDR (tail));
@@ -320,11 +311,10 @@ file_for_image (image)
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;
- struct image *img;
- GtkWidget *widget;
- GtkImage *old_widget;
+xg_get_image_for_pixmap (FRAME_PTR f,
+ struct image *img,
+ GtkWidget *widget,
+ GtkImage *old_widget)
{
GdkPixmap *gpix;
GdkPixmap *gmask;
@@ -392,13 +382,12 @@ xg_get_image_for_pixmap (f, img, widget, old_widget)
and it is those widgets that are visible. */
static void
-xg_set_cursor (w, cursor)
- GtkWidget *w;
- GdkCursor *cursor;
+xg_set_cursor (GtkWidget *w, GdkCursor *cursor)
{
- GList *children = gdk_window_peek_children (w->window);
+ GdkWindow *window = gtk_widget_get_window(w);
+ GList *children = gdk_window_peek_children (window);
- gdk_window_set_cursor (w->window, cursor);
+ gdk_window_set_cursor (window, cursor);
/* The scroll bar widget has more than one GDK window (had to look at
the source to figure this out), and there is no way to set cursor
@@ -441,21 +430,22 @@ xg_list_remove (xg_list_node *list, xg_list_node *node)
}
/* Allocate and return a utf8 version of STR. If STR is already
- utf8 or NULL, just return STR.
- If not, a new string is allocated and the caller must free the result
+ utf8 or NULL, just return a copy of STR.
+ A new string is allocated and the caller must free the result
with g_free. */
static char *
-get_utf8_string (str)
- char *str;
+get_utf8_string (const char *str)
{
- char *utf8_str = str;
+ char *utf8_str;
if (!str) return NULL;
/* If not UTF-8, try current locale. */
if (!g_utf8_validate (str, -1, NULL))
utf8_str = g_locale_to_utf8 (str, -1, 0, 0, 0);
+ else
+ return g_strdup (str);
if (!utf8_str)
{
@@ -514,6 +504,209 @@ get_utf8_string (str)
return utf8_str;
}
+/* Check for special colors used in face spec for region face.
+ The colors are fetched from the Gtk+ theme.
+ Return 1 if color was found, 0 if not. */
+
+int
+xg_check_special_colors (struct frame *f,
+ const char *color_name,
+ XColor *color)
+{
+ int success_p = 0;
+ if (FRAME_GTK_WIDGET (f))
+ {
+ if (strcmp ("gtk_selection_bg_color", color_name) == 0)
+ {
+ GtkStyle *gsty = gtk_widget_get_style (FRAME_GTK_WIDGET (f));
+ color->red = gsty->bg[GTK_STATE_SELECTED].red;
+ color->green = gsty->bg[GTK_STATE_SELECTED].green;
+ color->blue = gsty->bg[GTK_STATE_SELECTED].blue;
+ color->pixel = gsty->bg[GTK_STATE_SELECTED].pixel;
+ success_p = 1;
+ }
+ else if (strcmp ("gtk_selection_fg_color", color_name) == 0)
+ {
+ GtkStyle *gsty = gtk_widget_get_style (FRAME_GTK_WIDGET (f));
+ color->red = gsty->fg[GTK_STATE_SELECTED].red;
+ color->green = gsty->fg[GTK_STATE_SELECTED].green;
+ color->blue = gsty->fg[GTK_STATE_SELECTED].blue;
+ color->pixel = gsty->fg[GTK_STATE_SELECTED].pixel;
+ success_p = 1;
+ }
+ }
+
+ return success_p;
+}
+
+
+
+/***********************************************************************
+ Tooltips
+ ***********************************************************************/
+/* Gtk+ calls this callback when the parent of our tooltip dummy changes.
+ We use that to pop down the tooltip. This happens if Gtk+ for some
+ reason wants to change or hide the tooltip. */
+
+#ifdef USE_GTK_TOOLTIP
+
+static void
+hierarchy_ch_cb (GtkWidget *widget,
+ GtkWidget *previous_toplevel,
+ gpointer user_data)
+{
+ FRAME_PTR f = (FRAME_PTR) user_data;
+ struct x_output *x = f->output_data.x;
+ GtkWidget *top = gtk_widget_get_toplevel (x->ttip_lbl);
+
+ if (! top || ! GTK_IS_WINDOW (top))
+ gtk_widget_hide (previous_toplevel);
+}
+
+/* Callback called when Gtk+ thinks a tooltip should be displayed.
+ We use it to get the tooltip window and the tooltip widget so
+ we can manipulate the ourselves.
+
+ Return FALSE ensures that the tooltip is not shown. */
+
+static gboolean
+qttip_cb (GtkWidget *widget,
+ gint xpos,
+ gint ypos,
+ gboolean keyboard_mode,
+ GtkTooltip *tooltip,
+ gpointer user_data)
+{
+ FRAME_PTR f = (FRAME_PTR) user_data;
+ struct x_output *x = f->output_data.x;
+ if (x->ttip_widget == NULL)
+ {
+ g_object_set (G_OBJECT (widget), "has-tooltip", FALSE, NULL);
+ x->ttip_widget = tooltip;
+ g_object_ref (G_OBJECT (tooltip));
+ x->ttip_lbl = gtk_label_new ("");
+ g_object_ref (G_OBJECT (x->ttip_lbl));
+ gtk_tooltip_set_custom (tooltip, x->ttip_lbl);
+ x->ttip_window = GTK_WINDOW (gtk_widget_get_toplevel (x->ttip_lbl));
+ /* ATK needs an empty title for some reason. */
+ gtk_window_set_title (x->ttip_window, "");
+ /* Realize so we can safely get screen later on. */
+ gtk_widget_realize (GTK_WIDGET (x->ttip_window));
+ gtk_widget_realize (x->ttip_lbl);
+
+ g_signal_connect (x->ttip_lbl, "hierarchy-changed",
+ G_CALLBACK (hierarchy_ch_cb), f);
+ }
+ return FALSE;
+}
+
+#endif /* USE_GTK_TOOLTIP */
+
+/* Prepare a tooltip to be shown, i.e. calculate WIDTH and HEIGHT.
+ Return zero if no system tooltip available, non-zero otherwise. */
+
+int
+xg_prepare_tooltip (FRAME_PTR f,
+ Lisp_Object string,
+ int *width,
+ int *height)
+{
+#ifndef USE_GTK_TOOLTIP
+ return 0;
+#else
+ struct x_output *x = f->output_data.x;
+ GtkWidget *widget;
+ GdkWindow *gwin;
+ GdkScreen *screen;
+ GtkSettings *settings;
+ gboolean tt_enabled = TRUE;
+ GtkRequisition req;
+ Lisp_Object encoded_string;
+
+ if (!x->ttip_lbl) return 0;
+
+ BLOCK_INPUT;
+ encoded_string = ENCODE_UTF_8 (string);
+ widget = GTK_WIDGET (x->ttip_lbl);
+ gwin = gtk_widget_get_window (GTK_WIDGET (x->ttip_window));
+ screen = gdk_drawable_get_screen (gwin);
+ settings = gtk_settings_get_for_screen (screen);
+ g_object_get (settings, "gtk-enable-tooltips", &tt_enabled, NULL);
+ if (tt_enabled)
+ {
+ g_object_set (settings, "gtk-enable-tooltips", FALSE, NULL);
+ /* Record that we disabled it so it can be enabled again. */
+ g_object_set_data (G_OBJECT (x->ttip_window), "restore-tt",
+ (gpointer)f);
+ }
+
+ /* Prevent Gtk+ from hiding tooltip on mouse move and such. */
+ g_object_set_data (G_OBJECT
+ (gtk_widget_get_display (GTK_WIDGET (x->ttip_window))),
+ "gdk-display-current-tooltip", NULL);
+
+ /* Put out dummy widget in so we can get callbacks for unrealize and
+ hierarchy-changed. */
+ gtk_tooltip_set_custom (x->ttip_widget, widget);
+
+ gtk_tooltip_set_text (x->ttip_widget, SDATA (encoded_string));
+ gtk_widget_size_request (GTK_WIDGET (x->ttip_window), &req);
+ if (width) *width = req.width;
+ if (height) *height = req.height;
+
+ UNBLOCK_INPUT;
+
+ return 1;
+#endif /* USE_GTK_TOOLTIP */
+}
+
+/* Show the tooltip at ROOT_X and ROOT_Y.
+ xg_prepare_tooltip must have been called before this function. */
+
+void
+xg_show_tooltip (FRAME_PTR f, int root_x, int root_y)
+{
+#ifdef USE_GTK_TOOLTIP
+ struct x_output *x = f->output_data.x;
+ if (x->ttip_window)
+ {
+ BLOCK_INPUT;
+ gtk_window_move (x->ttip_window, root_x, root_y);
+ gtk_widget_show_all (GTK_WIDGET (x->ttip_window));
+ UNBLOCK_INPUT;
+ }
+#endif
+}
+
+/* Hide tooltip if shown. Do nothing if not shown.
+ Return non-zero if tip was hidden, non-ero if not (i.e. not using
+ system tooltips). */
+
+int
+xg_hide_tooltip (FRAME_PTR f)
+{
+ int ret = 0;
+#ifdef USE_GTK_TOOLTIP
+ if (f->output_data.x->ttip_window)
+ {
+ GtkWindow *win = f->output_data.x->ttip_window;
+ BLOCK_INPUT;
+ gtk_widget_hide (GTK_WIDGET (win));
+
+ if (g_object_get_data (G_OBJECT (win), "restore-tt"))
+ {
+ GdkWindow *gwin = gtk_widget_get_window (GTK_WIDGET (win));
+ GdkScreen *screen = gdk_drawable_get_screen (gwin);
+ GtkSettings *settings = gtk_settings_get_for_screen (screen);
+ g_object_set (settings, "gtk-enable-tooltips", TRUE, NULL);
+ }
+ UNBLOCK_INPUT;
+
+ ret = 1;
+ }
+#endif
+ return ret;
+}
/***********************************************************************
@@ -526,10 +719,9 @@ get_utf8_string (str)
F is the frame we shall set geometry for. */
static void
-xg_set_geometry (f)
- FRAME_PTR f;
+xg_set_geometry (FRAME_PTR f)
{
- if (f->size_hint_flags & USPosition)
+ if (f->size_hint_flags & (USPosition | PPosition))
{
int left = f->left_pos;
int xneg = f->size_hint_flags & XNegative;
@@ -544,7 +736,7 @@ xg_set_geometry (f)
sprintf (geom_str, "=%dx%d%c%d%c%d",
FRAME_PIXEL_WIDTH (f),
- FRAME_TOTAL_PIXEL_HEIGHT (f),
+ FRAME_PIXEL_HEIGHT (f),
(xneg ? '-' : '+'), left,
(yneg ? '-' : '+'), top);
@@ -552,17 +744,13 @@ xg_set_geometry (f)
geom_str))
fprintf (stderr, "Failed to parse: '%s'\n", geom_str);
}
- else if (f->size_hint_flags & PPosition)
- gtk_window_move (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
- f->left_pos, f->top_pos);
}
/* Clear under internal border if any. As we use a mix of Gtk+ and X calls
and use a GtkFixed widget, this doesn't happen automatically. */
static void
-xg_clear_under_internal_border (f)
- FRAME_PTR f;
+xg_clear_under_internal_border (FRAME_PTR f)
{
if (FRAME_INTERNAL_BORDER_WIDTH (f) > 0)
{
@@ -600,20 +788,19 @@ xg_clear_under_internal_border (f)
PIXELWIDTH, PIXELHEIGHT is the new size in pixels. */
void
-xg_frame_resized (f, pixelwidth, pixelheight)
- FRAME_PTR f;
- int pixelwidth, pixelheight;
+xg_frame_resized (FRAME_PTR f, int pixelwidth, int pixelheight)
{
int rows, columns;
if (pixelwidth == -1 && pixelheight == -1)
{
- if (FRAME_GTK_WIDGET (f) && GTK_WIDGET_MAPPED (FRAME_GTK_WIDGET (f)))
- gdk_window_get_geometry (FRAME_GTK_WIDGET (f)->window, 0, 0,
+ if (FRAME_GTK_WIDGET (f) && gtk_widget_get_mapped (FRAME_GTK_WIDGET (f)))
+ gdk_window_get_geometry (gtk_widget_get_window (FRAME_GTK_WIDGET (f)),
+ 0, 0,
&pixelwidth, &pixelheight, 0);
else return;
}
-
+
rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, pixelheight);
columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, pixelwidth);
@@ -637,10 +824,7 @@ xg_frame_resized (f, pixelwidth, pixelheight)
COLUMNS/ROWS is the size the edit area shall have after the resize. */
void
-xg_frame_set_char_size (f, cols, rows)
- FRAME_PTR f;
- int cols;
- int rows;
+xg_frame_set_char_size (FRAME_PTR f, int cols, int rows)
{
int pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows)
+ FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f);
@@ -661,7 +845,8 @@ xg_frame_set_char_size (f, cols, rows)
/* FRAME_TEXT_COLS_TO_PIXEL_WIDTH uses scroll_bar_actual_width, so call it
after calculating that value. */
- pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, cols);
+ pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, cols)
+ + FRAME_TOOLBAR_WIDTH (f);
/* Do this before resize, as we don't know yet if we will be resized. */
@@ -698,15 +883,15 @@ xg_frame_set_char_size (f, cols, rows)
}
}
-/* Handle height changes (i.e. add/remove menu/toolbar).
+/* Handle height/width changes (i.e. add/remove/move menu/toolbar).
The policy is to keep the number of editable lines. */
static void
-xg_height_changed (f)
- FRAME_PTR f;
+xg_height_or_width_changed (FRAME_PTR f)
{
gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
- FRAME_PIXEL_WIDTH (f), FRAME_TOTAL_PIXEL_HEIGHT (f));
+ FRAME_TOTAL_PIXEL_WIDTH (f),
+ FRAME_TOTAL_PIXEL_HEIGHT (f));
f->output_data.x->hint_flags = 0;
x_wm_set_size_hint (f, 0, 0);
}
@@ -718,9 +903,7 @@ xg_height_changed (f)
Return 0 if no widget match WDESC. */
GtkWidget *
-xg_win_to_widget (dpy, wdesc)
- Display *dpy;
- Window wdesc;
+xg_win_to_widget (Display *dpy, Window wdesc)
{
gpointer gdkwin;
GtkWidget *gwdesc = 0;
@@ -744,24 +927,40 @@ xg_win_to_widget (dpy, wdesc)
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;
- unsigned long pixel;
- GdkColor *c;
+xg_pix_to_gcolor (GtkWidget *w, long unsigned int pixel, GdkColor *c)
{
GdkColormap *map = gtk_widget_get_colormap (w);
gdk_colormap_query_color (map, pixel, c);
}
+/* Callback called when the gtk theme changes.
+ We notify lisp code so it can fix faces used for region for example. */
+
+static void
+style_changed_cb (GObject *go,
+ GParamSpec *spec,
+ gpointer user_data)
+{
+ struct input_event event;
+ GdkDisplay *gdpy = (GdkDisplay *) user_data;
+ const char *display_name = gdk_display_get_name (gdpy);
+
+ EVENT_INIT (event);
+ event.kind = CONFIG_CHANGED_EVENT;
+ event.frame_or_window = make_string (display_name, strlen (display_name));
+ /* Theme doesn't change often, so intern is called seldom. */
+ event.arg = intern ("theme-name");
+ kbd_buffer_store_event (&event);
+}
+
/* 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;
+xg_create_frame_widgets (FRAME_PTR f)
{
GtkWidget *wtop;
- GtkWidget *wvbox;
+ GtkWidget *wvbox, *whbox;
GtkWidget *wfixed;
GdkColor bg;
GtkRcStyle *style;
@@ -777,12 +976,14 @@ xg_create_frame_widgets (f)
xg_set_screen (wtop, f);
wvbox = gtk_vbox_new (FALSE, 0);
+ whbox = gtk_hbox_new (FALSE, 0);
wfixed = gtk_fixed_new (); /* Must have this to place scroll bars */
- if (! wtop || ! wvbox || ! wfixed)
+ if (! wtop || ! wvbox || ! whbox || ! wfixed)
{
if (wtop) gtk_widget_destroy (wtop);
if (wvbox) gtk_widget_destroy (wvbox);
+ if (whbox) gtk_widget_destroy (whbox);
if (wfixed) gtk_widget_destroy (wfixed);
UNBLOCK_INPUT;
@@ -803,11 +1004,13 @@ xg_create_frame_widgets (f)
FRAME_GTK_OUTER_WIDGET (f) = wtop;
FRAME_GTK_WIDGET (f) = wfixed;
f->output_data.x->vbox_widget = wvbox;
+ f->output_data.x->hbox_widget = whbox;
- gtk_fixed_set_has_window (GTK_FIXED (wfixed), TRUE);
+ gtk_widget_set_has_window (wfixed, TRUE);
gtk_container_add (GTK_CONTAINER (wtop), wvbox);
- gtk_box_pack_end (GTK_BOX (wvbox), wfixed, TRUE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (wvbox), whbox, TRUE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (whbox), wfixed, TRUE, TRUE, 0);
if (FRAME_EXTERNAL_TOOL_BAR (f))
update_frame_tool_bar (f);
@@ -866,17 +1069,54 @@ xg_create_frame_widgets (f)
style->bg_pixmap_name[GTK_STATE_NORMAL] = g_strdup ("");
gtk_widget_modify_style (wfixed, style);
- /* GTK does not set any border, and they look bad with GTK. */
- /* That they look bad is no excuse for imposing this here. --Stef
- It should be done by providing the proper default in Fx_create_Frame.
- f->border_width = 0;
- f->internal_border_width = 0; */
+#ifdef USE_GTK_TOOLTIP
+ /* Steal a tool tip window we can move ourselves. */
+ f->output_data.x->ttip_widget = 0;
+ f->output_data.x->ttip_lbl = 0;
+ f->output_data.x->ttip_window = 0;
+ gtk_widget_set_tooltip_text (wtop, "Dummy text");
+ g_signal_connect (wtop, "query-tooltip", G_CALLBACK (qttip_cb), f);
+#endif
+
+ {
+ GdkScreen *screen = gtk_widget_get_screen (wtop);
+ GtkSettings *gs = gtk_settings_get_for_screen (screen);
+ /* Only connect this signal once per screen. */
+ if (! g_signal_handler_find (G_OBJECT (gs),
+ G_SIGNAL_MATCH_FUNC,
+ 0, 0, 0,
+ G_CALLBACK (style_changed_cb),
+ 0))
+ {
+ g_signal_connect (G_OBJECT (gs), "notify::gtk-theme-name",
+ G_CALLBACK (style_changed_cb),
+ gdk_screen_get_display (screen));
+ }
+ }
UNBLOCK_INPUT;
return 1;
}
+void
+xg_free_frame_widgets (FRAME_PTR f)
+{
+ if (FRAME_GTK_OUTER_WIDGET (f))
+ {
+ struct x_output *x = f->output_data.x;
+ gtk_widget_destroy (FRAME_GTK_OUTER_WIDGET (f));
+ FRAME_X_WINDOW (f) = 0; /* Set to avoid XDestroyWindow in xterm.c */
+ FRAME_GTK_OUTER_WIDGET (f) = 0;
+#ifdef USE_GTK_TOOLTIP
+ if (x->ttip_lbl)
+ gtk_widget_destroy (x->ttip_lbl);
+ if (x->ttip_widget)
+ g_object_unref (G_OBJECT (x->ttip_widget));
+#endif
+ }
+}
+
/* Set the normal size hints for the window manager, for frame F.
FLAGS is the flags word to use--or 0 meaning preserve the flags
that the window now has.
@@ -884,10 +1124,7 @@ xg_create_frame_widgets (f)
flag (this is useful when FLAGS is 0). */
void
-x_wm_set_size_hint (f, flags, user_position)
- FRAME_PTR f;
- long flags;
- int user_position;
+x_wm_set_size_hint (FRAME_PTR f, long int flags, int user_position)
{
/* Must use GTK routines here, otherwise GTK resets the size hints
to its own defaults. */
@@ -920,7 +1157,7 @@ x_wm_set_size_hint (f, flags, user_position)
size_hints.height_inc = FRAME_LINE_HEIGHT (f);
hint_flags |= GDK_HINT_BASE_SIZE;
- base_width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, 0);
+ base_width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, 0) + FRAME_TOOLBAR_WIDTH (f);
base_height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, 0)
+ FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f);
@@ -956,10 +1193,6 @@ x_wm_set_size_hint (f, flags, user_position)
else if (win_gravity == StaticGravity)
size_hints.win_gravity = GDK_GRAVITY_STATIC;
- if (flags & PPosition) hint_flags |= GDK_HINT_POS;
- if (flags & USPosition) hint_flags |= GDK_HINT_USER_POS;
- if (flags & USSize) hint_flags |= GDK_HINT_USER_SIZE;
-
if (user_position)
{
hint_flags &= ~GDK_HINT_POS;
@@ -987,9 +1220,7 @@ x_wm_set_size_hint (f, flags, user_position)
BG is the pixel value to change to. */
void
-xg_set_background_color (f, bg)
- FRAME_PTR f;
- unsigned long bg;
+xg_set_background_color (FRAME_PTR f, long unsigned int bg)
{
if (FRAME_GTK_WIDGET (f))
{
@@ -1007,10 +1238,7 @@ xg_set_background_color (f, bg)
functions so GTK does not overwrite the icon. */
void
-xg_set_frame_icon (f, icon_pixmap, icon_mask)
- FRAME_PTR f;
- Pixmap icon_pixmap;
- Pixmap icon_mask;
+xg_set_frame_icon (FRAME_PTR f, Pixmap icon_pixmap, Pixmap icon_mask)
{
GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (FRAME_X_DISPLAY (f));
GdkPixmap *gpix = gdk_pixmap_foreign_new_for_display (gdpy, icon_pixmap);
@@ -1028,10 +1256,10 @@ xg_set_frame_icon (f, icon_pixmap, icon_mask)
/* 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 *
+static const char *
get_dialog_title (char key)
{
- char *title = "";
+ const char *title = "";
switch (key) {
case 'E': case 'e':
@@ -1070,10 +1298,7 @@ get_dialog_title (char key)
Returns TRUE to end propagation of event. */
static gboolean
-dialog_delete_callback (w, event, user_data)
- GtkWidget *w;
- GdkEvent *event;
- gpointer user_data;
+dialog_delete_callback (GtkWidget *w, GdkEvent *event, gpointer user_data)
{
gtk_widget_unmap (w);
return TRUE;
@@ -1087,20 +1312,20 @@ dialog_delete_callback (w, event, user_data)
Returns the GTK dialog widget. */
static GtkWidget *
-create_dialog (wv, select_cb, deactivate_cb)
- widget_value *wv;
- GCallback select_cb;
- GCallback deactivate_cb;
+create_dialog (widget_value *wv,
+ GCallback select_cb,
+ GCallback deactivate_cb)
{
- char *title = get_dialog_title (wv->name[0]);
+ const char *title = get_dialog_title (wv->name[0]);
int total_buttons = wv->name[1] - '0';
int right_buttons = wv->name[4] - '0';
int left_buttons;
int button_nr = 0;
int button_spacing = 10;
GtkWidget *wdialog = gtk_dialog_new ();
+ GtkDialog *wd = GTK_DIALOG (wdialog);
+ GtkBox *cur_box = GTK_BOX (gtk_dialog_get_action_area (wd));
widget_value *item;
- GtkBox *cur_box;
GtkWidget *wvbox;
GtkWidget *whbox_up;
GtkWidget *whbox_down;
@@ -1115,7 +1340,6 @@ create_dialog (wv, select_cb, deactivate_cb)
gtk_window_set_title (GTK_WINDOW (wdialog), title);
gtk_widget_set_name (wdialog, "emacs-dialog");
- cur_box = GTK_BOX (GTK_DIALOG (wdialog)->action_area);
if (make_two_rows)
{
@@ -1147,21 +1371,18 @@ create_dialog (wv, select_cb, deactivate_cb)
if (item->name && strcmp (item->name, "message") == 0)
{
+ GtkBox *wvbox = GTK_BOX (gtk_dialog_get_content_area (wd));
/* This is the text part of the dialog. */
w = gtk_label_new (utf8_label);
- gtk_box_pack_start (GTK_BOX (GTK_DIALOG (wdialog)->vbox),
- gtk_label_new (""),
- FALSE, FALSE, 0);
- gtk_box_pack_start (GTK_BOX (GTK_DIALOG (wdialog)->vbox), w,
- TRUE, TRUE, 0);
+ gtk_box_pack_start (wvbox, gtk_label_new (""), FALSE, FALSE, 0);
+ gtk_box_pack_start (wvbox, w, TRUE, TRUE, 0);
gtk_misc_set_alignment (GTK_MISC (w), 0.1, 0.5);
/* Try to make dialog look better. Must realize first so
the widget can calculate the size it needs. */
gtk_widget_realize (w);
gtk_widget_size_request (w, &req);
- gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (wdialog)->vbox),
- req.height);
+ gtk_box_set_spacing (wvbox, req.height);
if (item->value && strlen (item->value) > 0)
button_spacing = 2*req.width/strlen (item->value);
}
@@ -1188,7 +1409,7 @@ create_dialog (wv, select_cb, deactivate_cb)
}
}
- if (utf8_label && utf8_label != item->value)
+ if (utf8_label)
g_free (utf8_label);
}
@@ -1208,12 +1429,9 @@ struct xg_dialog_data
USER_DATA is what we passed in to g_signal_connect. */
static void
-xg_dialog_response_cb (w,
- response,
- user_data)
- GtkDialog *w;
- gint response;
- gpointer user_data;
+xg_dialog_response_cb (GtkDialog *w,
+ gint response,
+ gpointer user_data)
{
struct xg_dialog_data *dd = (struct xg_dialog_data *)user_data;
dd->response = response;
@@ -1224,8 +1442,7 @@ xg_dialog_response_cb (w,
/* Destroy the dialog. This makes it pop down. */
static Lisp_Object
-pop_down_dialog (arg)
- Lisp_Object arg;
+pop_down_dialog (Lisp_Object arg)
{
struct Lisp_Save_Value *p = XSAVE_VALUE (arg);
struct xg_dialog_data *dd = (struct xg_dialog_data *) p->pointer;
@@ -1236,7 +1453,7 @@ pop_down_dialog (arg)
g_main_loop_quit (dd->loop);
g_main_loop_unref (dd->loop);
-
+
UNBLOCK_INPUT;
return Qnil;
@@ -1246,8 +1463,7 @@ pop_down_dialog (arg)
We pass in DATA as gpointer* so we can use this as a callback. */
static gboolean
-xg_maybe_add_timer (data)
- gpointer data;
+xg_maybe_add_timer (gpointer data)
{
struct xg_dialog_data *dd = (struct xg_dialog_data *) data;
EMACS_TIME next_time = timer_check (1);
@@ -1265,16 +1481,13 @@ xg_maybe_add_timer (data)
return FALSE;
}
-
+
/* Pops up a modal dialog W and waits for response.
We don't use gtk_dialog_run because we want to process emacs timers.
The dialog W is not destroyed when this function returns. */
static int
-xg_dialog_run (f, w)
- FRAME_PTR f;
- GtkWidget *w;
-
+xg_dialog_run (FRAME_PTR f, GtkWidget *w)
{
int count = SPECPDL_INDEX ();
struct xg_dialog_data dd;
@@ -1302,7 +1515,7 @@ xg_dialog_run (f, w)
(void) xg_maybe_add_timer (&dd);
g_main_loop_run (dd.loop);
-
+
dd.w = 0;
unbind_to (count, Qnil);
@@ -1317,33 +1530,23 @@ xg_dialog_run (f, w)
Return zero if not. */
int
-xg_uses_old_file_dialog ()
+xg_uses_old_file_dialog (void)
{
-#ifdef HAVE_GTK_FILE_BOTH
- extern int x_gtk_use_old_file_dialog;
- return x_gtk_use_old_file_dialog;
-#else /* ! HAVE_GTK_FILE_BOTH */
-
#ifdef HAVE_GTK_FILE_SELECTION_NEW
- return 1;
+ return x_gtk_use_old_file_dialog;
#else
return 0;
#endif
-
-#endif /* ! HAVE_GTK_FILE_BOTH */
}
-typedef char * (*xg_get_file_func) P_ ((GtkWidget *));
-
-#ifdef HAVE_GTK_FILE_CHOOSER_DIALOG_NEW
+typedef char * (*xg_get_file_func) (GtkWidget *);
/* Return the selected file for file chooser dialog W.
The returned string must be free:d. */
static char *
-xg_get_file_name_from_chooser (w)
- GtkWidget *w;
+xg_get_file_name_from_chooser (GtkWidget *w)
{
return gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (w));
}
@@ -1352,9 +1555,7 @@ xg_get_file_name_from_chooser (w)
WIDGET is the toggle widget, DATA is the file chooser dialog. */
static void
-xg_toggle_visibility_cb (widget, data)
- GtkWidget *widget;
- gpointer data;
+xg_toggle_visibility_cb (GtkWidget *widget, gpointer data)
{
GtkFileChooser *dialog = GTK_FILE_CHOOSER (data);
gboolean visible;
@@ -1370,13 +1571,8 @@ xg_toggle_visibility_cb (widget, data)
changes that property by right clicking in the file list. */
static void
-xg_toggle_notify_cb (gobject, arg1, user_data)
- GObject *gobject;
- GParamSpec *arg1;
- gpointer user_data;
+xg_toggle_notify_cb (GObject *gobject, GParamSpec *arg1, gpointer user_data)
{
- extern int x_gtk_show_hidden_files;
-
if (strcmp (arg1->name, "show-hidden") == 0)
{
GtkWidget *wtoggle = GTK_WIDGET (user_data);
@@ -1411,13 +1607,11 @@ xg_toggle_notify_cb (gobject, arg1, user_data)
Returns the created widget. */
static GtkWidget *
-xg_get_file_with_chooser (f, prompt, default_filename,
- mustmatch_p, only_dir_p, func)
- FRAME_PTR f;
- char *prompt;
- char *default_filename;
- int mustmatch_p, only_dir_p;
- xg_get_file_func *func;
+xg_get_file_with_chooser (FRAME_PTR f,
+ char *prompt,
+ char *default_filename,
+ int mustmatch_p, int only_dir_p,
+ xg_get_file_func *func)
{
char message[1024];
@@ -1426,9 +1620,6 @@ xg_get_file_with_chooser (f, prompt, default_filename,
GtkFileChooserAction action = (mustmatch_p ?
GTK_FILE_CHOOSER_ACTION_OPEN :
GTK_FILE_CHOOSER_ACTION_SAVE);
- extern int x_gtk_show_hidden_files;
- extern int x_gtk_file_dialog_help_text;
-
if (only_dir_p)
action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
@@ -1513,7 +1704,6 @@ xg_get_file_with_chooser (f, prompt, default_filename,
*func = xg_get_file_name_from_chooser;
return filewin;
}
-#endif /* HAVE_GTK_FILE_CHOOSER_DIALOG_NEW */
#ifdef HAVE_GTK_FILE_SELECTION_NEW
@@ -1521,8 +1711,7 @@ xg_get_file_with_chooser (f, prompt, default_filename,
The returned string must be free:d. */
static char *
-xg_get_file_name_from_selector (w)
- GtkWidget *w;
+xg_get_file_name_from_selector (GtkWidget *w)
{
GtkFileSelection *filesel = GTK_FILE_SELECTION (w);
return xstrdup ((char*) gtk_file_selection_get_filename (filesel));
@@ -1539,13 +1728,11 @@ xg_get_file_name_from_selector (w)
Returns the created widget. */
static GtkWidget *
-xg_get_file_with_selection (f, prompt, default_filename,
- mustmatch_p, only_dir_p, func)
- FRAME_PTR f;
- char *prompt;
- char *default_filename;
- int mustmatch_p, only_dir_p;
- xg_get_file_func *func;
+xg_get_file_with_selection (FRAME_PTR f,
+ char *prompt,
+ char *default_filename,
+ int mustmatch_p, int only_dir_p,
+ xg_get_file_func *func)
{
GtkWidget *filewin;
GtkFileSelection *filesel;
@@ -1583,11 +1770,11 @@ xg_get_file_with_selection (f, prompt, default_filename,
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;
+xg_get_file_name (FRAME_PTR f,
+ char *prompt,
+ char *default_filename,
+ int mustmatch_p,
+ int only_dir_p)
{
GtkWidget *w = 0;
char *fn = 0;
@@ -1601,7 +1788,7 @@ xg_get_file_name (f, prompt, default_filename, mustmatch_p, only_dir_p)
sigblock (sigmask (__SIGRTMIN));
#endif /* HAVE_GTK_AND_PTHREAD */
-#ifdef HAVE_GTK_FILE_BOTH
+#ifdef HAVE_GTK_FILE_SELECTION_NEW
if (xg_uses_old_file_dialog ())
w = xg_get_file_with_selection (f, prompt, default_filename,
@@ -1610,18 +1797,10 @@ xg_get_file_name (f, prompt, default_filename, mustmatch_p, only_dir_p)
w = xg_get_file_with_chooser (f, prompt, default_filename,
mustmatch_p, only_dir_p, &func);
-#else /* not HAVE_GTK_FILE_BOTH */
-
-#ifdef HAVE_GTK_FILE_SELECTION_NEW
- w = xg_get_file_with_selection (f, prompt, default_filename,
- mustmatch_p, only_dir_p, &func);
-#endif
-#ifdef HAVE_GTK_FILE_CHOOSER_DIALOG_NEW
+#else /* not HAVE_GTK_FILE_SELECTION_NEW */
w = xg_get_file_with_chooser (f, prompt, default_filename,
mustmatch_p, only_dir_p, &func);
-#endif
-
-#endif /* HAVE_GTK_FILE_BOTH */
+#endif /* not HAVE_GTK_FILE_SELECTION_NEW */
gtk_widget_set_name (w, "emacs-filedialog");
@@ -1649,9 +1828,7 @@ xg_get_file_name (f, prompt, default_filename, mustmatch_p, only_dir_p)
DEFAULT_NAME, if non-zero, is the default font name. */
char *
-xg_get_font_name (f, default_name)
- FRAME_PTR f;
- char *default_name;
+xg_get_font_name (FRAME_PTR f, const char *default_name)
{
GtkWidget *w;
char *fontname = NULL;
@@ -1716,10 +1893,7 @@ static xg_list_node xg_menu_item_cb_list;
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;
- FRAME_PTR f;
- GCallback highlight_cb;
+make_cl_data (xg_menu_cb_data *cl_data, FRAME_PTR f, GCallback highlight_cb)
{
if (! cl_data)
{
@@ -1750,10 +1924,9 @@ make_cl_data (cl_data, f, highlight_cb)
creating the menu bar. */
static void
-update_cl_data (cl_data, f, highlight_cb)
- xg_menu_cb_data *cl_data;
- FRAME_PTR f;
- GCallback highlight_cb;
+update_cl_data (xg_menu_cb_data *cl_data,
+ FRAME_PTR f,
+ GCallback highlight_cb)
{
if (cl_data)
{
@@ -1768,8 +1941,7 @@ update_cl_data (cl_data, f, highlight_cb)
If reference count is zero, free CL_DATA. */
static void
-unref_cl_data (cl_data)
- xg_menu_cb_data *cl_data;
+unref_cl_data (xg_menu_cb_data *cl_data)
{
if (cl_data && cl_data->ref_count > 0)
{
@@ -1785,7 +1957,7 @@ unref_cl_data (cl_data)
/* Function that marks all lisp data during GC. */
void
-xg_mark_data ()
+xg_mark_data (void)
{
xg_list_node *iter;
@@ -1807,9 +1979,7 @@ xg_mark_data ()
CLIENT_DATA points to the xg_menu_item_cb_data associated with the W. */
static void
-menuitem_destroy_callback (w, client_data)
- GtkWidget *w;
- gpointer client_data;
+menuitem_destroy_callback (GtkWidget *w, gpointer client_data)
{
if (client_data)
{
@@ -1827,10 +1997,9 @@ menuitem_destroy_callback (w, client_data)
Returns FALSE to tell GTK to keep processing this event. */
static gboolean
-menuitem_highlight_callback (w, event, client_data)
- GtkWidget *w;
- GdkEventCrossing *event;
- gpointer client_data;
+menuitem_highlight_callback (GtkWidget *w,
+ GdkEventCrossing *event,
+ gpointer client_data)
{
GdkEvent ev;
GtkWidget *subwidget;
@@ -1858,9 +2027,7 @@ menuitem_highlight_callback (w, event, client_data)
CLIENT_DATA points to the xg_menu_cb_data associated with W. */
static void
-menu_destroy_callback (w, client_data)
- GtkWidget *w;
- gpointer client_data;
+menu_destroy_callback (GtkWidget *w, gpointer client_data)
{
unref_cl_data ((xg_menu_cb_data*) client_data);
}
@@ -1871,9 +2038,7 @@ menu_destroy_callback (w, client_data)
Returns the GtkHBox. */
static GtkWidget *
-make_widget_for_menu_item (utf8_label, utf8_key)
- char *utf8_label;
- char *utf8_key;
+make_widget_for_menu_item (const char *utf8_label, const char *utf8_key)
{
GtkWidget *wlbl;
GtkWidget *wkey;
@@ -1911,11 +2076,10 @@ make_widget_for_menu_item (utf8_label, utf8_key)
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;
- char *utf8_key;
- widget_value *item;
- GSList **group;
+make_menu_item (const char *utf8_label,
+ const char *utf8_key,
+ widget_value *item,
+ GSList **group)
{
GtkWidget *w;
GtkWidget *wtoadd = 0;
@@ -1957,60 +2121,12 @@ make_menu_item (utf8_label, utf8_key, item, group)
return w;
}
-/* Return non-zero if LABEL specifies a separator (GTK only has one
- separator type) */
-
-static const char* separator_names[] = {
- "space",
- "no-line",
- "single-line",
- "double-line",
- "single-dashed-line",
- "double-dashed-line",
- "shadow-etched-in",
- "shadow-etched-out",
- "shadow-etched-in-dash",
- "shadow-etched-out-dash",
- "shadow-double-etched-in",
- "shadow-double-etched-out",
- "shadow-double-etched-in-dash",
- "shadow-double-etched-out-dash",
- 0,
-};
-
-static int
-xg_separator_p (char *label)
-{
- if (! label) return 0;
- else if (strlen (label) > 3
- && strncmp (label, "--", 2) == 0
- && label[2] != '-')
- {
- int i;
-
- label += 2;
- for (i = 0; separator_names[i]; ++i)
- if (strcmp (label, separator_names[i]) == 0)
- return 1;
- }
- else
- {
- /* Old-style separator, maybe. It's a separator if it contains
- only dashes. */
- while (*label == '-')
- ++label;
- if (*label == 0) return 1;
- }
-
- return 0;
-}
-
static int xg_detached_menus;
/* Returns non-zero if there are detached menus. */
int
-xg_have_tear_offs ()
+xg_have_tear_offs (void)
{
return xg_detached_menus > 0;
}
@@ -2021,9 +2137,7 @@ xg_have_tear_offs ()
CLIENT_DATA is not used. */
static void
-tearoff_remove (widget, client_data)
- GtkWidget *widget;
- gpointer client_data;
+tearoff_remove (GtkWidget *widget, gpointer client_data)
{
if (xg_detached_menus > 0) --xg_detached_menus;
}
@@ -2034,9 +2148,7 @@ tearoff_remove (widget, client_data)
CLIENT_DATA is not used. */
static void
-tearoff_activate (widget, client_data)
- GtkWidget *widget;
- gpointer client_data;
+tearoff_activate (GtkWidget *widget, gpointer client_data)
{
GtkWidget *menu = gtk_widget_get_parent (widget);
if (gtk_menu_get_tearoff_state (GTK_MENU (menu)))
@@ -2064,13 +2176,12 @@ tearoff_activate (widget, client_data)
Returns the created GtkWidget. */
static GtkWidget *
-xg_create_one_menuitem (item, f, select_cb, highlight_cb, cl_data, group)
- widget_value *item;
- FRAME_PTR f;
- GCallback select_cb;
- GCallback highlight_cb;
- xg_menu_cb_data *cl_data;
- GSList **group;
+xg_create_one_menuitem (widget_value *item,
+ FRAME_PTR f,
+ GCallback select_cb,
+ GCallback highlight_cb,
+ xg_menu_cb_data *cl_data,
+ GSList **group)
{
char *utf8_label;
char *utf8_key;
@@ -2082,8 +2193,8 @@ xg_create_one_menuitem (item, f, select_cb, highlight_cb, cl_data, group)
w = make_menu_item (utf8_label, utf8_key, item, group);
- if (utf8_label && utf8_label != item->name) g_free (utf8_label);
- if (utf8_key && utf8_key != item->key) g_free (utf8_key);
+ if (utf8_label) g_free (utf8_label);
+ if (utf8_key) g_free (utf8_key);
cb_data = xmalloc (sizeof (xg_menu_item_cb_data));
@@ -2113,10 +2224,6 @@ xg_create_one_menuitem (item, f, select_cb, highlight_cb, cl_data, group)
return w;
}
-static GtkWidget *create_menus P_ ((widget_value *, FRAME_PTR, GCallback,
- GCallback, GCallback, int, int, int,
- GtkWidget *, xg_menu_cb_data *, char *));
-
/* Create a full menu tree specified by DATA.
F is the frame the created menu belongs to.
SELECT_CB is the callback to use when a menu item is selected.
@@ -2140,19 +2247,17 @@ static GtkWidget *create_menus P_ ((widget_value *, FRAME_PTR, GCallback,
This function calls itself to create submenus. */
static GtkWidget *
-create_menus (data, f, select_cb, deactivate_cb, highlight_cb,
- pop_up_p, menu_bar_p, add_tearoff_p, topmenu, cl_data, name)
- widget_value *data;
- FRAME_PTR f;
- GCallback select_cb;
- GCallback deactivate_cb;
- GCallback highlight_cb;
- int pop_up_p;
- int menu_bar_p;
- int add_tearoff_p;
- GtkWidget *topmenu;
- xg_menu_cb_data *cl_data;
- char *name;
+create_menus (widget_value *data,
+ FRAME_PTR f,
+ GCallback select_cb,
+ GCallback deactivate_cb,
+ GCallback highlight_cb,
+ int pop_up_p,
+ int menu_bar_p,
+ int add_tearoff_p,
+ GtkWidget *topmenu,
+ xg_menu_cb_data *cl_data,
+ const char *name)
{
widget_value *item;
GtkWidget *wmenu = topmenu;
@@ -2214,7 +2319,7 @@ create_menus (data, f, select_cb, deactivate_cb, highlight_cb,
GtkWidget *w;
if (pop_up_p && !item->contents && !item->call_data
- && !xg_separator_p (item->name))
+ && !menu_separator_name_p (item->name))
{
char *utf8_label;
/* A title for a popup. We do the same as GTK does when
@@ -2225,9 +2330,9 @@ create_menus (data, f, select_cb, deactivate_cb, highlight_cb,
gtk_menu_set_title (GTK_MENU (wmenu), utf8_label);
w = gtk_menu_item_new_with_label (utf8_label);
gtk_widget_set_sensitive (w, FALSE);
- if (utf8_label && utf8_label != item->name) g_free (utf8_label);
+ if (utf8_label) g_free (utf8_label);
}
- else if (xg_separator_p (item->name))
+ else if (menu_separator_name_p (item->name))
{
group = NULL;
/* GTK only have one separator type. */
@@ -2284,15 +2389,9 @@ create_menus (data, f, select_cb, deactivate_cb, highlight_cb,
Returns the widget created. */
GtkWidget *
-xg_create_widget (type, name, f, val,
- select_cb, deactivate_cb, highlight_cb)
- char *type;
- char *name;
- FRAME_PTR f;
- widget_value *val;
- GCallback select_cb;
- GCallback deactivate_cb;
- GCallback highlight_cb;
+xg_create_widget (const char *type, const char *name, FRAME_PTR f, widget_value *val,
+ GCallback select_cb, GCallback deactivate_cb,
+ GCallback highlight_cb)
{
GtkWidget *w = 0;
int menu_bar_p = strcmp (type, "menubar") == 0;
@@ -2343,19 +2442,16 @@ 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;
+xg_get_menu_item_label (GtkMenuItem *witem)
{
- GtkLabel *wlabel = GTK_LABEL (gtk_bin_get_child (GTK_BIN (witem)));
+ GtkLabel *wlabel = GTK_LABEL (XG_BIN_CHILD (witem));
return gtk_label_get_label (wlabel);
}
/* Return non-zero if the menu item WITEM has the text LABEL. */
static int
-xg_item_label_same_p (witem, label)
- GtkMenuItem *witem;
- char *label;
+xg_item_label_same_p (GtkMenuItem *witem, const char *label)
{
int is_same = 0;
char *utf8_label = get_utf8_string (label);
@@ -2366,7 +2462,7 @@ xg_item_label_same_p (witem, label)
else if (old_label && utf8_label)
is_same = strcmp (utf8_label, old_label) == 0;
- if (utf8_label && utf8_label != label) g_free (utf8_label);
+ if (utf8_label) g_free (utf8_label);
return is_same;
}
@@ -2374,8 +2470,7 @@ xg_item_label_same_p (witem, label)
/* Destroy widgets in LIST. */
static void
-xg_destroy_widgets (list)
- GList *list;
+xg_destroy_widgets (GList *list)
{
GList *iter;
@@ -2401,18 +2496,16 @@ xg_destroy_widgets (list)
This function calls itself to walk through the menu bar names. */
static void
-xg_update_menubar (menubar, f, list, iter, pos, val,
- select_cb, deactivate_cb, highlight_cb, cl_data)
- GtkWidget *menubar;
- FRAME_PTR f;
- GList **list;
- GList *iter;
- int pos;
- widget_value *val;
- GCallback select_cb;
- GCallback deactivate_cb;
- GCallback highlight_cb;
- xg_menu_cb_data *cl_data;
+xg_update_menubar (GtkWidget *menubar,
+ FRAME_PTR f,
+ GList **list,
+ GList *iter,
+ int pos,
+ widget_value *val,
+ GCallback select_cb,
+ GCallback deactivate_cb,
+ GCallback highlight_cb,
+ xg_menu_cb_data *cl_data)
{
if (! iter && ! val)
return;
@@ -2479,7 +2572,7 @@ xg_update_menubar (menubar, f, list, iter, pos, val,
New: A C
Remove B. */
- gtk_widget_ref (GTK_WIDGET (witem));
+ g_object_ref (G_OBJECT (witem));
gtk_container_remove (GTK_CONTAINER (menubar), GTK_WIDGET (witem));
gtk_widget_destroy (GTK_WIDGET (witem));
@@ -2504,7 +2597,7 @@ xg_update_menubar (menubar, f, list, iter, pos, val,
Rename X to B (minibuf to C-mode menu).
If the X menu hasn't been invoked, the menu under B
is up to date when leaving the minibuffer. */
- GtkLabel *wlabel = GTK_LABEL (gtk_bin_get_child (GTK_BIN (witem)));
+ GtkLabel *wlabel = GTK_LABEL (XG_BIN_CHILD (witem));
char *utf8_label = get_utf8_string (val->name);
GtkWidget *submenu = gtk_menu_item_get_submenu (witem);
@@ -2516,6 +2609,7 @@ xg_update_menubar (menubar, f, list, iter, pos, val,
/* Set the title of the detached window. */
gtk_menu_set_title (GTK_MENU (submenu), utf8_label);
+ if (utf8_label) g_free (utf8_label);
iter = g_list_next (iter);
val = val->next;
++pos;
@@ -2528,7 +2622,7 @@ xg_update_menubar (menubar, f, list, iter, pos, val,
Insert X. */
int nr = pos;
- GList *group = 0;
+ GSList *group = 0;
GtkWidget *w = xg_create_one_menuitem (val,
f,
select_cb,
@@ -2561,11 +2655,11 @@ xg_update_menubar (menubar, f, list, iter, pos, val,
New: A C B
Move C before B */
- gtk_widget_ref (GTK_WIDGET (witem2));
+ g_object_ref (G_OBJECT (witem2));
gtk_container_remove (GTK_CONTAINER (menubar), GTK_WIDGET (witem2));
gtk_menu_shell_insert (GTK_MENU_SHELL (menubar),
GTK_WIDGET (witem2), pos);
- gtk_widget_unref (GTK_WIDGET (witem2));
+ g_object_unref (G_OBJECT (witem2));
g_list_free (*list);
*list = iter = gtk_container_get_children (GTK_CONTAINER (menubar));
@@ -2587,12 +2681,11 @@ xg_update_menubar (menubar, f, list, iter, pos, val,
CL_DATA is the data to set in the widget for menu invocation. */
static void
-xg_update_menu_item (val, w, select_cb, highlight_cb, cl_data)
- widget_value *val;
- GtkWidget *w;
- GCallback select_cb;
- GCallback highlight_cb;
- xg_menu_cb_data *cl_data;
+xg_update_menu_item (widget_value *val,
+ GtkWidget *w,
+ GCallback select_cb,
+ GCallback highlight_cb,
+ xg_menu_cb_data *cl_data)
{
GtkWidget *wchild;
GtkLabel *wlbl = 0;
@@ -2603,7 +2696,7 @@ xg_update_menu_item (val, w, select_cb, highlight_cb, cl_data)
const char *old_key = 0;
xg_menu_item_cb_data *cb_data;
- wchild = gtk_bin_get_child (GTK_BIN (w));
+ wchild = XG_BIN_CHILD (w);
utf8_label = get_utf8_string (val->name);
utf8_key = get_utf8_string (val->key);
@@ -2619,9 +2712,10 @@ xg_update_menu_item (val, w, select_cb, highlight_cb, cl_data)
if (! utf8_key)
{
/* Remove the key and keep just the label. */
- gtk_widget_ref (GTK_WIDGET (wlbl));
+ g_object_ref (G_OBJECT (wlbl));
gtk_container_remove (GTK_CONTAINER (w), wchild);
gtk_container_add (GTK_CONTAINER (w), GTK_WIDGET (wlbl));
+ g_object_unref (G_OBJECT (wlbl));
wkey = 0;
}
@@ -2655,12 +2749,12 @@ xg_update_menu_item (val, w, select_cb, highlight_cb, cl_data)
if (! old_label || strcmp (utf8_label, old_label) != 0)
gtk_label_set_text (wlbl, utf8_label);
- if (utf8_key && utf8_key != val->key) g_free (utf8_key);
- if (utf8_label && utf8_label != val->name) g_free (utf8_label);
+ if (utf8_key) g_free (utf8_key);
+ if (utf8_label) g_free (utf8_label);
- if (! val->enabled && GTK_WIDGET_SENSITIVE (w))
+ if (! val->enabled && gtk_widget_get_sensitive (w))
gtk_widget_set_sensitive (w, FALSE);
- else if (val->enabled && ! GTK_WIDGET_SENSITIVE (w))
+ else if (val->enabled && ! gtk_widget_get_sensitive (w))
gtk_widget_set_sensitive (w, TRUE);
cb_data = (xg_menu_item_cb_data*) g_object_get_data (G_OBJECT (w),
@@ -2691,9 +2785,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;
- GtkWidget *w;
+xg_update_toggle_item (widget_value *val, GtkWidget *w)
{
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w), val->selected);
}
@@ -2701,9 +2793,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;
- GtkWidget *w;
+xg_update_radio_item (widget_value *val, GtkWidget *w)
{
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w), val->selected);
}
@@ -2721,15 +2811,13 @@ xg_update_radio_item (val, w)
was NULL. */
static GtkWidget *
-xg_update_submenu (submenu, f, val,
- select_cb, deactivate_cb, highlight_cb, cl_data)
- GtkWidget *submenu;
- FRAME_PTR f;
- widget_value *val;
- GCallback select_cb;
- GCallback deactivate_cb;
- GCallback highlight_cb;
- xg_menu_cb_data *cl_data;
+xg_update_submenu (GtkWidget *submenu,
+ FRAME_PTR f,
+ widget_value *val,
+ GCallback select_cb,
+ GCallback deactivate_cb,
+ GCallback highlight_cb,
+ xg_menu_cb_data *cl_data)
{
GtkWidget *newsub = submenu;
GList *list = 0;
@@ -2767,7 +2855,7 @@ xg_update_submenu (submenu, f, val,
if (GTK_IS_SEPARATOR_MENU_ITEM (w))
{
- if (! xg_separator_p (cur->name))
+ if (! menu_separator_name_p (cur->name))
break;
}
else if (GTK_IS_CHECK_MENU_ITEM (w))
@@ -2790,7 +2878,7 @@ xg_update_submenu (submenu, f, val,
GtkWidget *sub;
if (cur->button_type != BUTTON_TYPE_NONE ||
- xg_separator_p (cur->name))
+ menu_separator_name_p (cur->name))
break;
xg_update_menu_item (cur, w, select_cb, highlight_cb, cl_data);
@@ -2799,8 +2887,8 @@ xg_update_submenu (submenu, f, val,
if (sub && ! cur->contents)
{
/* Not a submenu anymore. */
- gtk_widget_ref (sub);
- gtk_menu_item_remove_submenu (witem);
+ g_object_ref (G_OBJECT (sub));
+ remove_submenu (witem);
gtk_widget_destroy (sub);
}
else if (cur->contents)
@@ -2864,15 +2952,10 @@ xg_update_submenu (submenu, f, val,
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)
- GtkWidget *menubar;
- FRAME_PTR f;
- widget_value *val;
- int deep_p;
- GCallback select_cb;
- GCallback deactivate_cb;
- GCallback highlight_cb;
+xg_modify_menubar_widgets (GtkWidget *menubar, FRAME_PTR f, widget_value *val,
+ int deep_p,
+ GCallback select_cb, GCallback deactivate_cb,
+ GCallback highlight_cb)
{
xg_menu_cb_data *cl_data;
GList *list = gtk_container_get_children (GTK_CONTAINER (menubar));
@@ -2901,7 +2984,7 @@ xg_modify_menubar_widgets (menubar, f, val, deep_p,
GList *iter;
GtkWidget *sub = 0;
GtkWidget *newsub;
- GtkMenuItem *witem;
+ GtkMenuItem *witem = 0;
/* Find sub menu that corresponds to val and update it. */
for (iter = list ; iter; iter = g_list_next (iter))
@@ -2924,7 +3007,7 @@ xg_modify_menubar_widgets (menubar, f, val, deep_p,
/* sub may still be NULL. If we just updated non deep and added
a new menu bar item, it has no sub menu yet. So we set the
newly created sub menu under witem. */
- if (newsub != sub)
+ if (newsub != sub && witem != 0)
{
xg_set_screen (newsub, f);
gtk_menu_item_set_submenu (witem, newsub);
@@ -2936,17 +3019,33 @@ xg_modify_menubar_widgets (menubar, f, val, deep_p,
gtk_widget_show_all (menubar);
}
+/* Callback called when the menu bar W is mapped.
+ Used to find the height of the menu bar if we didn't get it
+ after showing the widget. */
+
+static void
+menubar_map_cb (GtkWidget *w, gpointer user_data)
+{
+ GtkRequisition req;
+ FRAME_PTR f = (FRAME_PTR) user_data;
+ gtk_widget_size_request (w, &req);
+ if (FRAME_MENUBAR_HEIGHT (f) != req.height)
+ {
+ FRAME_MENUBAR_HEIGHT (f) = req.height;
+ xg_height_or_width_changed (f);
+ }
+}
+
/* Recompute all the widgets of frame F, when the menu bar has been
changed. Value is non-zero if widgets were updated. */
int
-xg_update_frame_menubar (f)
- FRAME_PTR f;
+xg_update_frame_menubar (FRAME_PTR f)
{
struct x_output *x = f->output_data.x;
GtkRequisition req;
- if (!x->menubar_widget || GTK_WIDGET_MAPPED (x->menubar_widget))
+ if (!x->menubar_widget || gtk_widget_get_mapped (x->menubar_widget))
return 0;
if (x->menubar_widget && gtk_widget_get_parent (x->menubar_widget))
@@ -2958,10 +3057,20 @@ xg_update_frame_menubar (f)
FALSE, FALSE, 0);
gtk_box_reorder_child (GTK_BOX (x->vbox_widget), x->menubar_widget, 0);
+ g_signal_connect (x->menubar_widget, "map", G_CALLBACK (menubar_map_cb), f);
gtk_widget_show_all (x->menubar_widget);
gtk_widget_size_request (x->menubar_widget, &req);
- FRAME_MENUBAR_HEIGHT (f) = req.height;
- xg_height_changed (f);
+
+ /* If menu bar doesn't know its height yet, cheat a little so the frame
+ doesn't jump so much when resized later in menubar_map_cb. */
+ if (req.height == 0)
+ req.height = 23;
+
+ if (FRAME_MENUBAR_HEIGHT (f) != req.height)
+ {
+ FRAME_MENUBAR_HEIGHT (f) = req.height;
+ xg_height_or_width_changed (f);
+ }
UNBLOCK_INPUT;
return 1;
@@ -2971,8 +3080,7 @@ xg_update_frame_menubar (f)
This is used when deleting a frame, and when turning off the menu bar. */
void
-free_frame_menubar (f)
- FRAME_PTR f;
+free_frame_menubar (FRAME_PTR f)
{
struct x_output *x = f->output_data.x;
@@ -2985,7 +3093,7 @@ free_frame_menubar (f)
the container. */
x->menubar_widget = 0;
FRAME_MENUBAR_HEIGHT (f) = 0;
- xg_height_changed (f);
+ xg_height_or_width_changed (f);
UNBLOCK_INPUT;
}
}
@@ -3032,7 +3140,7 @@ xg_event_is_for_menubar (FRAME_PTR f, XEvent *event)
for (iter = list ; iter; iter = g_list_next (iter))
{
GtkWidget *w = GTK_WIDGET (iter->data);
- if (GTK_WIDGET_MAPPED (w) && gtk_widget_intersect (w, &rec, NULL))
+ if (gtk_widget_get_mapped (w) && gtk_widget_intersect (w, &rec, NULL))
break;
}
g_list_free (list);
@@ -3069,8 +3177,7 @@ static struct
/* Store the widget pointer W in id_to_widget and return the integer index. */
static int
-xg_store_widget_in_map (w)
- GtkWidget *w;
+xg_store_widget_in_map (GtkWidget *w)
{
int i;
@@ -3108,8 +3215,7 @@ xg_store_widget_in_map (w)
Called when scroll bar is destroyed. */
static void
-xg_remove_widget_from_map (idx)
- int idx;
+xg_remove_widget_from_map (int idx)
{
if (idx < id_to_widget.max_size && id_to_widget.widgets[idx] != 0)
{
@@ -3121,8 +3227,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;
+xg_get_widget_from_map (int idx)
{
if (idx < id_to_widget.max_size && id_to_widget.widgets[idx] != 0)
return id_to_widget.widgets[idx];
@@ -3134,9 +3239,7 @@ xg_get_widget_from_map (idx)
Return -1 if WID not in id_to_widget. */
int
-xg_get_scroll_id_for_window (dpy, wid)
- Display *dpy;
- Window wid;
+xg_get_scroll_id_for_window (Display *dpy, Window wid)
{
int idx;
GtkWidget *w;
@@ -3158,9 +3261,7 @@ xg_get_scroll_id_for_window (dpy, wid)
We free pointer to last scroll bar values here and remove the index. */
static void
-xg_gtk_scroll_destroy (widget, data)
- GtkWidget *widget;
- gpointer data;
+xg_gtk_scroll_destroy (GtkWidget *widget, gpointer data)
{
int id = (int) (EMACS_INT) data; /* The EMACS_INT cast avoids a warning. */
xg_remove_widget_from_map (id);
@@ -3175,11 +3276,11 @@ xg_gtk_scroll_destroy (widget, data)
to set resources for the widget. */
void
-xg_create_scroll_bar (f, bar, scroll_callback, end_callback, scroll_bar_name)
- FRAME_PTR f;
- struct scroll_bar *bar;
- GCallback scroll_callback, end_callback;
- char *scroll_bar_name;
+xg_create_scroll_bar (FRAME_PTR f,
+ struct scroll_bar *bar,
+ GCallback scroll_callback,
+ GCallback end_callback,
+ const char *scroll_bar_name)
{
GtkWidget *wscroll;
GtkWidget *webox;
@@ -3212,7 +3313,7 @@ xg_create_scroll_bar (f, bar, scroll_callback, end_callback, scroll_bar_name)
"button-release-event",
end_callback,
(gpointer) bar);
-
+
/* 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
@@ -3229,23 +3330,10 @@ xg_create_scroll_bar (f, bar, scroll_callback, end_callback, scroll_bar_name)
bar->x_window = 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_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;
- int scrollbar_id;
+xg_remove_scroll_bar (FRAME_PTR f, int scrollbar_id)
{
GtkWidget *w = xg_get_widget_from_map (scrollbar_id);
if (w)
@@ -3263,13 +3351,12 @@ xg_remove_scroll_bar (f, scrollbar_id)
WIDTH, HEIGHT is the size in pixels the bar shall have. */
void
-xg_update_scrollbar_pos (f, scrollbar_id, top, left, width, height)
- FRAME_PTR f;
- int scrollbar_id;
- int top;
- int left;
- int width;
- int height;
+xg_update_scrollbar_pos (FRAME_PTR f,
+ int scrollbar_id,
+ int top,
+ int left,
+ int width,
+ int height)
{
GtkWidget *wscroll = xg_get_widget_from_map (scrollbar_id);
@@ -3278,30 +3365,35 @@ xg_update_scrollbar_pos (f, scrollbar_id, top, left, width, height)
{
GtkWidget *wfixed = f->output_data.x->edit_widget;
GtkWidget *wparent = gtk_widget_get_parent (wscroll);
- GtkFixed *wf = GTK_FIXED (wfixed);
+ gint msl;
/* Clear out old position. */
- GList *iter;
int oldx = -1, oldy = -1, oldw, oldh;
- for (iter = wf->children; iter; iter = iter->next)
- if (((GtkFixedChild *)iter->data)->widget == wparent)
- {
- GtkFixedChild *ch = (GtkFixedChild *)iter->data;
- if (ch->x != left || ch->y != top)
- {
- oldx = ch->x;
- oldy = ch->y;
- gtk_widget_get_size_request (wscroll, &oldw, &oldh);
- }
- break;
- }
+ if (gtk_widget_get_parent (wparent) == wfixed)
+ {
+ gtk_container_child_get (GTK_CONTAINER (wfixed), wparent,
+ "x", &oldx, "y", &oldy, NULL);
+ gtk_widget_get_size_request (wscroll, &oldw, &oldh);
+ }
/* Move and resize to new values. */
gtk_fixed_move (GTK_FIXED (wfixed), wparent, left, top);
- gtk_widget_set_size_request (wscroll, width, height);
+ gtk_widget_style_get (wscroll, "min-slider-length", &msl, NULL);
+ if (msl > height)
+ {
+ /* No room. Hide scroll bar as some themes output a warning if
+ the height is less than the min size. */
+ gtk_widget_hide (wparent);
+ gtk_widget_hide (wscroll);
+ }
+ else
+ {
+ gtk_widget_show_all (wparent);
+ gtk_widget_set_size_request (wscroll, width, height);
+ }
gtk_widget_queue_draw (wfixed);
gdk_window_process_all_updates ();
- if (oldx != -1)
+ if (oldx != -1 && oldw > 0 && oldh > 0)
{
/* Clear under old scroll bar position. This must be done after
the gtk_widget_queue_draw and gdk_window_process_all_updates
@@ -3310,11 +3402,11 @@ xg_update_scrollbar_pos (f, scrollbar_id, top, left, width, height)
FRAME_X_WINDOW (f),
oldx, oldy, oldw, oldh, 0);
}
-
+
/* GTK does not redraw until the main loop is entered again, but
if there are no X events pending we will not enter it. So we sync
here to get some events. */
-
+
x_sync (f);
SET_FRAME_GARBAGED (f);
cancel_mouse_face (f);
@@ -3325,9 +3417,10 @@ xg_update_scrollbar_pos (f, scrollbar_id, top, left, width, height)
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;
- int portion, position, whole;
+xg_set_toolkit_scroll_bar_thumb (struct scroll_bar *bar,
+ int portion,
+ int position,
+ int whole)
{
GtkWidget *wscroll = xg_get_widget_from_map (bar->x_window);
@@ -3371,13 +3464,13 @@ xg_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
/* Assume all lines are of equal size. */
new_step = size / max (1, FRAME_LINES (f));
- if ((int) adj->page_size != size
- || (int) adj->step_increment != new_step)
+ if ((int) gtk_adjustment_get_page_size (adj) != size
+ || (int) gtk_adjustment_get_step_increment (adj) != new_step)
{
- adj->page_size = size;
- adj->step_increment = new_step;
+ gtk_adjustment_set_page_size (adj, size);
+ gtk_adjustment_set_step_increment (adj, new_step);
/* Assume a page increment is about 95% of the page size */
- adj->page_increment = (int) (0.95*adj->page_size);
+ gtk_adjustment_set_page_increment (adj,(int) (0.95*size));
changed = 1;
}
@@ -3409,9 +3502,7 @@ xg_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
Return non-zero if the event is for a scroll bar, zero otherwise. */
int
-xg_event_is_for_scrollbar (f, event)
- FRAME_PTR f;
- XEvent *event;
+xg_event_is_for_scrollbar (FRAME_PTR f, XEvent *event)
{
int retval = 0;
@@ -3420,17 +3511,17 @@ xg_event_is_for_scrollbar (f, event)
/* Check if press occurred outside the edit widget. */
GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (FRAME_X_DISPLAY (f));
retval = gdk_display_get_window_at_pointer (gdpy, NULL, NULL)
- != f->output_data.x->edit_widget->window;
+ != gtk_widget_get_window (f->output_data.x->edit_widget);
}
else if (f
&& ((event->type == ButtonRelease && event->xbutton.button < 4)
|| event->type == MotionNotify))
{
/* If we are releasing or moving the scroll bar, it has the grab. */
- retval = gtk_grab_get_current () != 0
- && gtk_grab_get_current () != f->output_data.x->edit_widget;
+ GtkWidget *w = gtk_grab_get_current ();
+ retval = w != 0 && GTK_IS_SCROLLBAR (w);
}
-
+
return retval;
}
@@ -3466,10 +3557,9 @@ xg_event_is_for_scrollbar (f, event)
tool bar. 0 is the first button. */
static gboolean
-xg_tool_bar_button_cb (widget, event, user_data)
- GtkWidget *widget;
- GdkEventButton *event;
- gpointer user_data;
+xg_tool_bar_button_cb (GtkWidget *widget,
+ GdkEventButton *event,
+ gpointer user_data)
{
/* Casts to avoid warnings when gpointer is 64 bits and int is 32 bits */
gpointer ptr = (gpointer) (EMACS_INT) event->state;
@@ -3484,9 +3574,7 @@ xg_tool_bar_button_cb (widget, event, user_data)
tool bar. 0 is the first button. */
static void
-xg_tool_bar_callback (w, client_data)
- GtkWidget *w;
- gpointer client_data;
+xg_tool_bar_callback (GtkWidget *w, gpointer client_data)
{
/* The EMACS_INT cast avoids a warning. */
int idx = (int) (EMACS_INT) client_data;
@@ -3521,7 +3609,7 @@ xg_tool_bar_callback (w, client_data)
this is written. */
event.modifiers = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f), mod);
kbd_buffer_store_event (&event);
-
+
/* Return focus to the frame after we have clicked on a detached
tool bar button. */
Fx_focus_frame (frame);
@@ -3535,9 +3623,7 @@ xg_tool_bar_callback (w, client_data)
tool bar. 0 is the first button. */
static void
-xg_tool_bar_proxy_callback (w, client_data)
- GtkWidget *w;
- gpointer client_data;
+xg_tool_bar_proxy_callback (GtkWidget *w, gpointer client_data)
{
GtkWidget *wbutton = GTK_WIDGET (g_object_get_data (G_OBJECT (w),
XG_TOOL_BAR_PROXY_BUTTON));
@@ -3546,25 +3632,36 @@ xg_tool_bar_proxy_callback (w, client_data)
static gboolean
-xg_tool_bar_help_callback P_ ((GtkWidget *w,
- GdkEventCrossing *event,
- gpointer client_data));
+xg_tool_bar_help_callback (GtkWidget *w,
+ GdkEventCrossing *event,
+ gpointer client_data);
/* This callback is called when a help is to be shown for an item in
the detached tool bar when the detached tool bar it is not expanded. */
static gboolean
-xg_tool_bar_proxy_help_callback (w, event, client_data)
- GtkWidget *w;
- GdkEventCrossing *event;
- gpointer client_data;
+xg_tool_bar_proxy_help_callback (GtkWidget *w,
+ GdkEventCrossing *event,
+ gpointer client_data)
{
GtkWidget *wbutton = GTK_WIDGET (g_object_get_data (G_OBJECT (w),
XG_TOOL_BAR_PROXY_BUTTON));
-
+
return xg_tool_bar_help_callback (wbutton, event, client_data);
}
+static GtkWidget *
+xg_get_tool_bar_widgets (GtkWidget *vb, GtkWidget **wimage)
+{
+ GList *clist = gtk_container_get_children (GTK_CONTAINER (vb));
+ GtkWidget *c1 = (GtkWidget *) clist->data;
+ GtkWidget *c2 = clist->next ? (GtkWidget *) clist->next->data : NULL;
+
+ *wimage = GTK_IS_IMAGE (c1) ? c1 : c2;
+ g_list_free (clist);
+ return GTK_IS_LABEL (c1) ? c1 : c2;
+}
+
/* This callback is called when a tool item should create a proxy item,
such as for the overflow menu. Also called when the tool bar is detached.
@@ -3572,21 +3669,23 @@ xg_tool_bar_proxy_help_callback (w, event, client_data)
blank. */
static gboolean
-xg_tool_bar_menu_proxy (toolitem, user_data)
- GtkToolItem *toolitem;
- gpointer user_data;
+xg_tool_bar_menu_proxy (GtkToolItem *toolitem, gpointer user_data)
{
- GtkWidget *weventbox = gtk_bin_get_child (GTK_BIN (toolitem));
- GtkButton *wbutton = GTK_BUTTON (gtk_bin_get_child (GTK_BIN (weventbox)));
- GtkWidget *wmenuitem = gtk_image_menu_item_new_with_label ("");
+ GtkButton *wbutton = GTK_BUTTON (XG_BIN_CHILD (XG_BIN_CHILD (toolitem)));
+ GtkWidget *vb = XG_BIN_CHILD (wbutton);
+ GtkWidget *c1;
+ GtkLabel *wlbl = GTK_LABEL (xg_get_tool_bar_widgets (vb, &c1));
+ GtkImage *wimage = GTK_IMAGE (c1);
+ GtkWidget *wmenuitem = gtk_image_menu_item_new_with_label
+ (gtk_label_get_text (wlbl));
GtkWidget *wmenuimage;
+
if (gtk_button_get_use_stock (wbutton))
wmenuimage = gtk_image_new_from_stock (gtk_button_get_label (wbutton),
GTK_ICON_SIZE_MENU);
else
{
- GtkImage *wimage = GTK_IMAGE (gtk_bin_get_child (GTK_BIN (wbutton)));
GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (wbutton));
GtkImageType store_type = gtk_image_get_storage_type (wimage);
@@ -3650,11 +3749,12 @@ xg_tool_bar_menu_proxy (toolitem, user_data)
G_CALLBACK (xg_tool_bar_proxy_callback),
user_data);
-
+
g_object_set_data (G_OBJECT (wmenuitem), XG_TOOL_BAR_PROXY_BUTTON,
(gpointer) wbutton);
gtk_tool_item_set_proxy_menu_item (toolitem, "Emacs toolbar item", wmenuitem);
- gtk_widget_set_sensitive (wmenuitem, GTK_WIDGET_SENSITIVE (wbutton));
+ gtk_widget_set_sensitive (wmenuitem,
+ gtk_widget_get_sensitive (GTK_WIDGET (wbutton)));
/* Use enter/leave notify to show help. We use the events
rather than the GtkButton specific signals "enter" and
@@ -3680,26 +3780,32 @@ xg_tool_bar_menu_proxy (toolitem, user_data)
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;
- GtkWidget *w;
- gpointer client_data;
+xg_tool_bar_detach_callback (GtkHandleBox *wbox,
+ GtkWidget *w,
+ gpointer client_data)
{
FRAME_PTR f = (FRAME_PTR) client_data;
- extern int x_gtk_whole_detached_tool_bar;
g_object_set (G_OBJECT (w), "show-arrow", !x_gtk_whole_detached_tool_bar,
NULL);
if (f)
{
+ GtkRequisition req, req2;
FRAME_X_OUTPUT (f)->toolbar_detached = 1;
-
- /* When detaching a tool bar, not everything dissapear. There are
- a few pixels left that are used to drop the tool bar back into
- place. */
- FRAME_TOOLBAR_HEIGHT (f) = 4;
- xg_height_changed (f);
+ gtk_widget_size_request (GTK_WIDGET (wbox), &req);
+ gtk_widget_size_request (w, &req2);
+ req.width -= req2.width;
+ req.height -= req2.height;
+ if (FRAME_TOOLBAR_TOP_HEIGHT (f) != 0)
+ FRAME_TOOLBAR_TOP_HEIGHT (f) = req.height;
+ else if (FRAME_TOOLBAR_BOTTOM_HEIGHT (f) != 0)
+ FRAME_TOOLBAR_BOTTOM_HEIGHT (f) = req.height;
+ else if (FRAME_TOOLBAR_RIGHT_WIDTH (f) != 0)
+ FRAME_TOOLBAR_RIGHT_WIDTH (f) = req.width;
+ else if (FRAME_TOOLBAR_LEFT_WIDTH (f) != 0)
+ FRAME_TOOLBAR_LEFT_WIDTH (f) = req.width;
+ xg_height_or_width_changed (f);
}
}
@@ -3711,23 +3817,30 @@ xg_tool_bar_detach_callback (wbox, w, client_data)
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;
- GtkWidget *w;
- gpointer client_data;
+xg_tool_bar_attach_callback (GtkHandleBox *wbox,
+ GtkWidget *w,
+ gpointer client_data)
{
FRAME_PTR f = (FRAME_PTR) client_data;
g_object_set (G_OBJECT (w), "show-arrow", TRUE, NULL);
if (f)
{
- GtkRequisition req;
-
+ GtkRequisition req, req2;
FRAME_X_OUTPUT (f)->toolbar_detached = 0;
-
- gtk_widget_size_request (w, &req);
- FRAME_TOOLBAR_HEIGHT (f) = req.height;
- xg_height_changed (f);
+ gtk_widget_size_request (GTK_WIDGET (wbox), &req);
+ gtk_widget_size_request (w, &req2);
+ req.width += req2.width;
+ req.height += req2.height;
+ if (FRAME_TOOLBAR_TOP_HEIGHT (f) != 0)
+ FRAME_TOOLBAR_TOP_HEIGHT (f) = req.height;
+ else if (FRAME_TOOLBAR_BOTTOM_HEIGHT (f) != 0)
+ FRAME_TOOLBAR_BOTTOM_HEIGHT (f) = req.height;
+ else if (FRAME_TOOLBAR_RIGHT_WIDTH (f) != 0)
+ FRAME_TOOLBAR_RIGHT_WIDTH (f) = req.width;
+ else if (FRAME_TOOLBAR_LEFT_WIDTH (f) != 0)
+ FRAME_TOOLBAR_LEFT_WIDTH (f) = req.width;
+ xg_height_or_width_changed (f);
}
}
@@ -3741,10 +3854,9 @@ xg_tool_bar_attach_callback (wbox, w, client_data)
Returns FALSE to tell GTK to keep processing this event. */
static gboolean
-xg_tool_bar_help_callback (w, event, client_data)
- GtkWidget *w;
- GdkEventCrossing *event;
- gpointer client_data;
+xg_tool_bar_help_callback (GtkWidget *w,
+ GdkEventCrossing *event,
+ gpointer client_data)
{
/* The EMACS_INT cast avoids a warning. */
int idx = (int) (EMACS_INT) client_data;
@@ -3783,10 +3895,9 @@ xg_tool_bar_help_callback (w, event, client_data)
Returns FALSE to tell GTK to keep processing this event. */
static gboolean
-xg_tool_bar_item_expose_callback (w, event, client_data)
- GtkWidget *w;
- GdkEventExpose *event;
- gpointer client_data;
+xg_tool_bar_item_expose_callback (GtkWidget *w,
+ GdkEventExpose *event,
+ gpointer client_data)
{
gint width, height;
@@ -3804,37 +3915,70 @@ xg_tool_bar_item_expose_callback (w, event, client_data)
return FALSE;
}
+#ifdef HAVE_GTK_ORIENTABLE_SET_ORIENTATION
+#define toolbar_set_orientation(w, o) \
+ gtk_orientable_set_orientation (GTK_ORIENTABLE (w), o)
+#else
+#define toolbar_set_orientation(w, o) \
+ gtk_toolbar_set_orientation (GTK_TOOLBAR (w), o)
+#endif
+
/* Attach a tool bar to frame F. */
static void
-xg_pack_tool_bar (f)
- FRAME_PTR f;
+xg_pack_tool_bar (FRAME_PTR f, Lisp_Object pos)
{
struct x_output *x = f->output_data.x;
- int vbox_pos = x->menubar_widget ? 1 : 0;
-
- x->handlebox_widget = gtk_handle_box_new ();
- g_signal_connect (G_OBJECT (x->handlebox_widget), "child-detached",
- G_CALLBACK (xg_tool_bar_detach_callback), f);
- g_signal_connect (G_OBJECT (x->handlebox_widget), "child-attached",
- G_CALLBACK (xg_tool_bar_attach_callback), f);
-
- gtk_container_add (GTK_CONTAINER (x->handlebox_widget),
- x->toolbar_widget);
+ int into_hbox = EQ (pos, Qleft) || EQ (pos, Qright);
- gtk_box_pack_start (GTK_BOX (x->vbox_widget), x->handlebox_widget,
- FALSE, FALSE, 0);
+ toolbar_set_orientation (x->toolbar_widget,
+ into_hbox
+ ? GTK_ORIENTATION_VERTICAL
+ : GTK_ORIENTATION_HORIZONTAL);
+ if (!x->handlebox_widget)
+ {
+ x->handlebox_widget = gtk_handle_box_new ();
+ g_signal_connect (G_OBJECT (x->handlebox_widget), "child-detached",
+ G_CALLBACK (xg_tool_bar_detach_callback), f);
+ g_signal_connect (G_OBJECT (x->handlebox_widget), "child-attached",
+ G_CALLBACK (xg_tool_bar_attach_callback), f);
+ gtk_container_add (GTK_CONTAINER (x->handlebox_widget),
+ x->toolbar_widget);
+ }
- gtk_box_reorder_child (GTK_BOX (x->vbox_widget), x->handlebox_widget,
- vbox_pos);
- gtk_widget_show_all (x->handlebox_widget);
+ if (into_hbox)
+ {
+ gtk_handle_box_set_handle_position (GTK_HANDLE_BOX (x->handlebox_widget),
+ GTK_POS_TOP);
+ gtk_box_pack_start (GTK_BOX (x->hbox_widget), x->handlebox_widget,
+ FALSE, FALSE, 0);
+
+ if (EQ (pos, Qleft))
+ gtk_box_reorder_child (GTK_BOX (x->hbox_widget),
+ x->handlebox_widget,
+ 0);
+ x->toolbar_in_hbox = 1;
+ }
+ else
+ {
+ int vbox_pos = x->menubar_widget ? 1 : 0;
+ gtk_handle_box_set_handle_position (GTK_HANDLE_BOX (x->handlebox_widget),
+ GTK_POS_LEFT);
+ gtk_box_pack_start (GTK_BOX (x->vbox_widget), x->handlebox_widget,
+ FALSE, FALSE, 0);
+
+ if (EQ (pos, Qtop))
+ gtk_box_reorder_child (GTK_BOX (x->vbox_widget),
+ x->handlebox_widget,
+ vbox_pos);
+ x->toolbar_in_hbox = 0;
+ }
}
/* Create a tool bar for frame F. */
static void
-xg_create_tool_bar (f)
- FRAME_PTR f;
+xg_create_tool_bar (FRAME_PTR f)
{
struct x_output *x = f->output_data.x;
@@ -3843,16 +3987,8 @@ xg_create_tool_bar (f)
gtk_widget_set_name (x->toolbar_widget, "emacs-toolbar");
- /* We only have icons, so override any user setting. We could
- use the caption property of the toolbar item (see update_frame_tool_bar
- below), but some of those strings are long, making the toolbar so
- long it does not fit on the screen. The GtkToolbar widget makes every
- item equal size, so the longest caption determine the size of every
- tool bar item. I think the creators of the GtkToolbar widget
- counted on 4 or 5 character long strings. */
gtk_toolbar_set_style (GTK_TOOLBAR (x->toolbar_widget), GTK_TOOLBAR_ICONS);
- gtk_toolbar_set_orientation (GTK_TOOLBAR (x->toolbar_widget),
- GTK_ORIENTATION_HORIZONTAL);
+ toolbar_set_orientation (x->toolbar_widget, GTK_ORIENTATION_HORIZONTAL);
}
@@ -3862,10 +3998,7 @@ xg_create_tool_bar (f)
Returns IMAGE if RTL is not found. */
static Lisp_Object
-find_rtl_image (f, image, rtl)
- FRAME_PTR f;
- Lisp_Object image;
- Lisp_Object rtl;
+find_rtl_image (FRAME_PTR f, Lisp_Object image, Lisp_Object rtl)
{
int i;
Lisp_Object file, rtl_name;
@@ -3892,16 +4025,178 @@ find_rtl_image (f, image, rtl)
return image;
}
-/* Update the tool bar for frame F. Add new buttons and remove old. */
+static GtkToolItem *
+xg_make_tool_item (FRAME_PTR f,
+ GtkWidget *wimage,
+ GtkWidget **wbutton,
+ const char *label,
+ int i, int horiz, int text_image)
+{
+ GtkToolItem *ti = gtk_tool_item_new ();
+ GtkWidget *vb = horiz ? gtk_hbox_new (FALSE, 0) : gtk_vbox_new (FALSE, 0);
+ GtkWidget *wb = gtk_button_new ();
+ GtkWidget *weventbox = gtk_event_box_new ();
+
+ if (wimage && !text_image)
+ gtk_box_pack_start (GTK_BOX (vb), wimage, TRUE, TRUE, 0);
+ if (label)
+ gtk_box_pack_start (GTK_BOX (vb), gtk_label_new (label), TRUE, TRUE, 0);
+ if (wimage && text_image)
+ gtk_box_pack_start (GTK_BOX (vb), wimage, TRUE, TRUE, 0);
+
+ gtk_button_set_focus_on_click (GTK_BUTTON (wb), FALSE);
+ gtk_button_set_relief (GTK_BUTTON (wb), GTK_RELIEF_NONE);
+ gtk_container_add (GTK_CONTAINER (wb), vb);
+ gtk_container_add (GTK_CONTAINER (weventbox), wb);
+ gtk_container_add (GTK_CONTAINER (ti), weventbox);
+
+ if (wimage)
+ {
+ /* The EMACS_INT cast avoids a warning. */
+ g_signal_connect (G_OBJECT (ti), "create-menu-proxy",
+ G_CALLBACK (xg_tool_bar_menu_proxy),
+ (gpointer) (EMACS_INT) i);
+
+ g_signal_connect (G_OBJECT (wb), "clicked",
+ G_CALLBACK (xg_tool_bar_callback),
+ (gpointer) (EMACS_INT) i);
+
+ g_object_set_data (G_OBJECT (weventbox), XG_FRAME_DATA, (gpointer)f);
+
+ /* Catch expose events to overcome an annoying redraw bug, see
+ comment for xg_tool_bar_item_expose_callback. */
+ g_signal_connect (G_OBJECT (ti),
+ "expose-event",
+ G_CALLBACK (xg_tool_bar_item_expose_callback),
+ 0);
+
+ gtk_tool_item_set_homogeneous (ti, FALSE);
+
+ /* Callback to save modifyer mask (Shift/Control, etc). GTK makes
+ no distinction based on modifiers in the activate callback,
+ so we have to do it ourselves. */
+ g_signal_connect (wb, "button-release-event",
+ G_CALLBACK (xg_tool_bar_button_cb),
+ NULL);
+
+ g_object_set_data (G_OBJECT (wb), XG_FRAME_DATA, (gpointer)f);
+
+ /* Use enter/leave notify to show help. We use the events
+ rather than the GtkButton specific signals "enter" and
+ "leave", so we can have only one callback. The event
+ will tell us what kind of event it is. */
+ /* The EMACS_INT cast avoids a warning. */
+ g_signal_connect (G_OBJECT (weventbox),
+ "enter-notify-event",
+ G_CALLBACK (xg_tool_bar_help_callback),
+ (gpointer) (EMACS_INT) i);
+ g_signal_connect (G_OBJECT (weventbox),
+ "leave-notify-event",
+ G_CALLBACK (xg_tool_bar_help_callback),
+ (gpointer) (EMACS_INT) i);
+ }
+
+ if (wbutton) *wbutton = wb;
+
+ return ti;
+}
+
+static int
+xg_tool_item_stale_p (GtkWidget *wbutton, const char *stock_name,
+ const char *icon_name, const struct image *img,
+ const char *label, int horiz)
+{
+ gpointer old;
+ GtkWidget *wimage;
+ GtkWidget *vb = XG_BIN_CHILD (wbutton);
+ GtkWidget *wlbl = xg_get_tool_bar_widgets (vb, &wimage);
+
+ /* Check if the tool icon matches. */
+ if (stock_name)
+ {
+ old = g_object_get_data (G_OBJECT (wimage),
+ XG_TOOL_BAR_STOCK_NAME);
+ if (!old || strcmp (old, stock_name))
+ return 1;
+ }
+ else if (icon_name)
+ {
+ old = g_object_get_data (G_OBJECT (wimage),
+ XG_TOOL_BAR_ICON_NAME);
+ if (!old || strcmp (old, icon_name))
+ return 1;
+ }
+ else
+ {
+ Pixmap old_img
+ = (Pixmap) g_object_get_data (G_OBJECT (wimage),
+ XG_TOOL_BAR_IMAGE_DATA);
+ if (old_img != img->pixmap)
+ return 1;
+ }
-extern Lisp_Object Qx_gtk_map_stock;
+ /* Check button configuration and label. */
+ if ((horiz ? GTK_IS_VBOX (vb) : GTK_IS_HBOX (vb))
+ || (label ? (wlbl == NULL) : (wlbl != NULL)))
+ return 1;
+
+ /* Ensure label is correct. */
+ if (label)
+ gtk_label_set_text (GTK_LABEL (wlbl), label);
+ return 0;
+}
+
+static int
+xg_update_tool_bar_sizes (FRAME_PTR f)
+{
+ struct x_output *x = f->output_data.x;
+ GtkRequisition req;
+ int nl = 0, nr = 0, nt = 0, nb = 0;
+
+ gtk_widget_size_request (GTK_WIDGET (x->handlebox_widget), &req);
+ if (x->toolbar_in_hbox)
+ {
+ int pos;
+ gtk_container_child_get (GTK_CONTAINER (x->hbox_widget),
+ x->handlebox_widget,
+ "position", &pos, NULL);
+ if (pos == 0) nl = req.width;
+ else nr = req.width;
+ }
+ else
+ {
+ int pos;
+ gtk_container_child_get (GTK_CONTAINER (x->vbox_widget),
+ x->handlebox_widget,
+ "position", &pos, NULL);
+ if (pos == 0 || (pos == 1 && x->menubar_widget)) nt = req.height;
+ else nb = req.height;
+ }
+
+ if (nl != FRAME_TOOLBAR_LEFT_WIDTH (f)
+ || nr != FRAME_TOOLBAR_RIGHT_WIDTH (f)
+ || nt != FRAME_TOOLBAR_TOP_HEIGHT (f)
+ || nb != FRAME_TOOLBAR_BOTTOM_HEIGHT (f))
+ {
+ FRAME_TOOLBAR_RIGHT_WIDTH (f) = FRAME_TOOLBAR_LEFT_WIDTH (f)
+ = FRAME_TOOLBAR_TOP_HEIGHT (f) = FRAME_TOOLBAR_BOTTOM_HEIGHT (f) = 0;
+ FRAME_TOOLBAR_LEFT_WIDTH (f) = nl;
+ FRAME_TOOLBAR_RIGHT_WIDTH (f) = nr;
+ FRAME_TOOLBAR_TOP_HEIGHT (f) = nt;
+ FRAME_TOOLBAR_BOTTOM_HEIGHT (f) = nb;
+ return 1;
+ }
+
+ return 0;
+}
+
+
+/* Update the tool bar for frame F. Add new buttons and remove old. */
void
-update_frame_tool_bar (f)
- FRAME_PTR f;
+update_frame_tool_bar (FRAME_PTR f)
{
- int i;
- GtkRequisition old_req, new_req;
+ int i, j;
struct x_output *x = f->output_data.x;
int hmargin = 0, vmargin = 0;
GtkToolbar *wtoolbar;
@@ -3909,6 +4204,9 @@ update_frame_tool_bar (f)
GtkTextDirection dir;
int pack_tool_bar = x->handlebox_widget == NULL;
+ Lisp_Object style;
+ int text_image, horiz;
+
if (! FRAME_GTK_WIDGET (f))
return;
@@ -3942,10 +4240,13 @@ update_frame_tool_bar (f)
xg_create_tool_bar (f);
wtoolbar = GTK_TOOLBAR (x->toolbar_widget);
- gtk_widget_size_request (GTK_WIDGET (wtoolbar), &old_req);
- dir = gtk_widget_get_direction (x->toolbar_widget);
+ dir = gtk_widget_get_direction (GTK_WIDGET (wtoolbar));
- for (i = 0; i < f->n_tool_bar_items; ++i)
+ style = Ftool_bar_get_system_style ();
+ text_image = EQ (style, Qtext_image_horiz);
+ horiz = EQ (style, Qboth_horiz) || text_image;
+
+ for (i = j = 0; i < f->n_tool_bar_items; ++i)
{
int enabled_p = !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P));
int selected_p = !NILP (PROP (TOOL_BAR_ITEM_SELECTED_P));
@@ -3960,23 +4261,48 @@ update_frame_tool_bar (f)
char *icon_name = NULL;
Lisp_Object rtl;
GtkWidget *wbutton = NULL;
- GtkWidget *weventbox;
Lisp_Object specified_file;
-
- ti = gtk_toolbar_get_nth_item (GTK_TOOLBAR (x->toolbar_widget), i);
-
- if (ti)
- {
- weventbox = gtk_bin_get_child (GTK_BIN (ti));
- wbutton = gtk_bin_get_child (GTK_BIN (weventbox));
- }
-
- image = PROP (TOOL_BAR_ITEM_IMAGES);
+ int vert_only = ! NILP (PROP (TOOL_BAR_ITEM_VERT_ONLY));
+ const char *label
+ = (EQ (style, Qimage) || (vert_only && horiz)) ? NULL
+ : STRINGP (PROP (TOOL_BAR_ITEM_LABEL))
+ ? SSDATA (PROP (TOOL_BAR_ITEM_LABEL))
+ : "";
+
+ ti = gtk_toolbar_get_nth_item (GTK_TOOLBAR (wtoolbar), j);
+
+ /* If this is a separator, use a gtk separator item. */
+ if (EQ (PROP (TOOL_BAR_ITEM_TYPE), Qt))
+ {
+ if (ti == NULL || !GTK_IS_SEPARATOR_TOOL_ITEM (ti))
+ {
+ if (ti)
+ gtk_container_remove (GTK_CONTAINER (wtoolbar),
+ GTK_WIDGET (ti));
+ ti = gtk_separator_tool_item_new ();
+ gtk_toolbar_insert (GTK_TOOLBAR (wtoolbar), ti, j);
+ }
+ j++;
+ continue;
+ }
+
+ /* Otherwise, the tool-bar item is an ordinary button. */
+
+ if (ti && GTK_IS_SEPARATOR_TOOL_ITEM (ti))
+ {
+ gtk_container_remove (GTK_CONTAINER (wtoolbar), GTK_WIDGET (ti));
+ ti = NULL;
+ }
+
+ if (ti) wbutton = XG_BIN_CHILD (XG_BIN_CHILD (ti));
/* Ignore invalid image specifications. */
+ image = PROP (TOOL_BAR_ITEM_IMAGES);
if (!valid_image_p (image))
{
- if (wbutton) gtk_widget_hide (wbutton);
+ if (ti)
+ gtk_container_remove (GTK_CONTAINER (wtoolbar),
+ GTK_WIDGET (ti));
continue;
}
@@ -4002,7 +4328,7 @@ update_frame_tool_bar (f)
icon_size = gtk_toolbar_get_icon_size (wtoolbar);
}
else if (gtk_stock_lookup (SSDATA (stock), &stock_item))
- icon_size = gtk_toolbar_get_icon_size (wtoolbar);
+ icon_size = gtk_toolbar_get_icon_size (wtoolbar);
else
{
stock = Qnil;
@@ -4012,16 +4338,13 @@ update_frame_tool_bar (f)
if (stock_name == NULL && icon_name == NULL)
{
- /* No stock image, or stock item not known. Try regular image. */
-
- /* If image is a vector, choose the image according to the
+ /* No stock image, or stock item not known. Try regular
+ image. If image is a vector, choose it according to the
button state. */
if (dir == GTK_TEXT_DIR_RTL
&& !NILP (rtl = PROP (TOOL_BAR_ITEM_RTL_IMAGE))
&& STRINGP (rtl))
- {
- image = find_rtl_image (f, image, rtl);
- }
+ image = find_rtl_image (f, image, rtl);
if (VECTORP (image))
{
@@ -4046,29 +4369,32 @@ update_frame_tool_bar (f)
if (img->load_failed_p || img->pixmap == None)
{
- if (ti)
- gtk_widget_hide_all (GTK_WIDGET (ti));
- else
- {
- /* Insert an empty (non-image) button */
- weventbox = gtk_event_box_new ();
- wbutton = gtk_button_new ();
- gtk_button_set_focus_on_click (GTK_BUTTON (wbutton), FALSE);
- gtk_button_set_relief (GTK_BUTTON (wbutton),
- GTK_RELIEF_NONE);
- gtk_container_add (GTK_CONTAINER (weventbox), wbutton);
- ti = gtk_tool_item_new ();
- gtk_container_add (GTK_CONTAINER (ti), weventbox);
- gtk_toolbar_insert (GTK_TOOLBAR (x->toolbar_widget), ti, -1);
- }
- continue;
+ if (ti)
+ gtk_container_remove (GTK_CONTAINER (wtoolbar),
+ GTK_WIDGET (ti));
+ continue;
}
}
+ /* If there is an existing widget, check if it's stale; if so,
+ remove it and make a new tool item from scratch. */
+ if (ti && xg_tool_item_stale_p (wbutton, stock_name, icon_name,
+ img, label, horiz))
+ {
+ gtk_container_remove (GTK_CONTAINER (wtoolbar),
+ GTK_WIDGET (ti));
+ ti = NULL;
+ }
+
if (ti == NULL)
{
GtkWidget *w;
- if (stock_name)
+
+ /* Save the image so we can see if an update is needed the
+ next time we call xg_tool_item_match_p. */
+ if (EQ (style, Qtext))
+ w = NULL;
+ else if (stock_name)
{
w = gtk_image_new_from_stock (stock_name, icon_size);
g_object_set_data_full (G_OBJECT (w), XG_TOOL_BAR_STOCK_NAME,
@@ -4085,145 +4411,38 @@ update_frame_tool_bar (f)
else
{
w = xg_get_image_for_pixmap (f, img, x->widget, NULL);
- /* Save the image so we can see if an update is needed when
- this function is called again. */
g_object_set_data (G_OBJECT (w), XG_TOOL_BAR_IMAGE_DATA,
(gpointer)img->pixmap);
}
- gtk_misc_set_padding (GTK_MISC (w), hmargin, vmargin);
- wbutton = gtk_button_new ();
- gtk_button_set_focus_on_click (GTK_BUTTON (wbutton), FALSE);
- gtk_button_set_relief (GTK_BUTTON (wbutton), GTK_RELIEF_NONE);
- gtk_container_add (GTK_CONTAINER (wbutton), w);
- weventbox = gtk_event_box_new ();
- gtk_container_add (GTK_CONTAINER (weventbox), wbutton);
- ti = gtk_tool_item_new ();
- gtk_container_add (GTK_CONTAINER (ti), weventbox);
- gtk_toolbar_insert (GTK_TOOLBAR (x->toolbar_widget), ti, -1);
-
-
- /* The EMACS_INT cast avoids a warning. */
- g_signal_connect (G_OBJECT (ti), "create-menu-proxy",
- G_CALLBACK (xg_tool_bar_menu_proxy),
- (gpointer) (EMACS_INT) i);
-
- g_signal_connect (G_OBJECT (wbutton), "clicked",
- G_CALLBACK (xg_tool_bar_callback),
- (gpointer) (EMACS_INT) i);
-
- gtk_widget_show_all (GTK_WIDGET (ti));
-
-
- g_object_set_data (G_OBJECT (weventbox), XG_FRAME_DATA, (gpointer)f);
-
- /* Catch expose events to overcome an annoying redraw bug, see
- comment for xg_tool_bar_item_expose_callback. */
- g_signal_connect (G_OBJECT (ti),
- "expose-event",
- G_CALLBACK (xg_tool_bar_item_expose_callback),
- 0);
-
- gtk_widget_set_sensitive (wbutton, enabled_p);
- gtk_tool_item_set_homogeneous (ti, FALSE);
-
- /* Callback to save modifyer mask (Shift/Control, etc). GTK makes
- no distinction based on modifiers in the activate callback,
- so we have to do it ourselves. */
- g_signal_connect (wbutton, "button-release-event",
- G_CALLBACK (xg_tool_bar_button_cb),
- NULL);
-
- g_object_set_data (G_OBJECT (wbutton), XG_FRAME_DATA, (gpointer)f);
-
- /* Use enter/leave notify to show help. We use the events
- rather than the GtkButton specific signals "enter" and
- "leave", so we can have only one callback. The event
- will tell us what kind of event it is. */
- /* The EMACS_INT cast avoids a warning. */
- g_signal_connect (G_OBJECT (weventbox),
- "enter-notify-event",
- G_CALLBACK (xg_tool_bar_help_callback),
- (gpointer) (EMACS_INT) i);
- g_signal_connect (G_OBJECT (weventbox),
- "leave-notify-event",
- G_CALLBACK (xg_tool_bar_help_callback),
- (gpointer) (EMACS_INT) i);
+ if (w) gtk_misc_set_padding (GTK_MISC (w), hmargin, vmargin);
+ ti = xg_make_tool_item (f, w, &wbutton, label, i, horiz, text_image);
+ gtk_toolbar_insert (GTK_TOOLBAR (wtoolbar), ti, j);
}
- else
- {
- GtkWidget *wimage = gtk_bin_get_child (GTK_BIN (wbutton));
- Pixmap old_img = (Pixmap)g_object_get_data (G_OBJECT (wimage),
- XG_TOOL_BAR_IMAGE_DATA);
- gpointer old_stock_name = g_object_get_data (G_OBJECT (wimage),
- XG_TOOL_BAR_STOCK_NAME);
- gpointer old_icon_name = g_object_get_data (G_OBJECT (wimage),
- XG_TOOL_BAR_ICON_NAME);
- if (stock_name &&
- (! old_stock_name || strcmp (old_stock_name, stock_name) != 0))
- {
- gtk_image_set_from_stock (GTK_IMAGE (wimage),
- stock_name, icon_size);
- g_object_set_data_full (G_OBJECT (wimage), XG_TOOL_BAR_STOCK_NAME,
- (gpointer) xstrdup (stock_name),
- (GDestroyNotify) xfree);
- g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_IMAGE_DATA,
- NULL);
- g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_ICON_NAME, NULL);
- }
- else if (icon_name &&
- (! old_icon_name || strcmp (old_icon_name, icon_name) != 0))
- {
- gtk_image_set_from_icon_name (GTK_IMAGE (wimage),
- icon_name, icon_size);
- g_object_set_data_full (G_OBJECT (wimage), XG_TOOL_BAR_ICON_NAME,
- (gpointer) xstrdup (icon_name),
- (GDestroyNotify) xfree);
- g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_IMAGE_DATA,
- NULL);
- g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_STOCK_NAME,
- NULL);
- }
- else if (img && old_img != img->pixmap)
- {
- (void) xg_get_image_for_pixmap (f, img, x->widget, wimage);
- g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_IMAGE_DATA,
- (gpointer)img->pixmap);
-
- g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_STOCK_NAME,
- NULL);
- g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_ICON_NAME, NULL);
- }
-
- gtk_misc_set_padding (GTK_MISC (wimage), hmargin, vmargin);
-
- gtk_widget_set_sensitive (wbutton, enabled_p);
- gtk_widget_show_all (GTK_WIDGET (ti));
- }
#undef PROP
+
+ gtk_widget_set_sensitive (wbutton, enabled_p);
+ j++;
}
- /* Remove buttons not longer needed. We just hide them so they
- can be reused later on. */
+ /* Remove buttons not longer needed. */
do
{
- ti = gtk_toolbar_get_nth_item (GTK_TOOLBAR (x->toolbar_widget), i++);
- if (ti) gtk_widget_hide_all (GTK_WIDGET (ti));
+ ti = gtk_toolbar_get_nth_item (GTK_TOOLBAR (wtoolbar), j);
+ if (ti)
+ gtk_container_remove (GTK_CONTAINER (wtoolbar), GTK_WIDGET (ti));
} while (ti != NULL);
- new_req.height = 0;
- if (pack_tool_bar && f->n_tool_bar_items != 0)
- xg_pack_tool_bar (f);
-
-
- gtk_widget_size_request (GTK_WIDGET (x->toolbar_widget), &new_req);
- if (old_req.height != new_req.height
- && ! FRAME_X_OUTPUT (f)->toolbar_detached)
+ if (f->n_tool_bar_items != 0)
{
- FRAME_TOOLBAR_HEIGHT (f) = new_req.height;
- xg_height_changed (f);
+ if (pack_tool_bar)
+ xg_pack_tool_bar (f, f->tool_bar_position);
+ gtk_widget_show_all (GTK_WIDGET (x->handlebox_widget));
+ if (xg_update_tool_bar_sizes (f))
+ xg_height_or_width_changed (f);
}
+
UNBLOCK_INPUT;
}
@@ -4231,8 +4450,7 @@ update_frame_tool_bar (f)
Remove the tool bar. */
void
-free_frame_tool_bar (f)
- FRAME_PTR f;
+free_frame_tool_bar (FRAME_PTR f)
{
struct x_output *x = f->output_data.x;
@@ -4243,27 +4461,60 @@ free_frame_tool_bar (f)
/* We may have created the toolbar_widget in xg_create_tool_bar, but
not the x->handlebox_widget which is created in xg_pack_tool_bar. */
if (is_packed)
- gtk_container_remove (GTK_CONTAINER (x->vbox_widget),
- x->handlebox_widget);
+ {
+ if (x->toolbar_in_hbox)
+ gtk_container_remove (GTK_CONTAINER (x->hbox_widget),
+ x->handlebox_widget);
+ else
+ gtk_container_remove (GTK_CONTAINER (x->vbox_widget),
+ x->handlebox_widget);
+ }
else
gtk_widget_destroy (x->toolbar_widget);
x->toolbar_widget = 0;
x->handlebox_widget = 0;
- FRAME_TOOLBAR_HEIGHT (f) = 0;
- xg_height_changed (f);
+ FRAME_TOOLBAR_TOP_HEIGHT (f) = FRAME_TOOLBAR_BOTTOM_HEIGHT (f) = 0;
+ FRAME_TOOLBAR_LEFT_WIDTH (f) = FRAME_TOOLBAR_RIGHT_WIDTH (f) = 0;
+
+ xg_height_or_width_changed (f);
UNBLOCK_INPUT;
}
}
+int
+xg_change_toolbar_position (FRAME_PTR f, Lisp_Object pos)
+{
+ struct x_output *x = f->output_data.x;
+
+ if (! x->toolbar_widget || ! x->handlebox_widget)
+ return 1;
+
+ BLOCK_INPUT;
+ g_object_ref (x->handlebox_widget);
+ if (x->toolbar_in_hbox)
+ gtk_container_remove (GTK_CONTAINER (x->hbox_widget),
+ x->handlebox_widget);
+ else
+ gtk_container_remove (GTK_CONTAINER (x->vbox_widget),
+ x->handlebox_widget);
+ xg_pack_tool_bar (f, pos);
+ g_object_unref (x->handlebox_widget);
+ if (xg_update_tool_bar_sizes (f))
+ xg_height_or_width_changed (f);
+
+ UNBLOCK_INPUT;
+ return 1;
+}
+
/***********************************************************************
Initializing
- ***********************************************************************/
+***********************************************************************/
void
-xg_initialize ()
+xg_initialize (void)
{
GtkBindingSet *binding_set;
@@ -4311,6 +4562,3 @@ xg_initialize ()
}
#endif /* USE_GTK */
-
-/* arch-tag: fe7104da-bc1e-4aba-9bd1-f349c528f7e3
- (do not change this comment) */