/* Functions for creating and updating GTK widgets.
-Copyright (C) 2003-2011 Free Software Foundation, Inc.
+Copyright (C) 2003-2012 Free Software Foundation, Inc.
This file is part of GNU Emacs.
#include <config.h>
#ifdef USE_GTK
+#include <float.h>
#include <signal.h>
#include <stdio.h>
#include <setjmp.h>
#ifdef HAVE_GTK3
#include <gtk/gtkx.h>
+#include "emacsgtkfixed.h"
#endif
#define FRAME_TOTAL_PIXEL_HEIGHT(f) \
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 gtk_box_new(ori, spacing) \
+ ((ori) == GTK_ORIENTATION_HORIZONTAL \
+ ? gtk_hbox_new (FALSE, (spacing)) : gtk_vbox_new (FALSE, (spacing)))
+#define gtk_scrollbar_new(ori, spacing) \
+ ((ori) == GTK_ORIENTATION_HORIZONTAL \
+ ? gtk_hscrollbar_new ((spacing)) : gtk_vscrollbar_new ((spacing)))
#ifndef GDK_KEY_g
#define GDK_KEY_g GDK_g
#endif
-#endif
+#endif /* HAVE_GTK3 */
#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);
-}
+static void update_theme_scrollbar_width (void);
\f
/***********************************************************************
Returns non-zero if display could be opened, zero if display could not
be opened, and less than zero if the GTK version doesn't support
- multipe displays. */
+ multiple displays. */
void
xg_display_open (char *display_name, Display **dpy)
}
else
{
- wv = (widget_value *) xmalloc (sizeof (widget_value));
+ wv = xmalloc (sizeof *wv);
malloc_cpt++;
}
memset (wv, 0, sizeof (widget_value));
GDK_COLORSPACE_RGB,
FALSE,
xim->bitmap_unit,
- (int) width,
- (int) height,
+ width,
+ height,
xim->bytes_per_line,
NULL,
NULL);
/* 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
+ Otherwise the highlighting and dimming the tool bar code in GTK does
will look bad. For display with more than 8 planes we just use the
pixmap and mask directly. For monochrome displays, GTK doesn't seem
able to use external pixmaps, it looks bad whatever we do.
static void
xg_set_cursor (GtkWidget *w, GdkCursor *cursor)
{
- GdkWindow *window = gtk_widget_get_window(w);
+ GdkWindow *window = gtk_widget_get_window (w);
GList *children = gdk_window_peek_children (window);
gdk_window_set_cursor (window, cursor);
if (!utf8_str)
{
/* Probably some control characters in str. Escape them. */
- size_t nr_bad = 0;
+ ptrdiff_t len;
+ ptrdiff_t nr_bad = 0;
gsize bytes_read;
gsize bytes_written;
unsigned char *p = (unsigned char *)str;
}
if (cp) g_free (cp);
- up = utf8_str = xmalloc (strlen (str) + nr_bad * 4 + 1);
+ len = strlen (str);
+ if ((min (PTRDIFF_MAX, SIZE_MAX) - len - 1) / 4 < nr_bad)
+ memory_full (SIZE_MAX);
+ up = utf8_str = xmalloc (len + nr_bad * 4 + 1);
p = (unsigned char *)str;
while (! (cp = g_locale_to_utf8 ((char *)p, -1, &bytes_read,
&bytes_written, &err))
&& err->code == G_CONVERT_ERROR_ILLEGAL_SEQUENCE)
{
- strncpy (up, (char *)p, bytes_written);
+ memcpy (up, 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 (err);
GtkStyleContext *gsty
= gtk_widget_get_style_context (FRAME_GTK_OUTER_WIDGET (f));
GdkRGBA col;
- char buf[64];
+ char buf[sizeof "rgbi://" + 3 * (DBL_MAX_10_EXP + sizeof "-1.000000" - 1)];
int state = GTK_STATE_FLAG_SELECTED|GTK_STATE_FLAG_FOCUSED;
if (get_fg)
gtk_style_context_get_color (gsty, state, &col);
struct x_output *x = f->output_data.x;
if (x->ttip_widget == NULL)
{
+ GtkWidget *p;
+ GList *list, *iter;
+
g_object_set (G_OBJECT (widget), "has-tooltip", FALSE, NULL);
x->ttip_widget = tooltip;
g_object_ref (G_OBJECT (tooltip));
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));
+
+ /* Change stupid Gtk+ default line wrapping. */
+ p = gtk_widget_get_parent (x->ttip_lbl);
+ list = gtk_container_get_children (GTK_CONTAINER (p));
+ for (iter = list; iter; iter = g_list_next (iter))
+ {
+ GtkWidget *w = GTK_WIDGET (iter->data);
+ if (GTK_IS_LABEL (w))
+ gtk_label_set_line_wrap (GTK_LABEL (w), FALSE);
+ }
+ g_list_free (list);
+
/* ATK needs an empty title for some reason. */
gtk_window_set_title (x->ttip_window, "");
/* Realize so we can safely get screen later on. */
int
xg_prepare_tooltip (FRAME_PTR f,
- Lisp_Object string,
- int *width,
+ Lisp_Object string,
+ int *width,
int *height)
{
#ifndef USE_GTK_TOOLTIP
(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
+ /* Put our 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, SSDATA (encoded_string));
gtk_widget_get_preferred_size (GTK_WIDGET (x->ttip_window), NULL, &req);
if (width) *width = req.width;
}
/* Hide tooltip if shown. Do nothing if not shown.
- Return non-zero if tip was hidden, non-ero if not (i.e. not using
+ Return non-zero if tip was hidden, non-zero if not (i.e. not using
system tooltips). */
int
int xneg = f->size_hint_flags & XNegative;
int top = f->top_pos;
int yneg = f->size_hint_flags & YNegative;
- char geom_str[32];
+ char geom_str[sizeof "=x--" + 4 * INT_STRLEN_BOUND (int)];
if (xneg)
left = -left;
}
}
-/* Resize the outer window of frame F after chainging the height.
+/* Resize the outer window of frame F after changing the height.
COLUMNS/ROWS is the size the edit area shall have after the resize. */
void
{
GdkEvent event;
event.any.window = gdkwin;
+ event.any.type = GDK_NOTHING;
gwdesc = gtk_get_event_widget (&event);
}
struct input_event event;
GdkDisplay *gdpy = (GdkDisplay *) user_data;
const char *display_name = gdk_display_get_name (gdpy);
+ Display *dpy = GDK_DISPLAY_XDISPLAY (gdpy);
EVENT_INIT (event);
event.kind = CONFIG_CHANGED_EVENT;
- event.frame_or_window = make_string (display_name, strlen (display_name));
+ event.frame_or_window = build_string (display_name);
/* Theme doesn't change often, so intern is called seldom. */
event.arg = intern ("theme-name");
kbd_buffer_store_event (&event);
+
+ update_theme_scrollbar_width ();
+
+ /* If scroll bar width changed, we need set the new size on all frames
+ on this display. */
+ if (dpy)
+ {
+ Lisp_Object rest, frame;
+ FOR_EACH_FRAME (rest, frame)
+ {
+ FRAME_PTR f = XFRAME (frame);
+ if (FRAME_X_DISPLAY (f) == dpy)
+ {
+ x_set_scroll_bar_default_width (f);
+ xg_frame_set_char_size (f, FRAME_COLS (f), FRAME_LINES (f));
+ }
+ }
+ }
}
/* Called when a delete-event occurs on WIDGET. */
GtkWidget *wtop;
GtkWidget *wvbox, *whbox;
GtkWidget *wfixed;
+#ifndef HAVE_GTK3
GtkRcStyle *style;
+#endif
char *title = 0;
BLOCK_INPUT;
if (FRAME_X_EMBEDDED_P (f))
- wtop = gtk_plug_new (f->output_data.x->parent_desc);
+ {
+ GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (FRAME_X_DISPLAY (f));
+ wtop = gtk_plug_new_for_display (gdpy, f->output_data.x->parent_desc);
+ }
else
wtop = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ /* gtk_window_set_has_resize_grip is a Gtk+ 3.0 function but Ubuntu
+ has backported it to Gtk+ 2.0 and they add the resize grip for
+ Gtk+ 2.0 applications also. But it has a bug that makes Emacs loop
+ forever, so disable the grip. */
+#if GTK_MAJOR_VERSION < 3 && defined (HAVE_GTK_WINDOW_SET_HAS_RESIZE_GRIP)
+ gtk_window_set_has_resize_grip (GTK_WINDOW (wtop), FALSE);
+#endif
+
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 */
+ wvbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
+ whbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+ gtk_box_set_homogeneous (GTK_BOX (wvbox), FALSE);
+ gtk_box_set_homogeneous (GTK_BOX (whbox), FALSE);
+
+#ifdef HAVE_GTK3
+ wfixed = emacs_fixed_new (f);
+#else
+ wfixed = gtk_fixed_new ();
+#endif
if (! wtop || ! wvbox || ! whbox || ! wfixed)
{
gtk_widget_modify_style (wfixed, style);
#else
gtk_widget_set_can_focus (wfixed, TRUE);
+ gtk_window_set_resizable (GTK_WINDOW (wtop), TRUE);
#endif
#ifdef USE_GTK_TOOLTIP
hint_flags |= GDK_HINT_BASE_SIZE;
base_width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, 0) + FRAME_TOOLBAR_WIDTH (f);
- base_height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, 0)
+ /* Use one row here so base_height does not become zero.
+ Gtk+ and/or Unity on Ubuntu 12.04 can't handle it. */
+ base_height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, 1)
+ FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f);
check_frame_size (f, &min_rows, &min_cols);
+ if (min_rows > 0) --min_rows; /* We used one row in base_height = ... 1); */
size_hints.base_width = base_width;
size_hints.base_height = base_height;
{
BLOCK_INPUT;
gtk_window_set_geometry_hints (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
- NULL, &size_hints, hint_flags);
+ NULL, &size_hints, hint_flags);
f->output_data.x->size_hints = size_hints;
f->output_data.x->hint_flags = hint_flags;
UNBLOCK_INPUT;
/* Callback for dialogs that get WM_DELETE_WINDOW. We pop down
the dialog, but return TRUE so the event does not propagate further
in GTK. This prevents GTK from destroying the dialog widget automatically
- and we can always destrou the widget manually, regardles of how
+ and we can always destroy the widget manually, regardless of how
it was popped down (button press or WM_DELETE_WINDOW).
W is the dialog widget.
EVENT is the GdkEvent that represents WM_DELETE_WINDOW (not used).
if (make_two_rows)
{
- GtkWidget *wvbox = gtk_vbox_new (TRUE, button_spacing);
- GtkWidget *whbox_up = gtk_hbox_new (FALSE, 0);
- whbox_down = gtk_hbox_new (FALSE, 0);
+ GtkWidget *wvbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, button_spacing);
+ GtkWidget *whbox_up = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+ gtk_box_set_homogeneous (GTK_BOX (wvbox), TRUE);
+ gtk_box_set_homogeneous (GTK_BOX (whbox_up), FALSE);
+ whbox_down = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+ gtk_box_set_homogeneous (GTK_BOX (whbox_down), FALSE);
gtk_box_pack_start (cur_box, wvbox, FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (wvbox), whbox_up, FALSE, FALSE, 0);
{
struct xg_dialog_data *dd = (struct xg_dialog_data *) data;
EMACS_TIME next_time = timer_check ();
- long secs = EMACS_SECS (next_time);
- long usecs = EMACS_USECS (next_time);
dd->timerid = 0;
- if (secs >= 0 && usecs >= 0 && secs < ((guint)-1)/1000)
+ if (EMACS_TIME_VALID_P (next_time))
{
- dd->timerid = g_timeout_add (secs * 1000 + usecs/1000,
- xg_maybe_add_timer,
- dd);
+ time_t s = EMACS_SECS (next_time);
+ int per_ms = EMACS_TIME_RESOLUTION / 1000;
+ int ms = (EMACS_NSECS (next_time) + per_ms - 1) / per_ms;
+ if (s <= ((guint) -1 - ms) / 1000)
+ dd->timerid = g_timeout_add (s * 1000 + ms, xg_maybe_add_timer, dd);
}
return FALSE;
}
static int
xg_dialog_run (FRAME_PTR f, GtkWidget *w)
{
- int count = SPECPDL_INDEX ();
+ ptrdiff_t count = SPECPDL_INDEX ();
struct xg_dialog_data dd;
xg_set_screen (w, f);
PROMPT is a prompt to show to the user. May not be NULL.
DEFAULT_FILENAME is a default selection to be displayed. May be NULL.
If MUSTMATCH_P is non-zero, the returned file name must be an existing
- file. *FUNC is set to a function that can be used to retrieve the
- selected file name from the returned widget.
+ file. (Actually, this only has cosmetic effects, the user can
+ still enter a non-existing file.) *FUNC is set to a function that
+ can be used to retrieve the selected file name from the returned widget.
Returns the created widget. */
NULL);
gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (filewin), TRUE);
- wbox = gtk_vbox_new (FALSE, 0);
+ wbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
+ gtk_box_set_homogeneous (GTK_BOX (wbox), FALSE);
gtk_widget_show (wbox);
wtoggle = gtk_check_button_new_with_label ("Show hidden files.");
int filesel_done = 0;
xg_get_file_func func;
-#if defined (HAVE_GTK_AND_PTHREAD) && defined (__SIGRTMIN)
+#if defined (HAVE_PTHREAD) && defined (__SIGRTMIN)
/* I really don't know why this is needed, but without this the GLIBC add on
library linuxthreads hangs when the Gnome file chooser backend creates
threads. */
sigblock (sigmask (__SIGRTMIN));
-#endif /* HAVE_GTK_AND_PTHREAD */
+#endif /* HAVE_PTHREAD */
#ifdef HAVE_GTK_FILE_SELECTION_NEW
filesel_done = xg_dialog_run (f, w);
-#if defined (HAVE_GTK_AND_PTHREAD) && defined (__SIGRTMIN)
+#if defined (HAVE_PTHREAD) && defined (__SIGRTMIN)
sigunblock (sigmask (__SIGRTMIN));
#endif
char *fontname = NULL;
int done = 0;
-#if defined (HAVE_GTK_AND_PTHREAD) && defined (__SIGRTMIN)
+#if defined (HAVE_PTHREAD) && defined (__SIGRTMIN)
sigblock (sigmask (__SIGRTMIN));
-#endif /* HAVE_GTK_AND_PTHREAD */
+#endif /* HAVE_PTHREAD */
w = gtk_font_selection_dialog_new ("Pick a font");
if (!default_name)
done = xg_dialog_run (f, w);
-#if defined (HAVE_GTK_AND_PTHREAD) && defined (__SIGRTMIN)
+#if defined (HAVE_PTHREAD) && defined (__SIGRTMIN)
sigunblock (sigmask (__SIGRTMIN));
#endif
{
if (! cl_data)
{
- cl_data = (xg_menu_cb_data*) xmalloc (sizeof (*cl_data));
+ cl_data = xmalloc (sizeof *cl_data);
cl_data->f = f;
cl_data->menu_bar_vector = f->menu_bar_vector;
cl_data->menu_bar_items_used = f->menu_bar_items_used;
GtkWidget *wkey;
GtkWidget *wbox;
- wbox = gtk_hbox_new (FALSE, 0);
+ wbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+ gtk_box_set_homogeneous (GTK_BOX (wbox), FALSE);
wlbl = gtk_label_new (utf8_label);
wkey = gtk_label_new (utf8_key);
/* Create a menu item widget, and connect the callbacks.
- ITEM decribes the menu item.
+ ITEM describes the menu item.
F is the frame the created menu belongs to.
SELECT_CB is the callback to use when a menu item is selected.
HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
if (utf8_label) g_free (utf8_label);
if (utf8_key) g_free (utf8_key);
- cb_data = xmalloc (sizeof (xg_menu_item_cb_data));
+ cb_data = xmalloc (sizeof *cb_data);
xg_list_insert (&xg_menu_item_cb_list, &cb_data->ptrs);
HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
POP_UP_P is non-zero if we shall create a popup menu.
MENU_BAR_P is non-zero if we shall create a menu bar.
- ADD_TEAROFF_P is non-zero if we shall add a teroff menu item. Ignored
+ ADD_TEAROFF_P is non-zero if we shall add a tearoff menu item. Ignored
if MENU_BAR_P is non-zero.
TOPMENU is the topmost GtkWidget that others shall be placed under.
It may be NULL, in that case we create the appropriate widget
utf8_key = get_utf8_string (val->key);
/* See if W is a menu item with a key. See make_menu_item above. */
- if (GTK_IS_HBOX (wchild))
+ if (GTK_IS_BOX (wchild))
{
GList *list = gtk_container_get_children (GTK_CONTAINER (wchild));
}
}
- /* Remove widgets from first structual change. */
+ /* Remove widgets from first structural change. */
if (iter)
{
/* If we are adding new menu items below, we must remove from
gw = gdk_x11_window_lookup_for_display (gdpy, event->xbutton.window);
if (! gw) return 0;
gevent.any.window = gw;
+ gevent.any.type = GDK_NOTHING;
gwdesc = gtk_get_event_widget (&gevent);
if (! gwdesc) return 0;
if (! GTK_IS_MENU_BAR (gwdesc)
int xg_ignore_gtk_scrollbar;
+/* The width of the scroll bar for the current theme. */
+
+static int scroll_bar_width_for_theme;
+
/* 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
{
GtkWidget **widgets;
- int max_size;
- int used;
+ ptrdiff_t max_size;
+ ptrdiff_t used;
} id_to_widget;
/* Grow this much every time we need to allocate more */
/* Store the widget pointer W in id_to_widget and return the integer index. */
-static int
+static ptrdiff_t
xg_store_widget_in_map (GtkWidget *w)
{
- int i;
+ ptrdiff_t i;
if (id_to_widget.max_size == id_to_widget.used)
{
- int new_size = id_to_widget.max_size + ID_TO_WIDGET_INCR;
+ ptrdiff_t new_size;
+ if (TYPE_MAXIMUM (Window) - ID_TO_WIDGET_INCR < id_to_widget.max_size)
+ memory_full (SIZE_MAX);
- id_to_widget.widgets = xrealloc (id_to_widget.widgets,
- sizeof (GtkWidget *)*new_size);
+ new_size = id_to_widget.max_size + ID_TO_WIDGET_INCR;
+ id_to_widget.widgets = xnrealloc (id_to_widget.widgets,
+ new_size, sizeof (GtkWidget *));
for (i = id_to_widget.max_size; i < new_size; ++i)
id_to_widget.widgets[i] = 0;
Called when scroll bar is destroyed. */
static void
-xg_remove_widget_from_map (int idx)
+xg_remove_widget_from_map (ptrdiff_t idx)
{
if (idx < id_to_widget.max_size && id_to_widget.widgets[idx] != 0)
{
/* Get the widget pointer at IDX from id_to_widget. */
static GtkWidget *
-xg_get_widget_from_map (int idx)
+xg_get_widget_from_map (ptrdiff_t idx)
{
if (idx < id_to_widget.max_size && id_to_widget.widgets[idx] != 0)
return id_to_widget.widgets[idx];
return 0;
}
-int
-xg_get_default_scrollbar_width (FRAME_PTR f)
+static void
+update_theme_scrollbar_width (void)
{
#ifdef HAVE_GTK3
GtkAdjustment *vadj;
#endif
GtkWidget *wscroll;
int w = 0, b = 0;
+
vadj = gtk_adjustment_new (XG_SB_MIN, XG_SB_MIN, XG_SB_MAX, 0.1, 0.1, 0.1);
- wscroll = gtk_vscrollbar_new (GTK_ADJUSTMENT (vadj));
+ wscroll = gtk_scrollbar_new (GTK_ORIENTATION_VERTICAL, GTK_ADJUSTMENT (vadj));
+ g_object_ref_sink (G_OBJECT (wscroll));
gtk_widget_style_get (wscroll, "slider-width", &w, "trough-border", &b, NULL);
gtk_widget_destroy (wscroll);
+ g_object_unref (G_OBJECT (wscroll));
w += 2*b;
if (w < 16) w = 16;
- return w;
+ scroll_bar_width_for_theme = w;
+}
+
+int
+xg_get_default_scrollbar_width (void)
+{
+ return scroll_bar_width_for_theme;
}
/* Return the scrollbar id for X Window WID on display DPY.
Return -1 if WID not in id_to_widget. */
-int
+ptrdiff_t
xg_get_scroll_id_for_window (Display *dpy, Window wid)
{
- int idx;
+ ptrdiff_t idx;
GtkWidget *w;
w = xg_win_to_widget (dpy, wid);
static void
xg_gtk_scroll_destroy (GtkWidget *widget, gpointer data)
{
- int id = (intptr_t) data;
+ intptr_t id = (intptr_t) data;
xg_remove_widget_from_map (id);
}
vadj = gtk_adjustment_new (XG_SB_MIN, XG_SB_MIN, XG_SB_MAX,
0.1, 0.1, 0.1);
- wscroll = gtk_vscrollbar_new (GTK_ADJUSTMENT (vadj));
+ wscroll = gtk_scrollbar_new (GTK_ORIENTATION_VERTICAL, GTK_ADJUSTMENT (vadj));
webox = gtk_event_box_new ();
gtk_widget_set_name (wscroll, scroll_bar_name);
#ifndef HAVE_GTK3
/* Remove the scroll bar represented by SCROLLBAR_ID from the frame F. */
void
-xg_remove_scroll_bar (FRAME_PTR f, int scrollbar_id)
+xg_remove_scroll_bar (FRAME_PTR f, ptrdiff_t scrollbar_id)
{
GtkWidget *w = xg_get_widget_from_map (scrollbar_id);
if (w)
void
xg_update_scrollbar_pos (FRAME_PTR f,
- int scrollbar_id,
+ ptrdiff_t scrollbar_id,
int top,
int left,
int width,
}
}
+/* 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);
+}
+
+
/* Set the thumb size and position of scroll bar BAR. We are currently
displaying PORTION out of a whole WHOLE, and our position POSITION. */
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 */
- gtk_adjustment_set_page_increment (adj,(int) (0.95*size));
+ gtk_adjustment_set_page_increment (adj, size - size / 20);
changed = 1;
}
}
{
/* 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)
- != gtk_widget_get_window (f->output_data.x->edit_widget);
+ GdkWindow *gwin;
+#ifdef HAVE_GTK3
+ GdkDevice *gdev = gdk_device_manager_get_client_pointer
+ (gdk_display_get_device_manager (gdpy));
+ gwin = gdk_device_get_window_at_position (gdev, NULL, NULL);
+#else
+ gwin = gdk_display_get_window_at_pointer (gdpy, NULL, NULL);
+#endif
+ retval = gwin != gtk_widget_get_window (f->output_data.x->edit_widget);
}
else if (f
&& ((event->type == ButtonRelease && event->xbutton.button < 4)
xg_create_tool_bar (FRAME_PTR f)
{
struct x_output *x = f->output_data.x;
+#if GTK_CHECK_VERSION (3, 3, 6)
+ GtkStyleContext *gsty;
+#endif
x->toolbar_widget = gtk_toolbar_new ();
x->toolbar_detached = 0;
gtk_toolbar_set_style (GTK_TOOLBAR (x->toolbar_widget), GTK_TOOLBAR_ICONS);
toolbar_set_orientation (x->toolbar_widget, GTK_ORIENTATION_HORIZONTAL);
+#if GTK_CHECK_VERSION (3, 3, 6)
+ gsty = gtk_widget_get_style_context (x->toolbar_widget);
+ gtk_style_context_add_class (gsty, "primary-toolbar");
+#endif
}
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 *vb = gtk_box_new (horiz
+ ? GTK_ORIENTATION_HORIZONTAL
+ : GTK_ORIENTATION_VERTICAL,
+ 0);
GtkWidget *wb = gtk_button_new ();
+ /* The eventbox is here so we can have tooltips on disabled items. */
GtkWidget *weventbox = gtk_event_box_new ();
+#if GTK_CHECK_VERSION (3, 3, 6)
+ GtkCssProvider *css_prov = gtk_css_provider_new ();
+ GtkStyleContext *gsty;
+
+ gtk_css_provider_load_from_data (css_prov,
+ "GtkEventBox {"
+ " background-color: transparent;"
+ "}",
+ -1, NULL);
+
+ gsty = gtk_widget_get_style_context (weventbox);
+ gtk_style_context_add_provider (gsty,
+ GTK_STYLE_PROVIDER (css_prov),
+ GTK_STYLE_PROVIDER_PRIORITY_USER);
+ g_object_unref (css_prov);
+#endif
+
+ gtk_box_set_homogeneous (GTK_BOX (vb), FALSE);
if (wimage && !text_image)
gtk_box_pack_start (GTK_BOX (vb), wimage, TRUE, TRUE, 0);
gtk_container_add (GTK_CONTAINER (weventbox), wb);
gtk_container_add (GTK_CONTAINER (ti), weventbox);
- if (wimage)
+ if (wimage || label)
{
intptr_t ii = i;
gpointer gi = (gpointer) ii;
#endif
gtk_tool_item_set_homogeneous (ti, FALSE);
- /* Callback to save modifyer mask (Shift/Control, etc). GTK makes
+ /* Callback to save modifier 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",
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),
return ti;
}
+static int
+is_box_type (GtkWidget *vb, int is_horizontal)
+{
+#ifdef HAVE_GTK3
+ int ret = 0;
+ if (GTK_IS_BOX (vb))
+ {
+ GtkOrientation ori = gtk_orientable_get_orientation (GTK_ORIENTABLE (vb));
+ ret = (ori == GTK_ORIENTATION_HORIZONTAL && is_horizontal)
+ || (ori == GTK_ORIENTATION_VERTICAL && ! is_horizontal);
+ }
+ return ret;
+#else
+ return is_horizontal ? GTK_IS_VBOX (vb) : GTK_IS_HBOX (vb);
+#endif
+}
+
+
static int
xg_tool_item_stale_p (GtkWidget *wbutton, const char *stock_name,
const char *icon_name, const struct image *img,
GtkWidget *wlbl = xg_get_tool_bar_widgets (vb, &wimage);
/* Check if the tool icon matches. */
- if (stock_name)
+ if (stock_name && wimage)
{
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)
+ else if (icon_name && wimage)
{
old = g_object_get_data (G_OBJECT (wimage),
XG_TOOL_BAR_ICON_NAME);
if (!old || strcmp (old, icon_name))
return 1;
}
- else
+ else if (wimage)
{
gpointer gold_img = g_object_get_data (G_OBJECT (wimage),
- XG_TOOL_BAR_IMAGE_DATA);
+ 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))
+ if (is_box_type (vb, horiz)
|| (label ? (wlbl == NULL) : (wlbl != NULL)))
return 1;
/* Ensure label is correct. */
- if (label)
+ if (label && wlbl)
gtk_label_set_text (GTK_LABEL (wlbl), label);
return 0;
}
BLOCK_INPUT;
- if (INTEGERP (Vtool_bar_button_margin)
- && XINT (Vtool_bar_button_margin) > 0)
+ if (RANGED_INTEGERP (1, Vtool_bar_button_margin, INT_MAX))
{
hmargin = XFASTINT (Vtool_bar_button_margin);
vmargin = XFASTINT (Vtool_bar_button_margin);
}
else if (CONSP (Vtool_bar_button_margin))
{
- if (INTEGERP (XCAR (Vtool_bar_button_margin))
- && XINT (XCAR (Vtool_bar_button_margin)) > 0)
+ if (RANGED_INTEGERP (1, XCAR (Vtool_bar_button_margin), INT_MAX))
hmargin = XFASTINT (XCAR (Vtool_bar_button_margin));
- if (INTEGERP (XCDR (Vtool_bar_button_margin))
- && XINT (XCDR (Vtool_bar_button_margin)) > 0)
+ if (RANGED_INTEGERP (1, XCDR (Vtool_bar_button_margin), INT_MAX))
vmargin = XFASTINT (XCDR (Vtool_bar_button_margin));
}
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;
+ ptrdiff_t img_id;
int icon_size = 0;
struct image *img = NULL;
Lisp_Object image;
? TOOL_BAR_IMAGE_DISABLED_SELECTED
: TOOL_BAR_IMAGE_DISABLED_DESELECTED);
- xassert (ASIZE (image) >= idx);
+ eassert (ASIZE (image) >= idx);
image = AREF (image, idx);
}
else
xg_initialize (void)
{
GtkBindingSet *binding_set;
+ GtkSettings *settings;
#if HAVE_XFT
/* Work around a bug with corrupted data if libXft gets unloaded. This way
id_to_widget.max_size = id_to_widget.used = 0;
id_to_widget.widgets = 0;
+ settings = gtk_settings_get_for_screen (gdk_display_get_default_screen
+ (gdk_display_get_default ()));
/* Remove F10 as a menu accelerator, it does not mix well with Emacs key
bindings. It doesn't seem to be any way to remove properties,
so we set it to VoidSymbol which in X means "no key". */
- gtk_settings_set_string_property (gtk_settings_get_default (),
+ gtk_settings_set_string_property (settings,
"gtk-menu-bar-accel",
"VoidSymbol",
EMACS_CLASS);
/* Make GTK text input widgets use Emacs style keybindings. This is
Emacs after all. */
- gtk_settings_set_string_property (gtk_settings_get_default (),
+ gtk_settings_set_string_property (settings,
"gtk-key-theme-name",
"Emacs",
EMACS_CLASS);
(GTK_TYPE_MENU_SHELL));
gtk_binding_entry_add_signal (binding_set, GDK_KEY_g, GDK_CONTROL_MASK,
"cancel", 0);
+ update_theme_scrollbar_width ();
}
#endif /* USE_GTK */