/* 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.
#include <config.h>
#ifdef USE_GTK
-#include <string.h>
#include <signal.h>
#include <stdio.h>
#include <setjmp.h>
#include <X11/Xft/Xft.h>
#endif
+#ifdef HAVE_GTK3
+#include <gtk/gtkx.h>
+#endif
+
#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) \
#define remove_submenu(w) gtk_menu_item_remove_submenu ((w))
#endif
+#ifndef HAVE_GTK3
+#ifdef USE_GTK_TOOLTIP
+#define gdk_window_get_screen(w) gdk_drawable_get_screen (w)
+#endif
+#define gdk_window_get_geometry(w, a, b, c, d) \
+ gdk_window_get_geometry (w, a, b, c, d, 0)
+#define gdk_x11_window_lookup_for_display(d, w) \
+ gdk_xid_table_lookup_for_display (d, w)
+#define GDK_KEY_g GDK_g
+#endif
+
+#define XG_BIN_CHILD(x) gtk_bin_get_child (GTK_BIN (x))
+
+/* Get the current value of the range, truncated to an integer. */
+static int
+int_gtk_range_get_value (GtkRange *range)
+{
+ return gtk_range_get_value (range);
+}
+
\f
/***********************************************************************
Display handling functions
static void
xg_set_screen (GtkWidget *w, FRAME_PTR f)
{
- if (FRAME_X_DISPLAY (f) != GDK_DISPLAY ())
+ if (FRAME_X_DISPLAY (f) != DEFAULT_GDK_DISPLAY ())
{
GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (FRAME_X_DISPLAY (f));
GdkScreen *gscreen = gdk_display_get_default_screen (gdpy);
return gdk_cursor_new_for_display (gdpy, GDK_LEFT_PTR);
}
+static GdkPixbuf *
+xg_get_pixbuf_from_pixmap (FRAME_PTR f, Pixmap pix)
+{
+ int iunused;
+ GdkPixbuf *tmp_buf;
+ Window wunused;
+ unsigned int width, height, uunused;
+ XImage *xim;
+
+ XGetGeometry (FRAME_X_DISPLAY (f), pix, &wunused, &iunused, &iunused,
+ &width, &height, &uunused, &uunused);
+
+ xim = XGetImage (FRAME_X_DISPLAY (f), pix, 0, 0, width, height,
+ ~0, XYPixmap);
+ if (!xim) return 0;
+
+ tmp_buf = gdk_pixbuf_new_from_data ((guchar *) xim->data,
+ GDK_COLORSPACE_RGB,
+ FALSE,
+ xim->bitmap_unit,
+ (int) width,
+ (int) height,
+ xim->bytes_per_line,
+ NULL,
+ NULL);
+ XDestroyImage (xim);
+ return tmp_buf;
+}
+
/* Apply GMASK to GPIX and return a GdkPixbuf with an alpha channel. */
static GdkPixbuf *
-xg_get_pixbuf_from_pix_and_mask (GdkPixmap *gpix,
- GdkPixmap *gmask,
- GdkColormap *cmap)
+xg_get_pixbuf_from_pix_and_mask (FRAME_PTR f,
+ Pixmap pix,
+ Pixmap mask)
{
int width, height;
GdkPixbuf *icon_buf, *tmp_buf;
- gdk_drawable_get_size (gpix, &width, &height);
- tmp_buf = gdk_pixbuf_get_from_drawable (NULL, gpix, cmap,
- 0, 0, 0, 0, width, height);
+ tmp_buf = xg_get_pixbuf_from_pixmap (f, pix);
icon_buf = gdk_pixbuf_add_alpha (tmp_buf, FALSE, 0, 0, 0);
g_object_unref (G_OBJECT (tmp_buf));
- if (gmask)
+ width = gdk_pixbuf_get_width (icon_buf);
+ height = gdk_pixbuf_get_height (icon_buf);
+
+ if (mask)
{
- GdkPixbuf *mask_buf = gdk_pixbuf_get_from_drawable (NULL,
- gmask,
- NULL,
- 0, 0, 0, 0,
- width, height);
+ GdkPixbuf *mask_buf = xg_get_pixbuf_from_pixmap (f, mask);
guchar *pixels = gdk_pixbuf_get_pixels (icon_buf);
guchar *mask_pixels = gdk_pixbuf_get_pixels (mask_buf);
int rowstride = gdk_pixbuf_get_rowstride (icon_buf);
{
Lisp_Object specified_file = Qnil;
Lisp_Object tail;
- extern Lisp_Object QCfile;
for (tail = XCDR (image);
NILP (specified_file) && CONSP (tail) && CONSP (XCDR (tail));
GtkWidget *widget,
GtkImage *old_widget)
{
- GdkPixmap *gpix;
- GdkPixmap *gmask;
- GdkDisplay *gdpy;
- GdkColormap *cmap;
GdkPixbuf *icon_buf;
/* If we have a file, let GTK do all the image handling.
on a monochrome display, and sometimes bad on all displays with
certain themes. */
- 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;
-
/* 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
not associated with the img->pixmap. The img->pixmap may be removed
by clearing the image cache and then the tool bar redraw fails, since
Gtk+ assumes the pixmap is always there. */
- cmap = gtk_widget_get_colormap (widget);
- icon_buf = xg_get_pixbuf_from_pix_and_mask (gpix, gmask, cmap);
+ icon_buf = xg_get_pixbuf_from_pix_and_mask (f, img->pixmap, img->mask);
- if (! old_widget)
- old_widget = GTK_IMAGE (gtk_image_new_from_pixbuf (icon_buf));
- else
- gtk_image_set_from_pixbuf (old_widget, icon_buf);
-
- g_object_unref (G_OBJECT (icon_buf));
+ if (icon_buf)
+ {
+ if (! old_widget)
+ old_widget = GTK_IMAGE (gtk_image_new_from_pixbuf (icon_buf));
+ else
+ gtk_image_set_from_pixbuf (old_widget, icon_buf);
- g_object_unref (G_OBJECT (gpix));
- if (gmask) g_object_unref (G_OBJECT (gmask));
+ g_object_unref (G_OBJECT (icon_buf));
+ }
return GTK_WIDGET (old_widget);
}
}
/* 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 (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)
{
gsize bytes_written;
unsigned char *p = (unsigned char *)str;
char *cp, *up;
- GError *error = NULL;
+ GError *err = NULL;
while (! (cp = g_locale_to_utf8 ((char *)p, -1, &bytes_read,
- &bytes_written, &error))
- && error->code == G_CONVERT_ERROR_ILLEGAL_SEQUENCE)
+ &bytes_written, &err))
+ && err->code == G_CONVERT_ERROR_ILLEGAL_SEQUENCE)
{
++nr_bad;
p += bytes_written+1;
- g_error_free (error);
- error = NULL;
+ g_error_free (err);
+ err = NULL;
}
- if (error)
+ if (err)
{
- g_error_free (error);
- error = NULL;
+ g_error_free (err);
+ err = NULL;
}
if (cp) g_free (cp);
p = (unsigned char *)str;
while (! (cp = g_locale_to_utf8 ((char *)p, -1, &bytes_read,
- &bytes_written, &error))
- && error->code == G_CONVERT_ERROR_ILLEGAL_SEQUENCE)
+ &bytes_written, &err))
+ && err->code == G_CONVERT_ERROR_ILLEGAL_SEQUENCE)
{
strncpy (up, (char *)p, bytes_written);
sprintf (up + bytes_written, "\\%03o", p[bytes_written]);
up[bytes_written+4] = '\0';
up += bytes_written+4;
p += bytes_written+1;
- g_error_free (error);
- error = NULL;
+ g_error_free (err);
+ err = NULL;
}
if (cp)
strcat (utf8_str, cp);
g_free (cp);
}
- if (error)
+ if (err)
{
- g_error_free (error);
- error = NULL;
+ g_error_free (err);
+ err = NULL;
}
}
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;
+ int get_bg = strcmp ("gtk_selection_bg_color", color_name) == 0;
+ int get_fg = !get_bg && strcmp ("gtk_selection_fg_color", color_name) == 0;
+
+ if (! FRAME_GTK_WIDGET (f) || ! (get_bg || get_fg))
+ return success_p;
+
+ BLOCK_INPUT;
+ {
+#ifdef HAVE_GTK3
+ GtkStyleContext *gsty
+ = gtk_widget_get_style_context (FRAME_GTK_OUTER_WIDGET (f));
+ GdkRGBA col;
+ char buf[64];
+ int state = GTK_STATE_FLAG_SELECTED|GTK_STATE_FLAG_FOCUSED;
+ if (get_fg)
+ gtk_style_context_get_color (gsty, state, &col);
+ else
+ gtk_style_context_get_background_color (gsty, state, &col);
+
+ sprintf (buf, "rgbi:%lf/%lf/%lf", col.red, col.green, col.blue);
+ success_p = XParseColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
+ buf, color);
+#else
+ GtkStyle *gsty = gtk_widget_get_style (FRAME_GTK_WIDGET (f));
+ GdkColor *grgb = get_bg
+ ? &gsty->bg[GTK_STATE_SELECTED]
+ : &gsty->fg[GTK_STATE_SELECTED];
+
+ color->red = grgb->red;
+ color->green = grgb->green;
+ color->blue = grgb->blue;
+ color->pixel = grgb->pixel;
+ success_p = 1;
+#endif
+
+ }
+ UNBLOCK_INPUT;
+ return success_p;
+}
+
+
+\f
+/***********************************************************************
+ 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_window_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_get_preferred_size (GTK_WIDGET (x->ttip_window), NULL, &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_window_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;
+}
\f
/***********************************************************************
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);
+ &pixelwidth, &pixelheight);
else return;
}
-
+
rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, pixelheight);
columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, pixelwidth);
/* 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. */
}
}
-/* 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 (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);
}
BLOCK_INPUT;
- gdkwin = gdk_xid_table_lookup_for_display (gdk_x11_lookup_xdisplay (dpy),
- wdesc);
+ gdkwin = gdk_x11_window_lookup_for_display (gdk_x11_lookup_xdisplay (dpy),
+ wdesc);
if (gdkwin)
{
GdkEvent event;
return gwdesc;
}
-/* Fill in the GdkColor C so that it represents PIXEL.
- W is the widget that color will be used for. Used to find colormap. */
+/* Set the background of widget W to PIXEL. */
static void
-xg_pix_to_gcolor (GtkWidget *w, long unsigned int pixel, GdkColor *c)
+xg_set_widget_bg (FRAME_PTR f, GtkWidget *w, long unsigned int pixel)
{
+#ifdef HAVE_GTK3
+ GdkRGBA bg;
+ XColor xbg;
+ xbg.pixel = pixel;
+ if (XQueryColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &xbg))
+ {
+ bg.red = (double)xbg.red/65536.0;
+ bg.green = (double)xbg.green/65536.0;
+ bg.blue = (double)xbg.blue/65536.0;
+ bg.alpha = 1.0;
+ gtk_widget_override_background_color (w, GTK_STATE_FLAG_NORMAL, &bg);
+ }
+#else
+ GdkColor bg;
GdkColormap *map = gtk_widget_get_colormap (w);
- gdk_colormap_query_color (map, pixel, c);
+ gdk_colormap_query_color (map, pixel, &bg);
+ gtk_widget_modify_bg (FRAME_GTK_WIDGET (f), GTK_STATE_NORMAL, &bg);
+#endif
+}
+
+/* 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);
+}
+
+/* Called when a delete-event occurs on WIDGET. */
+
+static gboolean
+delete_cb (GtkWidget *widget,
+ GdkEvent *event,
+ gpointer user_data)
+{
+#ifdef HAVE_GTK3
+ /* The event doesn't arrive in the normal event loop. Send event
+ here. */
+ FRAME_PTR f = (FRAME_PTR) user_data;
+ struct input_event ie;
+
+ EVENT_INIT (ie);
+ ie.kind = DELETE_WINDOW_EVENT;
+ XSETFRAME (ie.frame_or_window, f);
+ kbd_buffer_store_event (&ie);
+#endif
+
+ return TRUE;
}
/* Create and set up the GTK widgets for frame F.
xg_create_frame_widgets (FRAME_PTR f)
{
GtkWidget *wtop;
- GtkWidget *wvbox;
+ GtkWidget *wvbox, *whbox;
GtkWidget *wfixed;
- GdkColor bg;
GtkRcStyle *style;
char *title = 0;
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;
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_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);
/* Add callback to do nothing on WM_DELETE_WINDOW. The default in
GTK is to destroy the widget. We want Emacs to do that instead. */
g_signal_connect (G_OBJECT (wtop), "delete-event",
- G_CALLBACK (gtk_true), 0);
+ G_CALLBACK (delete_cb), f);
/* Convert our geometry parameters into a geometry string
and specify it.
/* Since GTK clears its window by filling with the background color,
we must keep X and GTK background in sync. */
- xg_pix_to_gcolor (wfixed, FRAME_BACKGROUND_PIXEL (f), &bg);
- gtk_widget_modify_bg (wfixed, GTK_STATE_NORMAL, &bg);
+ xg_set_widget_bg (f, wfixed, FRAME_BACKGROUND_PIXEL (f));
+#ifndef HAVE_GTK3
/* Also, do not let any background pixmap to be set, this looks very
bad as Emacs overwrites the background pixmap with its own idea
of background color. */
/* Must use g_strdup because gtk_widget_modify_style does g_free. */
style->bg_pixmap_name[GTK_STATE_NORMAL] = g_strdup ("<none>");
gtk_widget_modify_style (wfixed, style);
+#else
+ gtk_widget_set_can_focus (wfixed, TRUE);
+#endif
- /* 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))
+ {
+#ifdef USE_GTK_TOOLTIP
+ struct x_output *x = f->output_data.x;
+#endif
+ 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.
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);
{
if (FRAME_GTK_WIDGET (f))
{
- GdkColor gdk_bg;
-
BLOCK_INPUT;
- xg_pix_to_gcolor (FRAME_GTK_WIDGET (f), bg, &gdk_bg);
- gtk_widget_modify_bg (FRAME_GTK_WIDGET (f), GTK_STATE_NORMAL, &gdk_bg);
+ xg_set_widget_bg (f, FRAME_GTK_WIDGET (f), FRAME_BACKGROUND_PIXEL (f));
UNBLOCK_INPUT;
}
}
void
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);
- GdkPixmap *gmask = gdk_pixmap_foreign_new_for_display (gdpy, icon_mask);
- GdkPixbuf *gp = xg_get_pixbuf_from_pix_and_mask (gpix, gmask, NULL);
-
+ GdkPixbuf *gp = xg_get_pixbuf_from_pix_and_mask (f,
+ icon_pixmap,
+ icon_mask);
+ if (gp)
gtk_window_set_icon (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), gp);
}
/* 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':
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;
GtkDialog *wd = GTK_DIALOG (wdialog);
GtkBox *cur_box = GTK_BOX (gtk_dialog_get_action_area (wd));
widget_value *item;
- GtkWidget *wvbox;
- GtkWidget *whbox_up;
GtkWidget *whbox_down;
/* If the number of buttons is greater than 4, make two rows of buttons
if (make_two_rows)
{
- wvbox = gtk_vbox_new (TRUE, button_spacing);
- whbox_up = gtk_hbox_new (FALSE, 0);
+ GtkWidget *wvbox = gtk_vbox_new (TRUE, button_spacing);
+ GtkWidget *whbox_up = gtk_hbox_new (FALSE, 0);
whbox_down = gtk_hbox_new (FALSE, 0);
gtk_box_pack_start (cur_box, wvbox, FALSE, FALSE, 0);
/* 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_widget_get_preferred_size (w, NULL, &req);
gtk_box_set_spacing (wvbox, req.height);
if (item->value && strlen (item->value) > 0)
button_spacing = 2*req.width/strlen (item->value);
}
}
- if (utf8_label && utf8_label != item->value)
+ if (utf8_label)
g_free (utf8_label);
}
g_main_loop_quit (dd->loop);
g_main_loop_unref (dd->loop);
-
+
UNBLOCK_INPUT;
return Qnil;
xg_maybe_add_timer (gpointer data)
{
struct xg_dialog_data *dd = (struct xg_dialog_data *) data;
- EMACS_TIME next_time = timer_check (1);
+ EMACS_TIME next_time = timer_check ();
long secs = EMACS_SECS (next_time);
long usecs = EMACS_USECS (next_time);
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. */
(void) xg_maybe_add_timer (&dd);
g_main_loop_run (dd.loop);
-
+
dd.w = 0;
unbind_to (count, Qnil);
xg_uses_old_file_dialog (void)
{
#ifdef HAVE_GTK_FILE_SELECTION_NEW
- extern int x_gtk_use_old_file_dialog;
return x_gtk_use_old_file_dialog;
#else
return 0;
static void
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);
int mustmatch_p, int only_dir_p,
xg_get_file_func *func)
{
- char message[1024];
+ char msgbuf[1024];
GtkWidget *filewin, *wtoggle, *wbox, *wmessage;
GtkWindow *gwin = GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f));
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;
if (x_gtk_file_dialog_help_text)
{
- message[0] = '\0';
+ msgbuf[0] = '\0';
/* Gtk+ 2.10 has the file name text entry box integrated in the dialog.
Show the C-l help text only for versions < 2.10. */
if (gtk_check_version (2, 10, 0) && action != GTK_FILE_CHOOSER_ACTION_SAVE)
- strcat (message, "\nType C-l to display a file name text entry box.\n");
- strcat (message, "\nIf you don't like this file selector, use the "
+ strcat (msgbuf, "\nType C-l to display a file name text entry box.\n");
+ strcat (msgbuf, "\nIf you don't like this file selector, use the "
"corresponding\nkey binding or customize "
"use-file-dialog to turn it off.");
- wmessage = gtk_label_new (message);
+ wmessage = gtk_label_new (msgbuf);
gtk_widget_show (wmessage);
}
DEFAULT_NAME, if non-zero, is the default font name. */
char *
-xg_get_font_name (FRAME_PTR f, char *default_name)
+xg_get_font_name (FRAME_PTR f, const char *default_name)
{
GtkWidget *w;
char *fontname = NULL;
Returns the GtkHBox. */
static GtkWidget *
-make_widget_for_menu_item (char *utf8_label, char *utf8_key)
+make_widget_for_menu_item (const char *utf8_label, const char *utf8_key)
{
GtkWidget *wlbl;
GtkWidget *wkey;
but the MacOS X version doesn't either, so I guess that is OK. */
static GtkWidget *
-make_menu_item (char *utf8_label,
- char *utf8_key,
+make_menu_item (const char *utf8_label,
+ const char *utf8_key,
widget_value *item,
GSList **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. */
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));
int add_tearoff_p,
GtkWidget *topmenu,
xg_menu_cb_data *cl_data,
- char *name)
+ const char *name)
{
widget_value *item;
GtkWidget *wmenu = topmenu;
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
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. */
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;
static const char *
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 (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);
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;
}
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);
/* 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;
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);
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_get_sensitive (w))
gtk_widget_set_sensitive (w, FALSE);
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))
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);
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));
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_get_preferred_size (w, NULL, &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. */
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);
+ gtk_widget_get_preferred_size (x->menubar_widget, NULL, &req);
+
+ /* 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;
the container. */
x->menubar_widget = 0;
FRAME_MENUBAR_HEIGHT (f) = 0;
- xg_height_changed (f);
+ xg_height_or_width_changed (f);
UNBLOCK_INPUT;
}
}
+int
+xg_event_is_for_menubar (FRAME_PTR f, XEvent *event)
+{
+ struct x_output *x = f->output_data.x;
+ GList *iter;
+ GdkRectangle rec;
+ GList *list;
+ GdkDisplay *gdpy;
+ GdkWindow *gw;
+ GdkEvent gevent;
+ GtkWidget *gwdesc;
+
+ if (! x->menubar_widget) return 0;
+
+ if (! (event->xbutton.x >= 0
+ && event->xbutton.x < FRAME_PIXEL_WIDTH (f)
+ && event->xbutton.y >= 0
+ && event->xbutton.y < f->output_data.x->menubar_height
+ && event->xbutton.same_screen))
+ return 0;
+
+ gdpy = gdk_x11_lookup_xdisplay (FRAME_X_DISPLAY (f));
+ gw = gdk_x11_window_lookup_for_display (gdpy, event->xbutton.window);
+ if (! gw) return 0;
+ gevent.any.window = gw;
+ gwdesc = gtk_get_event_widget (&gevent);
+ if (! gwdesc) return 0;
+ if (! GTK_IS_MENU_BAR (gwdesc)
+ && ! GTK_IS_MENU_ITEM (gwdesc)
+ && ! gtk_widget_is_ancestor (x->menubar_widget, gwdesc))
+ return 0;
+
+ list = gtk_container_get_children (GTK_CONTAINER (x->menubar_widget));
+ if (! list) return 0;
+ rec.x = event->xbutton.x;
+ rec.y = event->xbutton.y;
+ rec.width = 1;
+ rec.height = 1;
+
+ for (iter = list ; iter; iter = g_list_next (iter))
+ {
+ GtkWidget *w = GTK_WIDGET (iter->data);
+ if (gtk_widget_get_mapped (w) && gtk_widget_intersect (w, &rec, NULL))
+ break;
+ }
+ g_list_free (list);
+ return iter == 0 ? 0 : 1;
+}
+
\f
/***********************************************************************
struct scroll_bar *bar,
GCallback scroll_callback,
GCallback end_callback,
- char *scroll_bar_name)
+ const char *scroll_bar_name)
{
GtkWidget *wscroll;
GtkWidget *webox;
- GtkObject *vadj;
int scroll_id;
+#ifdef HAVE_GTK3
+ GtkAdjustment *vadj;
+#else
+ GtkObject *vadj;
+#endif
/* Page, step increment values are not so important here, they
will be corrected in x_set_toolkit_scroll_bar_thumb. */
wscroll = gtk_vscrollbar_new (GTK_ADJUSTMENT (vadj));
webox = gtk_event_box_new ();
gtk_widget_set_name (wscroll, scroll_bar_name);
+#ifndef HAVE_GTK3
gtk_range_set_update_policy (GTK_RANGE (wscroll), GTK_UPDATE_CONTINUOUS);
+#endif
g_object_set_data (G_OBJECT (wscroll), XG_FRAME_DATA, (gpointer)f);
scroll_id = xg_store_widget_in_map (wscroll);
"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
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);
changed = 1;
}
- if (changed || (int) gtk_range_get_value (GTK_RANGE (wscroll)) != value)
+ if (changed || int_gtk_range_get_value (GTK_RANGE (wscroll)) != value)
{
BLOCK_INPUT;
ignore_gtk_scrollbar to make the callback do nothing */
xg_ignore_gtk_scrollbar = 1;
- if ((int) gtk_range_get_value (GTK_RANGE (wscroll)) != value)
+ if (int_gtk_range_get_value (GTK_RANGE (wscroll)) != value)
gtk_range_set_value (GTK_RANGE (wscroll), (gdouble)value);
else if (changed)
gtk_adjustment_changed (adj);
GtkWidget *w = gtk_grab_get_current ();
retval = w != 0 && GTK_IS_SCROLLBAR (w);
}
-
+
return retval;
}
{
/* The EMACS_INT cast avoids a warning. */
int idx = (int) (EMACS_INT) client_data;
- int mod = (int) (EMACS_INT) g_object_get_data (G_OBJECT (w),
- XG_TOOL_BAR_LAST_MODIFIER);
+ gpointer gmod = g_object_get_data (G_OBJECT (w), XG_TOOL_BAR_LAST_MODIFIER);
+ int mod = (int) (EMACS_INT) gmod;
FRAME_PTR f = (FRAME_PTR) g_object_get_data (G_OBJECT (w), XG_FRAME_DATA);
Lisp_Object key, frame;
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);
{
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);
}
{
GList *clist = gtk_container_get_children (GTK_CONTAINER (vb));
GtkWidget *c1 = (GtkWidget *) clist->data;
- GtkWidget *c2 = (GtkWidget *) clist->next->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;
static gboolean
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 *vb = gtk_bin_get_child (GTK_BIN (wbutton));
+ 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));
+ (wlbl ? gtk_label_get_text (wlbl) : "");
GtkWidget *wmenuimage;
GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (wbutton));
GtkImageType store_type = gtk_image_get_storage_type (wimage);
+ g_object_set (G_OBJECT (settings), "gtk-menu-images", TRUE, NULL);
+
if (store_type == GTK_IMAGE_STOCK)
{
gchar *stock_id;
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);
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_get_preferred_size (GTK_WIDGET (wbox), NULL, &req);
+ gtk_widget_get_preferred_size (w, NULL, &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);
}
}
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_get_preferred_size (GTK_WIDGET (wbox), NULL, &req);
+ gtk_widget_get_preferred_size (w, NULL, &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);
}
}
Returns FALSE to tell GTK to keep processing this event. */
+#ifndef HAVE_GTK3
static gboolean
xg_tool_bar_item_expose_callback (GtkWidget *w,
GdkEventExpose *event,
gint width, height;
gdk_drawable_get_size (event->window, &width, &height);
-
event->area.x -= width > event->area.width ? width-event->area.width : 0;
event->area.y -= height > event->area.height ? height-event->area.height : 0;
return FALSE;
}
+#endif
+
+#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 (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);
+ int into_hbox = EQ (pos, Qleft) || EQ (pos, Qright);
- gtk_container_add (GTK_CONTAINER (x->handlebox_widget),
- x->toolbar_widget);
-
- gtk_box_pack_start (GTK_BOX (x->vbox_widget), x->handlebox_widget,
- FALSE, FALSE, 0);
-
- gtk_box_reorder_child (GTK_BOX (x->vbox_widget), x->handlebox_widget,
- vbox_pos);
+ 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_widget_show (x->toolbar_widget);
- gtk_widget_show (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. */
-#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
static void
xg_create_tool_bar (FRAME_PTR f)
gtk_widget_set_name (x->toolbar_widget, "emacs-toolbar");
gtk_toolbar_set_style (GTK_TOOLBAR (x->toolbar_widget), GTK_TOOLBAR_ICONS);
- toolbar_set_orientation (x->toolbar_widget,
- GTK_ORIENTATION_HORIZONTAL);
+ toolbar_set_orientation (x->toolbar_widget, GTK_ORIENTATION_HORIZONTAL);
}
xg_make_tool_item (FRAME_PTR f,
GtkWidget *wimage,
GtkWidget **wbutton,
- char *label,
- int i)
+ const char *label,
+ int i, int horiz, int text_image)
{
GtkToolItem *ti = gtk_tool_item_new ();
- GtkWidget *vb = EQ (Vtool_bar_style, Qboth_horiz)
- ? gtk_hbox_new (FALSE, 0) : gtk_vbox_new (FALSE, 0);
+ 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)
+ 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_box_pack_start (GTK_BOX (vb), gtk_label_new (label), 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);
g_object_set_data (G_OBJECT (weventbox), XG_FRAME_DATA, (gpointer)f);
+#ifndef HAVE_GTK3
/* 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);
-
+#endif
gtk_tool_item_set_homogeneous (ti, FALSE);
/* Callback to save modifyer mask (Shift/Control, etc). GTK makes
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
G_CALLBACK (xg_tool_bar_help_callback),
(gpointer) (EMACS_INT) i);
}
-
+
if (wbutton) *wbutton = wb;
return ti;
}
-static void
-xg_show_toolbar_item (GtkToolItem *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)
{
- Lisp_Object style = Ftool_bar_get_system_style ();
-
- int show_label = EQ (style, Qboth)
- || EQ (style, Qboth_horiz) || EQ (style, Qtext);
- int show_image = ! EQ (style, Qtext);
- int horiz = EQ (style, Qboth_horiz);
-
- GtkWidget *weventbox = gtk_bin_get_child (GTK_BIN (ti));
- GtkWidget *wbutton = gtk_bin_get_child (GTK_BIN (weventbox));
- GtkWidget *vb = gtk_bin_get_child (GTK_BIN (wbutton));
+ gpointer old;
GtkWidget *wimage;
+ GtkWidget *vb = XG_BIN_CHILD (wbutton);
GtkWidget *wlbl = xg_get_tool_bar_widgets (vb, &wimage);
- GtkWidget *new_box = NULL;
- if (GTK_IS_VBOX (vb) && horiz)
- new_box = gtk_hbox_new (FALSE, 0);
- else if (GTK_IS_HBOX (vb) && !horiz && show_label && show_image)
- new_box = gtk_vbox_new (FALSE, 0);
- if (new_box)
+ /* Check if the tool icon matches. */
+ if (stock_name)
{
- g_object_ref (G_OBJECT (wimage));
- g_object_ref (G_OBJECT (wlbl));
- gtk_container_remove (GTK_CONTAINER (vb), wimage);
- gtk_container_remove (GTK_CONTAINER (vb), wlbl);
- gtk_widget_destroy (GTK_WIDGET (vb));
- gtk_box_pack_start (GTK_BOX (new_box), wimage, TRUE, TRUE, 0);
- gtk_box_pack_start (GTK_BOX (new_box), wlbl, TRUE, TRUE, 0);
- gtk_container_add (GTK_CONTAINER (wbutton), new_box);
- g_object_unref (G_OBJECT (wimage));
- g_object_unref (G_OBJECT (wlbl));
- vb = new_box;
+ 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
+ {
+ gpointer gold_img = g_object_get_data (G_OBJECT (wimage),
+ XG_TOOL_BAR_IMAGE_DATA);
+ Pixmap old_img = (Pixmap) gold_img;
+ if (old_img != img->pixmap)
+ return 1;
+ }
+
+ /* Check button configuration and label. */
+ if ((horiz ? GTK_IS_VBOX (vb) : GTK_IS_HBOX (vb))
+ || (label ? (wlbl == NULL) : (wlbl != NULL)))
+ return 1;
- if (show_label) gtk_widget_show (wlbl);
- else gtk_widget_hide (wlbl);
- if (show_image) gtk_widget_show (wimage);
- else gtk_widget_hide (wimage);
- gtk_widget_show (GTK_WIDGET (weventbox));
- gtk_widget_show (GTK_WIDGET (vb));
- gtk_widget_show (GTK_WIDGET (wbutton));
- gtk_widget_show (GTK_WIDGET (ti));
+ /* 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;
-/* Update the tool bar for frame F. Add new buttons and remove old. */
+ gtk_widget_get_preferred_size (GTK_WIDGET (x->handlebox_widget), NULL, &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;
+ }
-extern Lisp_Object Qx_gtk_map_stock;
+ 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 (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;
GtkToolItem *ti;
GtkTextDirection dir;
int pack_tool_bar = x->handlebox_widget == NULL;
+ Lisp_Object style;
+ int text_image, horiz;
if (! FRAME_GTK_WIDGET (f))
return;
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 (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));
char *icon_name = NULL;
Lisp_Object rtl;
GtkWidget *wbutton = NULL;
- GtkWidget *weventbox;
Lisp_Object specified_file;
- char *label = SSDATA (PROP (TOOL_BAR_ITEM_LABEL));
-
- ti = gtk_toolbar_get_nth_item (GTK_TOOLBAR (wtoolbar), 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;
}
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))
{
if (img->load_failed_p || img->pixmap == None)
{
if (ti)
- gtk_widget_hide_all (GTK_WIDGET (ti));
- else
- {
- /* Insert an empty (non-image) button */
- ti = xg_make_tool_item (f, NULL, NULL, "", i);
- gtk_toolbar_insert (GTK_TOOLBAR (wtoolbar), ti, -1);
- }
+ 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,
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);
- ti = xg_make_tool_item (f, w, &wbutton, label, i);
- gtk_toolbar_insert (GTK_TOOLBAR (wtoolbar), ti, -1);
- gtk_widget_set_sensitive (wbutton, enabled_p);
- }
- else
- {
- GtkWidget *vb = gtk_bin_get_child (GTK_BIN (wbutton));
- GtkWidget *wimage;
- GtkWidget *wlbl = xg_get_tool_bar_widgets (vb, &wimage);
-
- 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);
- gtk_label_set_text (GTK_LABEL (wlbl), label);
- 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,
- GTK_IMAGE (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);
+ 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);
}
- xg_show_toolbar_item (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 (wtoolbar), 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 (wtoolbar), &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;
}
/* 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;
+}
+
\f
/***********************************************************************
/* Make dialogs close on C-g. Since file dialog inherits from
dialog, this works for them also. */
binding_set = gtk_binding_set_by_class (g_type_class_ref (GTK_TYPE_DIALOG));
- gtk_binding_entry_add_signal (binding_set, GDK_g, GDK_CONTROL_MASK,
+ gtk_binding_entry_add_signal (binding_set, GDK_KEY_g, GDK_CONTROL_MASK,
"close", 0);
/* Make menus close on C-g. */
binding_set = gtk_binding_set_by_class (g_type_class_ref
(GTK_TYPE_MENU_SHELL));
- gtk_binding_entry_add_signal (binding_set, GDK_g, GDK_CONTROL_MASK,
+ gtk_binding_entry_add_signal (binding_set, GDK_KEY_g, GDK_CONTROL_MASK,
"cancel", 0);
}
#endif /* USE_GTK */
-
-/* arch-tag: fe7104da-bc1e-4aba-9bd1-f349c528f7e3
- (do not change this comment) */