/* Functions for creating and updating GTK widgets.
- Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+ Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008
+ Free Software Foundation, Inc.
This file is part of GNU Emacs.
#ifdef HAVE_GTK_MULTIDISPLAY
+/* Gtk does not work well without any display open. Emacs may close
+ all its displays. In that case, keep a display around just for
+ the purpose of having one. */
+
+static GdkDisplay *gdpy_def;
+
+
/* Return the GdkDisplay that corresponds to the X display DPY. */
static GdkDisplay *
break;
}
- if (! new_dpy) return; /* Emacs will exit anyway. */
+ if (new_dpy)
+ gdpy_new = gdk_x11_lookup_xdisplay (new_dpy);
+ else
+ {
+ if (!gdpy_def)
+ gdpy_def = gdk_display_open (gdk_display_get_name (gdpy));
+ gdpy_new = gdpy_def;
+ }
- gdpy_new = gdk_x11_lookup_xdisplay (new_dpy);
gdk_display_manager_set_default_display (gdk_display_manager_get (),
gdpy_new);
}
return icon_buf;
}
+static Lisp_Object
+file_for_image(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));
+ tail = XCDR (XCDR (tail)))
+ if (EQ (XCAR (tail), QCfile))
+ specified_file = XCAR (XCDR (tail));
+
+ return specified_file;
+}
+
/* For the image defined in IMG, make and return a GtkImage. For displays with
8 planes or less we must make a GdkPixbuf and apply the mask manually.
Otherwise the highlightning and dimming the tool bar code in GTK does
GdkPixmap *gpix;
GdkPixmap *gmask;
GdkDisplay *gdpy;
+ GdkColormap *cmap;
+ GdkPixbuf *icon_buf;
/* If we have a file, let GTK do all the image handling.
This seems to be the only way to make insensitive and activated icons
look good in all cases. */
- Lisp_Object specified_file = Qnil;
- Lisp_Object tail;
+ Lisp_Object specified_file = file_for_image (img->spec);
Lisp_Object file;
- extern Lisp_Object QCfile;
-
- for (tail = XCDR (img->spec);
- NILP (specified_file) && CONSP (tail) && CONSP (XCDR (tail));
- tail = XCDR (XCDR (tail)))
- if (EQ (XCAR (tail), QCfile))
- specified_file = XCAR (XCDR (tail));
/* We already loaded the image once before calling this
function, so this only fails if the image file has been removed.
gpix = gdk_pixmap_foreign_new_for_display (gdpy, img->pixmap);
gmask = img->mask ? gdk_pixmap_foreign_new_for_display (gdpy, img->mask) : 0;
- if (x_screen_planes (f) > 8 || x_screen_planes (f) == 1)
- {
- if (! old_widget)
- old_widget = GTK_IMAGE (gtk_image_new_from_pixmap (gpix, gmask));
- else
- gtk_image_set_from_pixmap (old_widget, gpix, gmask);
- }
+ /* This is a workaround to make icons look good on pseudo color
+ displays. Apparently GTK expects the images to have an alpha
+ channel. If they don't, insensitive and activated icons will
+ look bad. This workaround does not work on monochrome displays,
+ and is strictly not needed on true color/static color displays (i.e.
+ 16 bits and higher). But we do it anyway so we get a pixbuf that is
+ 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);
+
+ if (! old_widget)
+ old_widget = GTK_IMAGE (gtk_image_new_from_pixbuf (icon_buf));
else
- {
-
- /* This is a workaround to make icons look good on pseudo color
- displays. Apparently GTK expects the images to have an alpha
- channel. If they don't, insensitive and activated icons will
- look bad. This workaround does not work on monochrome displays,
- and is not needed on true color/static color displays (i.e.
- 16 bits and higher). */
- GdkColormap *cmap = gtk_widget_get_colormap (widget);
- GdkPixbuf *icon_buf = xg_get_pixbuf_from_pix_and_mask (gpix, gmask, cmap);
-
- if (! old_widget)
- old_widget = GTK_IMAGE (gtk_image_new_from_pixbuf (icon_buf));
- else
- gtk_image_set_from_pixbuf (old_widget, icon_buf);
+ gtk_image_set_from_pixbuf (old_widget, icon_buf);
- g_object_unref (G_OBJECT (icon_buf));
- }
+ g_object_unref (G_OBJECT (icon_buf));
g_object_unref (G_OBJECT (gpix));
if (gmask) g_object_unref (G_OBJECT (gmask));
FRAME_PTR f;
{
if (f->size_hint_flags & USPosition)
- {
- int left = f->left_pos;
- int xneg = f->size_hint_flags & XNegative;
- int top = f->top_pos;
- int yneg = f->size_hint_flags & YNegative;
- char geom_str[32];
-
- if (xneg)
- left = -left;
- if (yneg)
- top = -top;
-
- sprintf (geom_str, "=%dx%d%c%d%c%d",
- FRAME_PIXEL_WIDTH (f),
- FRAME_TOTAL_PIXEL_HEIGHT (f),
- (xneg ? '-' : '+'), left,
- (yneg ? '-' : '+'), top);
-
- if (!gtk_window_parse_geometry (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
- geom_str))
- fprintf (stderr, "Failed to parse: '%s'\n", geom_str);
- } else if (f->size_hint_flags & PPosition) {
+ {
+ int left = f->left_pos;
+ int xneg = f->size_hint_flags & XNegative;
+ int top = f->top_pos;
+ int yneg = f->size_hint_flags & YNegative;
+ char geom_str[32];
+
+ if (xneg)
+ left = -left;
+ if (yneg)
+ top = -top;
+
+ sprintf (geom_str, "=%dx%d%c%d%c%d",
+ FRAME_PIXEL_WIDTH (f),
+ FRAME_TOTAL_PIXEL_HEIGHT (f),
+ (xneg ? '-' : '+'), left,
+ (yneg ? '-' : '+'), top);
+
+ if (!gtk_window_parse_geometry (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (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);
- }
}
-/* Resize the outer window of frame F after chainging the height.
- This happend when the menu bar or the tool bar is added or removed.
- COLUMNS/ROWS is the size the edit area shall have after the resize. */
-
-static void
-xg_resize_outer_widget (f, columns, rows)
- FRAME_PTR f;
- int columns;
- int rows;
-{
- /* If we are not mapped yet, set geometry once again, as window
- height now have changed. */
- if (! GTK_WIDGET_MAPPED (FRAME_GTK_OUTER_WIDGET (f)))
- xg_set_geometry (f);
-
- xg_frame_set_char_size (f, columns, rows);
- gdk_window_process_all_updates ();
-}
-
-/* Function to handle resize of our widgets. Since Emacs has some layouts
- that does not fit well with GTK standard containers, we do most layout
- manually.
+/* Function to handle resize of our frame. As we have a Gtk+ tool bar
+ and a Gtk+ menu bar, we get resize events for the edit part of the
+ frame only. We let Gtk+ deal with the Gtk+ parts.
F is the frame to resize.
PIXELWIDTH, PIXELHEIGHT is the new size in pixels. */
void
-xg_resize_widgets (f, pixelwidth, pixelheight)
+xg_frame_resized (f, pixelwidth, pixelheight)
FRAME_PTR f;
int pixelwidth, pixelheight;
{
- int mbheight = FRAME_MENUBAR_HEIGHT (f);
- int tbheight = FRAME_TOOLBAR_HEIGHT (f);
- int rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, (pixelheight
- - mbheight - tbheight));
+ int rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, pixelheight);
int columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, pixelwidth);
if (FRAME_GTK_WIDGET (f)
|| pixelwidth != FRAME_PIXEL_WIDTH (f)
|| pixelheight != FRAME_PIXEL_HEIGHT (f)))
{
- struct x_output *x = f->output_data.x;
- GtkAllocation all;
-
- all.y = mbheight + tbheight;
- all.x = 0;
+ FRAME_PIXEL_WIDTH (f) = pixelwidth;
+ FRAME_PIXEL_HEIGHT (f) = pixelheight;
- all.width = pixelwidth;
- all.height = pixelheight - mbheight - tbheight;
+ if (rows != FRAME_LINES (f) || columns != FRAME_COLS (f)
+ || (f->new_text_lines != 0 && f->new_text_lines != rows)
+ || (f->new_text_cols != 0 && f->new_text_cols != columns))
+ {
+ change_frame_size (f, rows, columns, 0, 1, 0);
+ SET_FRAME_GARBAGED (f);
+ cancel_mouse_face (f);
+ }
+ }
+}
- gtk_widget_size_allocate (x->edit_widget, &all);
+/* Process all pending events on the display for frame F. */
- change_frame_size (f, rows, columns, 0, 1, 0);
- SET_FRAME_GARBAGED (f);
- cancel_mouse_face (f);
+static void
+flush_and_sync (f)
+ FRAME_PTR f;
+{
+ gdk_window_process_all_updates ();
+ x_sync (f);
+ while (gtk_events_pending ())
+ {
+ gtk_main_iteration ();
+ gdk_window_process_all_updates ();
+ x_sync (f);
}
}
+/* Turn wm hints for resize off on frame F */
-/* Update our widget size to be COLS/ROWS characters for frame F. */
+static void
+x_wm_size_hint_off (f)
+ FRAME_PTR f;
+{
+ GdkGeometry size_hints;
+ gint hint_flags = 0;
+ memset (&size_hints, 0, sizeof (size_hints));
+ hint_flags |= GDK_HINT_RESIZE_INC | GDK_HINT_MIN_SIZE;
+ size_hints.width_inc = 1;
+ size_hints.height_inc = 1;
+ hint_flags |= GDK_HINT_BASE_SIZE;
+ size_hints.base_width = 1;
+ size_hints.base_height = 1;
+ size_hints.min_width = 1;
+ size_hints.min_height = 1;
+ gtk_window_set_geometry_hints (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
+ NULL,
+ &size_hints,
+ hint_flags);
+ /* Make sure these get set again in next call to x_wm_set_size_hint. */
+ f->output_data.x->hint_flags &= ~hint_flags;
+ flush_and_sync (f);
+}
+
+/* Resize the outer window of frame F after chainging the height.
+ This happend when the menu bar or the tool bar is added or removed.
+ COLUMNS/ROWS is the size the edit area shall have after the resize. */
void
xg_frame_set_char_size (f, cols, rows)
+ FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f);
int pixelwidth;
+ if (FRAME_PIXEL_HEIGHT (f) == 0)
+ return;
+
/* Take into account the size of the scroll bar. Always use the
number of columns occupied by the scroll bar here otherwise we
might end up with a frame width that is not a multiple of the
pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, cols);
/* Must resize our top level widget. Font size may have changed,
- but not rows/cols. */
+ but not rows/cols.
+ Turn wm hints (min/max size and size increments) of temporarly.
+ It interferes too much, when for example adding or removing the
+ menu/tool bar. */
+ x_wm_size_hint_off (f);
gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
pixelwidth, pixelheight);
- xg_resize_widgets (f, pixelwidth, pixelheight);
+ flush_and_sync (f);
x_wm_set_size_hint (f, 0, 0);
- SET_FRAME_GARBAGED (f);
- cancel_mouse_face (f);
}
/* Convert an X Window WSESC on display DPY to its corresponding GtkWidget.
BLOCK_INPUT;
- wtop = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ if (FRAME_X_EMBEDDED_P (f))
+ wtop = gtk_plug_new (f->output_data.x->parent_desc);
+ else
+ wtop = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
xg_set_screen (wtop, f);
wvbox = gtk_vbox_new (FALSE, 0);
if (FRAME_EXTERNAL_TOOL_BAR (f))
update_frame_tool_bar (f);
- /* The tool bar is created but first there are no items in it.
- This causes it to be zero height. Later items are added, but then
- the frame is already mapped, so there is a "jumping" resize.
- This makes geometry handling difficult, for example -0-0 will end
- up in the wrong place as tool bar height has not been taken into account.
- So we cheat a bit by setting a height that is what it will have
- later on when tool bar items are added. */
- if (FRAME_EXTERNAL_TOOL_BAR (f) && f->n_tool_bar_items == 0)
- FRAME_TOOLBAR_HEIGHT (f) = 38;
-
-
/* We don't want this widget double buffered, because we draw on it
with regular X drawing primitives, so from a GTK/GDK point of
view, the widget is totally blank. When an expose comes, this
hint_flags |= GDK_HINT_USER_POS;
}
- BLOCK_INPUT;
+ if (hint_flags != f->output_data.x->hint_flags
+ || memcmp (&size_hints,
+ &f->output_data.x->size_hints,
+ sizeof (size_hints)) != 0)
+ {
+ BLOCK_INPUT;
- gtk_window_set_geometry_hints (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
- FRAME_GTK_OUTER_WIDGET (f),
- &size_hints,
- hint_flags);
+ gtk_window_set_geometry_hints (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
+ NULL,
+ &size_hints,
+ hint_flags);
- f->output_data.x->size_hints = size_hints;
- f->output_data.x->hint_flags = hint_flags;
- UNBLOCK_INPUT;
+ f->output_data.x->size_hints = size_hints;
+ f->output_data.x->hint_flags = hint_flags;
+ UNBLOCK_INPUT;
+ }
}
}
{
Lisp_Object file;
struct gcpro gcpro1;
- GCPRO1 (file);
char *utf8_filename;
+ GCPRO1 (file);
file = build_string (default_filename);
UNGRAB_P is TRUE if this is an ungrab, FALSE if it is a grab.
CLIENT_DATA is NULL (not used). */
+/* Keep track of total number of grabs. */
+static int menu_grab_callback_cnt;
+
static void
menu_grab_callback (GtkWidget *widget,
gboolean ungrab_p,
gpointer client_data)
{
- /* Keep track of total number of grabs. */
- static int cnt;
+ if (ungrab_p) menu_grab_callback_cnt--;
+ else menu_grab_callback_cnt++;
- if (ungrab_p) cnt--;
- else cnt++;
-
- if (cnt > 0 && ! xg_timer) xg_start_timer ();
- else if (cnt == 0 && xg_timer) xg_stop_timer ();
+ if (menu_grab_callback_cnt > 0 && ! xg_timer) xg_start_timer ();
+ else if (menu_grab_callback_cnt == 0 && xg_timer) xg_stop_timer ();
}
/* Make a GTK widget that contains both UTF8_LABEL and UTF8_KEY (both
/* Return non-zero if LABEL specifies a separator (GTK only has one
separator type) */
+static 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)
{
&& strncmp (label, "--", 2) == 0
&& label[2] != '-')
{
- static 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,
- };
-
int i;
label += 2;
/* The height has changed, resize outer widget and set columns
rows to what we had before adding the menu bar. */
- xg_resize_outer_widget (f, FRAME_COLS (f), FRAME_LINES (f));
+ xg_frame_set_char_size (f, FRAME_COLS (f), FRAME_LINES (f));
SET_FRAME_GARBAGED (f);
UNBLOCK_INPUT;
/* The height has changed, resize outer widget and set columns
rows to what we had before removing the menu bar. */
- xg_resize_outer_widget (f, FRAME_COLS (f), FRAME_LINES (f));
+ xg_frame_set_char_size (f, FRAME_COLS (f), FRAME_LINES (f));
SET_FRAME_GARBAGED (f);
UNBLOCK_INPUT;
int xg_ignore_gtk_scrollbar;
-/* SET_SCROLL_BAR_X_WINDOW assumes the second argument fits in
- 32 bits. But we want to store pointers, and they may be larger
- than 32 bits. Keep a mapping from integer index to widget pointers
- to get around the 32 bit limitation. */
+/* Xlib's `Window' fits in 32 bits. But we want to store pointers, and they
+ may be larger than 32 bits. Keep a mapping from integer index to widget
+ pointers to get around the 32 bit limitation. */
static struct
{
/* Set the cursor to an arrow. */
xg_set_cursor (webox, FRAME_X_DISPLAY_INFO (f)->xg_cursor);
- SET_SCROLL_BAR_X_WINDOW (bar, scroll_id);
+ bar->x_window = scroll_id;
}
/* Make the scroll bar represented by SCROLLBAR_ID visible. */
struct scroll_bar *bar;
int portion, position, whole;
{
- GtkWidget *wscroll = xg_get_widget_from_map (SCROLL_BAR_X_WINDOW (bar));
+ GtkWidget *wscroll = xg_get_widget_from_map (bar->x_window);
FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
/* The key for storing the button widget in its proxy menu item. */
#define XG_TOOL_BAR_PROXY_BUTTON "emacs-tool-bar-proxy-button"
+/* The key for the data we put in the GtkImage widgets. The data is
+ the stock name used by Emacs. We use this to see if we need to update
+ the GtkImage with a new image. */
+#define XG_TOOL_BAR_STOCK_NAME "emacs-tool-bar-stock-name"
+
+/* As above, but this is used for named theme widgets, as opposed to
+ stock items. */
+#define XG_TOOL_BAR_ICON_NAME "emacs-tool-bar-icon-name"
+
+/* Callback function invoked when a tool bar item is pressed.
+ W is the button widget in the tool bar that got pressed,
+ CLIENT_DATA is an integer that is the index of the button in the
+ tool bar. 0 is the first button. */
+
static gboolean
xg_tool_bar_button_cb (widget, event, user_data)
GtkWidget *widget;
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);
+
if (store_type == GTK_IMAGE_STOCK)
{
gchar *stock_id;
wmenuimage = gtk_image_new_from_pixbuf (dest_pixbuf);
}
+ else
+ {
+ fprintf (stderr, "internal error: GTK_IMAGE_PIXBUF failed\n");
+ abort ();
+ }
+ }
+ else if (store_type == GTK_IMAGE_ICON_NAME)
+ {
+ const gchar *icon_name;
+ GtkIconSize icon_size;
+
+ gtk_image_get_icon_name (wimage, &icon_name, &icon_size);
+ wmenuimage = gtk_image_new_from_icon_name (icon_name,
+ GTK_ICON_SIZE_MENU);
+ }
+ else
+ {
+ fprintf (stderr, "internal error: store_type is %d\n", store_type);
+ abort ();
}
}
if (wmenuimage)
/* The height has changed, resize outer widget and set columns
rows to what we had before detaching the tool bar. */
- xg_resize_outer_widget (f, FRAME_COLS (f), FRAME_LINES (f));
+ xg_frame_set_char_size (f, FRAME_COLS (f), FRAME_LINES (f));
}
}
/* The height has changed, resize outer widget and set columns
rows to what we had before attaching the tool bar. */
- xg_resize_outer_widget (f, FRAME_COLS (f), FRAME_LINES (f));
+ xg_frame_set_char_size (f, FRAME_COLS (f), FRAME_LINES (f));
}
}
return FALSE;
}
-/* This callback is called when a tool bar shall be redrawn.
- We need to update the tool bar from here in case the image cache
- has deleted the pixmaps used in the tool bar.
- W is the GtkToolbar to be redrawn.
- EVENT is the expose event for W.
- CLIENT_DATA is pointing to the frame for this tool bar.
-
- Returns FALSE to tell GTK to keep processing this event. */
-
-static gboolean
-xg_tool_bar_expose_callback (w, event, client_data)
- GtkWidget *w;
- GdkEventExpose *event;
- gpointer client_data;
-{
- update_frame_tool_bar ((FRAME_PTR) client_data);
- return FALSE;
-}
-
-/* Create a tool bar for frame F. */
+/* Attach a tool bar to frame F. */
static void
-xg_create_tool_bar (f)
+xg_pack_tool_bar (f)
FRAME_PTR f;
{
struct x_output *x = f->output_data.x;
- GtkRequisition req;
int vbox_pos = x->menubar_widget ? 1 : 0;
- x->toolbar_widget = gtk_toolbar_new ();
x->handlebox_widget = gtk_handle_box_new ();
- x->toolbar_detached = 0;
+ 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);
+}
+
+/* Create a tool bar for frame F. */
+
+static void
+xg_create_tool_bar (f)
+ FRAME_PTR f;
+{
+ struct x_output *x = f->output_data.x;
+ GtkRequisition req;
+
+ x->toolbar_widget = gtk_toolbar_new ();
+ x->toolbar_detached = 0;
gtk_widget_set_name (x->toolbar_widget, "emacs-toolbar");
gtk_toolbar_set_style (GTK_TOOLBAR (x->toolbar_widget), GTK_TOOLBAR_ICONS);
gtk_toolbar_set_orientation (GTK_TOOLBAR (x->toolbar_widget),
GTK_ORIENTATION_HORIZONTAL);
+}
- 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);
- g_signal_connect (G_OBJECT (x->toolbar_widget),
- "expose-event",
- G_CALLBACK (xg_tool_bar_expose_callback),
- f);
- gtk_widget_show_all (x->handlebox_widget);
+#define PROP(IDX) AREF (f->tool_bar_items, i * TOOL_BAR_ITEM_NSLOTS + (IDX))
- gtk_widget_size_request (x->toolbar_widget, &req);
- FRAME_TOOLBAR_HEIGHT (f) = req.height;
+/* Find the right-to-left image named by RTL in the tool bar images for F.
+ Returns IMAGE if RTL is not found. */
- /* The height has changed, resize outer widget and set columns
- rows to what we had before adding the tool bar. */
- xg_resize_outer_widget (f, FRAME_COLS (f), FRAME_LINES (f));
+static Lisp_Object
+find_rtl_image (f, image, rtl)
+ FRAME_PTR f;
+ Lisp_Object image;
+ Lisp_Object rtl;
+{
+ int i;
+ Lisp_Object file, rtl_name;
+ struct gcpro gcpro1, gcpro2;
+ GCPRO2 (file, rtl_name);
- SET_FRAME_GARBAGED (f);
+ rtl_name = Ffile_name_nondirectory (rtl);
+
+ for (i = 0; i < f->n_tool_bar_items; ++i)
+ {
+ Lisp_Object rtl_image = PROP (TOOL_BAR_ITEM_IMAGES);
+ if (!NILP (file = file_for_image (rtl_image)))
+ {
+ file = call1 (intern ("file-name-sans-extension"),
+ Ffile_name_nondirectory (file));
+ if (EQ (Fequal (file, rtl_name), Qt))
+ {
+ image = rtl_image;
+ break;
+ }
+ }
+ }
+
+ return image;
}
/* Update the tool bar for frame F. Add new buttons and remove old. */
GtkRequisition old_req, new_req;
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;
if (! FRAME_GTK_WIDGET (f))
return;
if (! x->toolbar_widget)
xg_create_tool_bar (f);
- gtk_widget_size_request (x->toolbar_widget, &old_req);
+ wtoolbar = GTK_TOOLBAR (x->toolbar_widget);
+ gtk_widget_size_request (GTK_WIDGET (wtoolbar), &old_req);
+ dir = gtk_widget_get_direction (x->toolbar_widget);
for (i = 0; i < f->n_tool_bar_items; ++i)
{
-#define PROP(IDX) AREF (f->tool_bar_items, i * TOOL_BAR_ITEM_NSLOTS + (IDX))
int enabled_p = !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P));
int selected_p = !NILP (PROP (TOOL_BAR_ITEM_SELECTED_P));
int idx;
int img_id;
- struct image *img;
+ int icon_size = 0;
+ struct image *img = NULL;
Lisp_Object image;
- GtkWidget *wbutton;
+ Lisp_Object stock;
+ GtkStockItem stock_item;
+ char *stock_name = NULL;
+ char *icon_name = NULL;
+ Lisp_Object rtl;
+ GtkWidget *wbutton = NULL;
GtkWidget *weventbox;
+ Lisp_Object func = intern ("x-gtk-map-stock");
+ Lisp_Object specified_file;
ti = gtk_toolbar_get_nth_item (GTK_TOOLBAR (x->toolbar_widget), i);
wbutton = gtk_bin_get_child (GTK_BIN (weventbox));
}
- /* If image is a vector, choose the image according to the
- button state. */
image = PROP (TOOL_BAR_ITEM_IMAGES);
- if (VECTORP (image))
- {
- if (enabled_p)
- idx = (selected_p
- ? TOOL_BAR_IMAGE_ENABLED_SELECTED
- : TOOL_BAR_IMAGE_ENABLED_DESELECTED);
- else
- idx = (selected_p
- ? TOOL_BAR_IMAGE_DISABLED_SELECTED
- : TOOL_BAR_IMAGE_DISABLED_DESELECTED);
-
- xassert (ASIZE (image) >= idx);
- image = AREF (image, idx);
- }
- else
- idx = -1;
/* Ignore invalid image specifications. */
if (!valid_image_p (image))
{
- if (ti) gtk_widget_hide_all (GTK_WIDGET (ti));
+ if (wbutton) gtk_widget_hide (wbutton);
continue;
}
- img_id = lookup_image (f, image);
- img = IMAGE_FROM_ID (f, img_id);
- prepare_image_for_display (f, img);
+ specified_file = file_for_image (image);
+ if (!NILP (specified_file) && EQ (Qt, Ffboundp (func)))
+ stock = call1 (func, specified_file);
- if (img->load_failed_p || img->pixmap == None)
+ if (! NILP (stock) && STRINGP (stock))
{
- if (ti)
- gtk_widget_hide_all (GTK_WIDGET (ti));
- else
+ stock_name = SSDATA (stock);
+ if (stock_name[0] == 'n' && stock_name[1] == ':')
{
- /* 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);
+ GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (wtoolbar));
+ GtkIconTheme *icon_theme = gtk_icon_theme_get_for_screen (screen);
+
+ icon_name = stock_name + 2;
+ stock_name = NULL;
+ stock = Qnil;
+
+ if (! gtk_icon_theme_has_icon (icon_theme, icon_name))
+ icon_name = NULL;
+ else
+ 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);
+ else
+ {
+ stock = Qnil;
+ stock_name = NULL;
+ }
+ }
+
+ 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
+ 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);
+ }
+
+ if (VECTORP (image))
+ {
+ if (enabled_p)
+ idx = (selected_p
+ ? TOOL_BAR_IMAGE_ENABLED_SELECTED
+ : TOOL_BAR_IMAGE_ENABLED_DESELECTED);
+ else
+ idx = (selected_p
+ ? TOOL_BAR_IMAGE_DISABLED_SELECTED
+ : TOOL_BAR_IMAGE_DISABLED_DESELECTED);
+
+ xassert (ASIZE (image) >= idx);
+ image = AREF (image, idx);
+ }
+ else
+ idx = -1;
+
+ img_id = lookup_image (f, image);
+ img = IMAGE_FROM_ID (f, img_id);
+ prepare_image_for_display (f, img);
+
+ 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;
}
- continue;
}
if (ti == NULL)
{
- GtkWidget *w = xg_get_image_for_pixmap (f, img, x->widget, NULL);
+ GtkWidget *w;
+ 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,
+ (gpointer) xstrdup (stock_name),
+ (GDestroyNotify) xfree);
+ }
+ else if (icon_name)
+ {
+ w = gtk_image_new_from_icon_name (icon_name, icon_size);
+ g_object_set_data_full (G_OBJECT (w), XG_TOOL_BAR_ICON_NAME,
+ (gpointer) xstrdup (icon_name),
+ (GDestroyNotify) xfree);
+ }
+ 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_widget_show_all (GTK_WIDGET (ti));
- /* 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);
g_object_set_data (G_OBJECT (weventbox), XG_FRAME_DATA, (gpointer)f);
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);
- gtk_misc_set_padding (GTK_MISC (wimage), hmargin, vmargin);
+ 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);
- if (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_STOCK_NAME,
+ NULL);
+ g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_ICON_NAME, NULL);
+ }
- g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_IMAGE_DATA,
- (gpointer)img->pixmap);
+ gtk_misc_set_padding (GTK_MISC (wimage), hmargin, vmargin);
gtk_widget_set_sensitive (wbutton, enabled_p);
gtk_widget_show_all (GTK_WIDGET (ti));
if (ti) gtk_widget_hide_all (GTK_WIDGET (ti));
} while (ti != NULL);
- gtk_widget_size_request (x->toolbar_widget, &new_req);
- if (old_req.height != new_req.height
+ new_req.height = 0;
+ gtk_widget_size_request (GTK_WIDGET (wtoolbar), &new_req);
+
+ if (pack_tool_bar && f->n_tool_bar_items != 0)
+ xg_pack_tool_bar (f);
+
+ if (new_req.height != 0
+ && f->n_tool_bar_items != 0
+ && old_req.height != new_req.height
&& ! FRAME_X_OUTPUT (f)->toolbar_detached)
{
FRAME_TOOLBAR_HEIGHT (f) = new_req.height;
- xg_resize_outer_widget (f, FRAME_COLS (f), FRAME_LINES (f));
+ xg_frame_set_char_size (f, FRAME_COLS (f), FRAME_LINES (f));
}
UNBLOCK_INPUT;
if (x->toolbar_widget)
{
+ int is_packed = x->handlebox_widget != 0;
BLOCK_INPUT;
- gtk_container_remove (GTK_CONTAINER (x->vbox_widget),
- x->handlebox_widget);
+ /* 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);
+ else
+ gtk_widget_destroy (x->toolbar_widget);
+
x->toolbar_widget = 0;
x->handlebox_widget = 0;
FRAME_TOOLBAR_HEIGHT (f) = 0;
/* The height has changed, resize outer widget and set columns
rows to what we had before removing the tool bar. */
- xg_resize_outer_widget (f, FRAME_COLS (f), FRAME_LINES (f));
-
- SET_FRAME_GARBAGED (f);
+ xg_frame_set_char_size (f, FRAME_COLS (f), FRAME_LINES (f));
UNBLOCK_INPUT;
}
}
we keep it permanently linked in. */
XftInit (0);
#endif
+
+ gdpy_def = NULL;
xg_ignore_gtk_scrollbar = 0;
xg_detached_menus = 0;
xg_menu_cb_list.prev = xg_menu_cb_list.next =