/* Functions for creating and updating GTK widgets.
-Copyright (C) 2003-2013 Free Software Foundation, Inc.
+Copyright (C) 2003-2014 Free Software Foundation, Inc.
This file is part of GNU Emacs.
#include "blockinput.h"
#include "syssignal.h"
#include "window.h"
+#include "buffer.h"
#include "gtkutil.h"
#include "termhooks.h"
#include "keyboard.h"
#include "charset.h"
#include "coding.h"
+#include "font.h"
+
#include <gdk/gdkkeysyms.h>
#include "xsettings.h"
#define remove_submenu(w) gtk_menu_item_remove_submenu ((w))
#endif
+#ifdef HAVE_FREETYPE
#if GTK_CHECK_VERSION (3, 2, 0)
#define USE_NEW_GTK_FONT_CHOOSER 1
#else
#define gtk_font_chooser_set_font(x, y) \
gtk_font_selection_dialog_set_font_name (x, y)
#endif
+#endif /* HAVE_FREETYPE */
#ifndef HAVE_GTK3
#ifdef USE_GTK_TOOLTIP
#define XG_BIN_CHILD(x) gtk_bin_get_child (GTK_BIN (x))
static void update_theme_scrollbar_width (void);
+static void update_theme_scrollbar_height (void);
#define TB_INFO_KEY "xg_frame_tb_info"
struct xg_frame_tb_info
/***********************************************************************
Utility functions
***********************************************************************/
-/* The next two variables and functions are taken from lwlib. */
-static widget_value *widget_value_free_list;
-static int malloc_cpt;
-
-/* Allocate a widget_value structure, either by taking one from the
- widget_value_free_list or by malloc:ing a new one.
-
- Return a pointer to the allocated structure. */
-
-widget_value *
-malloc_widget_value (void)
-{
- widget_value *wv;
- if (widget_value_free_list)
- {
- wv = widget_value_free_list;
- widget_value_free_list = wv->free_list;
- wv->free_list = 0;
- }
- else
- {
- wv = xmalloc (sizeof *wv);
- malloc_cpt++;
- }
- memset (wv, 0, sizeof (widget_value));
- return wv;
-}
-
-/* This is analogous to free. It frees only what was allocated
- by malloc_widget_value, and no substructures. */
-
-void
-free_widget_value (widget_value *wv)
-{
- if (wv->free_list)
- emacs_abort ();
-
- if (malloc_cpt > 25)
- {
- /* When the number of already allocated cells is too big,
- We free it. */
- xfree (wv);
- malloc_cpt--;
- }
- else
- {
- wv->free_list = widget_value_free_list;
- widget_value_free_list = wv;
- }
-}
-
/* Create and return the cursor to be used for popup menus and
scroll bars on display DPY. */
&& err->code == G_CONVERT_ERROR_ILLEGAL_SEQUENCE)
{
memcpy (up, p, bytes_written);
- sprintf (up + bytes_written, "\\%03o", p[bytes_written]);
- up += bytes_written+4;
- p += bytes_written+1;
+ up += bytes_written;
+ up += sprintf (up, "\\%03o", p[bytes_written]);
+ p += bytes_written + 1;
g_error_free (err);
err = NULL;
}
if (cp)
{
- strcat (utf8_str, cp);
+ strcpy (up, cp);
g_free (cp);
}
if (err)
GtkStyleContext *gsty
= gtk_widget_get_style_context (FRAME_GTK_OUTER_WIDGET (f));
GdkRGBA col;
- char buf[sizeof "rgbi://" + 3 * (DBL_MAX_10_EXP + sizeof "-1.000000" - 1)];
+ char buf[sizeof "rgb://rrrr/gggg/bbbb"];
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);
+ sprintf (buf, "rgb:%04x/%04x/%04x",
+ (int)(col.red * 65535),
+ (int)(col.green * 65535),
+ (int)(col.blue * 65535));
success_p = (XParseColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
buf, color)
!= 0);
/* Clear under internal border if any. As we use a mix of Gtk+ and X calls
and use a GtkFixed widget, this doesn't happen automatically. */
-static void
+void
xg_clear_under_internal_border (struct frame *f)
{
if (FRAME_INTERNAL_BORDER_WIDTH (f) > 0)
{
GtkWidget *wfixed = f->output_data.x->edit_widget;
+
gtk_widget_queue_draw (wfixed);
gdk_window_process_all_updates ();
- x_clear_area (FRAME_X_DISPLAY (f),
- FRAME_X_WINDOW (f),
- 0, 0,
- FRAME_PIXEL_WIDTH (f),
- FRAME_INTERNAL_BORDER_WIDTH (f), 0);
- x_clear_area (FRAME_X_DISPLAY (f),
- FRAME_X_WINDOW (f),
- 0, 0,
- FRAME_INTERNAL_BORDER_WIDTH (f),
- FRAME_PIXEL_HEIGHT (f), 0);
- x_clear_area (FRAME_X_DISPLAY (f),
- FRAME_X_WINDOW (f),
- 0, FRAME_PIXEL_HEIGHT (f) - FRAME_INTERNAL_BORDER_WIDTH (f),
- FRAME_PIXEL_WIDTH (f),
- FRAME_INTERNAL_BORDER_WIDTH (f), 0);
- x_clear_area (FRAME_X_DISPLAY (f),
- FRAME_X_WINDOW (f),
- FRAME_PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH (f),
- 0,
- FRAME_INTERNAL_BORDER_WIDTH (f),
- FRAME_PIXEL_HEIGHT (f), 0);
+
+ x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), 0, 0,
+ FRAME_PIXEL_WIDTH (f), FRAME_INTERNAL_BORDER_WIDTH (f));
+
+ x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), 0, 0,
+ FRAME_INTERNAL_BORDER_WIDTH (f), FRAME_PIXEL_HEIGHT (f));
+
+ x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), 0,
+ FRAME_PIXEL_HEIGHT (f) - FRAME_INTERNAL_BORDER_WIDTH (f),
+ FRAME_PIXEL_WIDTH (f), FRAME_INTERNAL_BORDER_WIDTH (f));
+
+ x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ FRAME_PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH (f),
+ 0, FRAME_INTERNAL_BORDER_WIDTH (f), FRAME_PIXEL_HEIGHT (f));
}
}
void
xg_frame_resized (struct frame *f, int pixelwidth, int pixelheight)
{
- int rows, columns;
+ int width, height;
if (pixelwidth == -1 && pixelheight == -1)
{
}
- rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, pixelheight);
- columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, pixelwidth);
+ width = FRAME_PIXEL_TO_TEXT_WIDTH (f, pixelwidth);
+ height = FRAME_PIXEL_TO_TEXT_HEIGHT (f, pixelheight);
- if (columns != FRAME_COLS (f)
- || rows != FRAME_LINES (f)
+ if (width != FRAME_TEXT_WIDTH (f)
+ || height != FRAME_TEXT_HEIGHT (f)
|| pixelwidth != FRAME_PIXEL_WIDTH (f)
|| pixelheight != FRAME_PIXEL_HEIGHT (f))
{
FRAME_PIXEL_HEIGHT (f) = pixelheight;
xg_clear_under_internal_border (f);
- change_frame_size (f, rows, columns, 0, 1, 0);
+ change_frame_size (f, width, height, 0, 1, 0, 1);
SET_FRAME_GARBAGED (f);
cancel_mouse_face (f);
+
+ do_pending_window_change (0);
}
}
COLUMNS/ROWS is the size the edit area shall have after the resize. */
void
-xg_frame_set_char_size (struct frame *f, int cols, int rows)
+xg_frame_set_char_size (struct frame *f, int width, int height)
{
- int pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows)
- + FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f);
- int pixelwidth;
+ int pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
+ int pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height);
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
- frame's character width which is bad for vertically split
- windows. */
- f->scroll_bar_actual_width
- = FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f);
-
- compute_fringe_widths (f, 0);
-
- /* 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)
- + FRAME_TOOLBAR_WIDTH (f);
-
-
/* Do this before resize, as we don't know yet if we will be resized. */
xg_clear_under_internal_border (f);
/* Must resize our top level widget. Font size may have changed,
but not rows/cols. */
gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
- pixelwidth, pixelheight);
+ pixelwidth + FRAME_TOOLBAR_WIDTH (f),
+ pixelheight + FRAME_TOOLBAR_HEIGHT (f)
+ + FRAME_MENUBAR_HEIGHT (f));
x_wm_set_size_hint (f, 0, 0);
SET_FRAME_GARBAGED (f);
x_wait_for_event (f, ConfigureNotify);
}
else
- {
- change_frame_size (f, rows, cols, 0, 1, 0);
- FRAME_PIXEL_WIDTH (f) = pixelwidth;
- FRAME_PIXEL_HEIGHT (f) = pixelheight;
- }
+ adjust_frame_size (f, -1, -1, 5, 0);
}
/* Handle height/width changes (i.e. add/remove/move menu/toolbar).
/* Set the background of widget W to PIXEL. */
static void
-xg_set_widget_bg (struct frame *f, GtkWidget *w, long unsigned int pixel)
+xg_set_widget_bg (struct frame *f, GtkWidget *w, unsigned long pixel)
{
#ifdef HAVE_GTK3
GdkRGBA bg;
kbd_buffer_store_event (&event);
update_theme_scrollbar_width ();
+ update_theme_scrollbar_height ();
/* If scroll bar width changed, we need set the new size on all frames
on this display. */
&& FRAME_X_DISPLAY (f) == dpy)
{
x_set_scroll_bar_default_width (f);
- xg_frame_set_char_size (f, FRAME_COLS (f), FRAME_LINES (f));
+ x_set_scroll_bar_default_height (f);
+ xg_frame_set_char_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f));
}
}
}
int base_width, base_height;
int min_rows = 0, min_cols = 0;
int win_gravity = f->win_gravity;
+ Lisp_Object fs_state, frame;
/* Don't set size hints during initialization; that apparently leads
to a race condition. See the thread at
if (NILP (Vafter_init_time) || !FRAME_GTK_OUTER_WIDGET (f))
return;
+ XSETFRAME (frame, f);
+ fs_state = Fframe_parameter (frame, Qfullscreen);
+ if (EQ (fs_state, Qmaximized) || EQ (fs_state, Qfullboth))
+ {
+ /* Don't set hints when maximized or fullscreen. Apparently KWin and
+ Gtk3 don't get along and the frame shrinks (!).
+ */
+ return;
+ }
+
if (flags)
{
memset (&size_hints, 0, sizeof (size_hints));
hint_flags = f->output_data.x->hint_flags;
hint_flags |= GDK_HINT_RESIZE_INC | GDK_HINT_MIN_SIZE;
- size_hints.width_inc = FRAME_COLUMN_WIDTH (f);
- size_hints.height_inc = FRAME_LINE_HEIGHT (f);
+ size_hints.width_inc = frame_resize_pixelwise ? 1 : FRAME_COLUMN_WIDTH (f);
+ size_hints.height_inc = frame_resize_pixelwise ? 1 : FRAME_LINE_HEIGHT (f);
hint_flags |= GDK_HINT_BASE_SIZE;
/* Use one row/col here so base_height/width does not become zero.
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_cols > 0) --min_cols; /* We used one col in base_width = ... 1); */
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;
- size_hints.min_width = base_width + min_cols * size_hints.width_inc;
- size_hints.min_height = base_height + min_rows * size_hints.height_inc;
+ size_hints.min_width = base_width + min_cols * FRAME_COLUMN_WIDTH (f);
+ size_hints.min_height = base_height + min_rows * FRAME_LINE_HEIGHT (f);
/* These currently have a one to one mapping with the X values, but I
don't think we should rely on that. */
BG is the pixel value to change to. */
void
-xg_set_background_color (struct frame *f, long unsigned int bg)
+xg_set_background_color (struct frame *f, unsigned long bg)
{
if (FRAME_GTK_WIDGET (f))
{
gtk_box_set_spacing (wvbox, req.height);
if (item->value && strlen (item->value) > 0)
button_spacing = 2*req.width/strlen (item->value);
+ if (button_spacing < 10) button_spacing = 10;
}
else
{
{
if (make_two_rows)
cur_box = GTK_BOX (whbox_down);
- else
- gtk_box_pack_start (cur_box,
- gtk_label_new (""),
- TRUE, TRUE,
- button_spacing);
}
}
xg_maybe_add_timer (gpointer data)
{
struct xg_dialog_data *dd = data;
- EMACS_TIME next_time = timer_check ();
+ struct timespec next_time = timer_check ();
dd->timerid = 0;
- if (EMACS_TIME_VALID_P (next_time))
+ if (timespec_valid_p (next_time))
{
- 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;
+ time_t s = next_time.tv_sec;
+ int per_ms = TIMESPEC_RESOLUTION / 1000;
+ int ms = (next_time.tv_nsec + per_ms - 1) / per_ms;
if (s <= ((guint) -1 - ms) / 1000)
dd->timerid = g_timeout_add (s * 1000 + ms, xg_maybe_add_timer, dd);
}
static char *x_last_font_name;
-extern Lisp_Object Qxft;
/* Pop up a GTK font selector and return the name of the font the user
selects, as a C string. The returned font name follows GTK's own
font = Ffont_spec (8, args);
pango_font_description_free (desc);
- xfree (x_last_font_name);
- x_last_font_name = xstrdup (name);
+ dupstring (&x_last_font_name, name);
}
#else /* Use old font selector, which just returns the font name. */
/* Return true if there are detached menus. */
bool
-xg_have_tear_offs (void)
+xg_have_tear_offs (struct frame *f)
{
- return xg_detached_menus > 0;
+ /* If the frame's menubar height is zero, the menu bar is probably
+ being redirected outside the window to some kind of global menu;
+ this situation is the moral equivalent of a tear-off. */
+ return FRAME_MENUBAR_HEIGHT (f) == 0 || xg_detached_menus > 0;
}
/* Callback invoked when a detached menu window is removed. Here we
}
#else /* ! HAVE_GTK_TEAROFF_MENU_ITEM_NEW */
bool
-xg_have_tear_offs (void)
+xg_have_tear_offs (struct frame *f)
{
- return false;
+ return FRAME_MENUBAR_HEIGHT (f) == 0;
}
#endif /* ! HAVE_GTK_TEAROFF_MENU_ITEM_NEW */
{
/* Must realize so the GdkWindow inside the widget is created. */
gtk_widget_realize (w);
- xg_set_cursor (w, FRAME_X_DISPLAY_INFO (f)->xg_cursor);
+ xg_set_cursor (w, FRAME_DISPLAY_INFO (f)->xg_cursor);
}
}
else
char *utf8_label = get_utf8_string (val->name);
GtkWidget *submenu = gtk_menu_item_get_submenu (witem);
+ /* GTK menu items don't notice when their labels have been
+ changed from underneath them, so we have to explicitly
+ use g_object_notify to tell listeners (e.g., a GMenuModel
+ bridge that might be loaded) that the item's label has
+ changed. */
gtk_label_set_text (wlabel, utf8_label);
+ g_object_notify (G_OBJECT (witem), "label");
#ifdef HAVE_GTK_TEAROFF_MENU_ITEM_NEW
/* If this item has a submenu that has been detached, change
select_cb, deactivate_cb,
highlight_cb,
0, 0, 0, 0, cl_data, 0);
+
gtk_widget_set_name (w, MENU_ITEM_NAME);
gtk_menu_shell_insert (GTK_MENU_SHELL (menubar), w, pos);
gtk_menu_item_set_submenu (GTK_MENU_ITEM (w), submenu);
const char *old_label = 0;
const char *old_key = 0;
xg_menu_item_cb_data *cb_data;
+ bool label_changed = false;
wchild = XG_BIN_CHILD (w);
utf8_label = get_utf8_string (val->name);
}
}
-
if (wkey) old_key = gtk_label_get_label (wkey);
if (wlbl) old_label = gtk_label_get_label (wlbl);
if (wkey && utf8_key && (! old_key || strcmp (utf8_key, old_key) != 0))
- gtk_label_set_text (wkey, utf8_key);
+ {
+ label_changed = true;
+ gtk_label_set_text (wkey, utf8_key);
+ }
if (! old_label || strcmp (utf8_label, old_label) != 0)
- gtk_label_set_text (wlbl, utf8_label);
+ {
+ label_changed = true;
+ gtk_label_set_text (wlbl, utf8_label);
+ }
if (utf8_key) g_free (utf8_key);
if (utf8_label) g_free (utf8_label);
cb_data->select_id = 0;
}
}
+
+ if (label_changed) /* See comment in xg_update_menubar. */
+ g_object_notify (G_OBJECT (w), "label");
}
/* Update the toggle menu item W so it corresponds to VAL. */
gtk_widget_show_all (x->menubar_widget);
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;
}
bool
-xg_event_is_for_menubar (struct frame *f, XEvent *event)
+xg_event_is_for_menubar (struct frame *f, const XEvent *event)
{
struct x_output *x = f->output_data.x;
GList *iter;
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.y < FRAME_MENUBAR_HEIGHT (f)
&& event->xbutton.same_screen))
return 0;
bool xg_ignore_gtk_scrollbar;
-/* The width of the scroll bar for the current theme. */
-
+/* Width and height of scroll bars for the current theme. */
static int scroll_bar_width_for_theme;
+static int scroll_bar_height_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
scroll_bar_width_for_theme = w;
}
+static void
+update_theme_scrollbar_height (void)
+{
+#ifdef HAVE_GTK3
+ GtkAdjustment *hadj;
+#else
+ GtkObject *hadj;
+#endif
+ GtkWidget *wscroll;
+ int w = 0, b = 0;
+
+ hadj = gtk_adjustment_new (YG_SB_MIN, YG_SB_MIN, YG_SB_MAX, 0.1, 0.1, 0.1);
+ wscroll = gtk_scrollbar_new (GTK_ORIENTATION_HORIZONTAL, GTK_ADJUSTMENT (hadj));
+ 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 < 12) w = 12;
+ scroll_bar_height_for_theme = w;
+}
+
int
xg_get_default_scrollbar_width (void)
{
return scroll_bar_width_for_theme;
}
+int
+xg_get_default_scrollbar_height (void)
+{
+ /* Apparently there's no default height for themes. */
+ 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. */
/* Set the cursor to an arrow. */
- xg_set_cursor (webox, FRAME_X_DISPLAY_INFO (f)->xg_cursor);
+ xg_set_cursor (webox, FRAME_DISPLAY_INFO (f)->xg_cursor);
+
+ bar->x_window = scroll_id;
+ bar->horizontal = 0;
+}
+
+/* Create a horizontal scroll bar widget for frame F. Store the scroll
+ bar in BAR. SCROLL_CALLBACK is the callback to invoke when the value
+ of the bar changes. END_CALLBACK is the callback to invoke when
+ scrolling ends. SCROLL_BAR_NAME is the name we use for the scroll
+ bar. Can be used to set resources for the widget. */
+
+void
+xg_create_horizontal_scroll_bar (struct frame *f,
+ struct scroll_bar *bar,
+ GCallback scroll_callback,
+ GCallback end_callback,
+ const char *scroll_bar_name)
+{
+ GtkWidget *wscroll;
+ GtkWidget *webox;
+ intptr_t scroll_id;
+#ifdef HAVE_GTK3
+ GtkAdjustment *hadj;
+#else
+ GtkObject *hadj;
+#endif
+
+ /* Page, step increment values are not so important here, they
+ will be corrected in x_set_toolkit_scroll_bar_thumb. */
+ hadj = gtk_adjustment_new (YG_SB_MIN, YG_SB_MIN, YG_SB_MAX,
+ 0.1, 0.1, 0.1);
+
+ wscroll = gtk_scrollbar_new (GTK_ORIENTATION_HORIZONTAL, GTK_ADJUSTMENT (hadj));
+ 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);
+
+ g_signal_connect (G_OBJECT (wscroll),
+ "destroy",
+ G_CALLBACK (xg_gtk_scroll_destroy),
+ (gpointer) scroll_id);
+ g_signal_connect (G_OBJECT (wscroll),
+ "change-value",
+ scroll_callback,
+ (gpointer) bar);
+ g_signal_connect (G_OBJECT (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
+ also, which causes flicker. Put an event box between the edit widget
+ and the scroll bar, so the scroll bar instead draws itself on the
+ event box window. */
+ gtk_fixed_put (GTK_FIXED (f->output_data.x->edit_widget), webox, -1, -1);
+ gtk_container_add (GTK_CONTAINER (webox), wscroll);
+
+
+ /* Set the cursor to an arrow. */
+ xg_set_cursor (webox, FRAME_DISPLAY_INFO (f)->xg_cursor);
bar->x_window = scroll_id;
+ bar->horizontal = 1;
}
/* Remove the scroll bar represented by SCROLLBAR_ID from the frame F. */
gtk_widget_queue_draw (wfixed);
gdk_window_process_all_updates ();
if (oldx != -1 && oldw > 0 && oldh > 0)
+ /* Clear under old scroll bar position. This must be done after
+ the gtk_widget_queue_draw and gdk_window_process_all_updates
+ above. */
+ x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ oldx, oldy, oldw, oldh);
+
+ /* 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);
+ }
+}
+
+
+/* Update the position of the horizontal scroll bar represented by SCROLLBAR_ID
+ in frame F.
+ TOP/LEFT are the new pixel positions where the bar shall appear.
+ WIDTH, HEIGHT is the size in pixels the bar shall have. */
+
+void
+xg_update_horizontal_scrollbar_pos (struct frame *f,
+ ptrdiff_t scrollbar_id,
+ int top,
+ int left,
+ int width,
+ int height)
+{
+
+ GtkWidget *wscroll = xg_get_widget_from_map (scrollbar_id);
+
+ if (wscroll)
+ {
+ GtkWidget *wfixed = f->output_data.x->edit_widget;
+ GtkWidget *wparent = gtk_widget_get_parent (wscroll);
+ gint msl;
+
+ /* Clear out old position. */
+ int oldx = -1, oldy = -1, oldw, oldh;
+ if (gtk_widget_get_parent (wparent) == wfixed)
{
- /* Clear under old scroll bar position. This must be done after
- the gtk_widget_queue_draw and gdk_window_process_all_updates
- above. */
- x_clear_area (FRAME_X_DISPLAY (f),
- FRAME_X_WINDOW (f),
- oldx, oldy, oldw, oldh, 0);
+ gtk_container_child_get (GTK_CONTAINER (wfixed), wparent,
+ "x", &oldx, "y", &oldy, NULL);
+ gtk_widget_get_size_request (wscroll, &oldw, &oldh);
}
+ /* Move and resize to new values. */
+ gtk_fixed_move (GTK_FIXED (wfixed), wparent, left, top);
+ gtk_widget_style_get (wscroll, "min-slider-length", &msl, NULL);
+ if (msl > width)
+ {
+ /* No room. Hide scroll bar as some themes output a warning if
+ the width is less than the min size. */
+ gtk_widget_hide (wparent);
+ gtk_widget_hide (wscroll);
+ }
+ else
+ {
+ gtk_widget_show_all (wparent);
+ gtk_widget_set_size_request (wscroll, width, height);
+ }
+ gtk_widget_queue_draw (wfixed);
+ gdk_window_process_all_updates ();
+ if (oldx != -1 && oldw > 0 && oldh > 0)
+ /* Clear under old scroll bar position. This must be done after
+ the gtk_widget_queue_draw and gdk_window_process_all_updates
+ above. */
+ x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ oldx, oldy, oldw, oldh);
+
/* 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. */
}
}
+
/* Get the current value of the range, truncated to an integer. */
static int
struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
- if (wscroll && NILP (bar->dragging))
+ if (wscroll && bar->dragging == -1)
{
GtkAdjustment *adj;
gdouble shown;
}
}
+/* Set the thumb size and position of horizontal scroll bar BAR. We are
+ currently displaying PORTION out of a whole WHOLE, and our position
+ POSITION. */
+void
+xg_set_toolkit_horizontal_scroll_bar_thumb (struct scroll_bar *bar,
+ int portion,
+ int position,
+ int whole)
+{
+ GtkWidget *wscroll = xg_get_widget_from_map (bar->x_window);
+
+ if (wscroll && bar->dragging == -1)
+ {
+ GtkAdjustment *adj;
+ int lower = 0;
+ int upper = max (whole - 1, 0);
+ int pagesize = min (upper, max (portion, 0));
+ int value = max (0, min (position, upper - pagesize));
+ /* These should be set to something more <portion, whole>
+ related. */
+ int page_increment = 4;
+ int step_increment = 1;
+
+ block_input ();
+ adj = gtk_range_get_adjustment (GTK_RANGE (wscroll));
+#if GTK_CHECK_VERSION (2, 3, 16)
+ gtk_adjustment_configure (adj, (gdouble) value, (gdouble) lower,
+ (gdouble) upper, (gdouble) step_increment,
+ (gdouble) page_increment, (gdouble) pagesize);
+#else
+ gtk_adjustment_set_lower (adj, (gdouble) lower);
+ gtk_adjustment_set_upper (adj, (gdouble) upper);
+ gtk_adjustment_set_page_size (adj, (gdouble) pagesize);
+ gtk_adjustment_set_value (adj, (gdouble) value);
+ gtk_adjustment_set_page_increment (adj, (gdouble) page_increment);
+ gtk_adjustment_set_step_increment (adj, (gdouble) step_increment);
+#endif
+ gtk_adjustment_changed (adj);
+ unblock_input ();
+ }
+}
+
/* Return true if EVENT is for a scroll bar in frame F.
When the same X window is used for several Gtk+ widgets, we cannot
say for sure based on the X window alone if an event is for the
frame. This function does additional checks. */
bool
-xg_event_is_for_scrollbar (struct frame *f, XEvent *event)
+xg_event_is_for_scrollbar (struct frame *f, const XEvent *event)
{
bool retval = 0;
/* Convert between the modifier bits GDK uses and the modifier bits
Emacs uses. This assumes GDK and X masks are the same, which they are when
this is written. */
- event.modifiers = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f), mod);
+ event.modifiers = x_x_to_emacs_modifiers (FRAME_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);
+ /* Return focus to the frame after we have clicked on a detached
+ tool bar button. */
+ x_focus_frame (f);
}
/* Callback function invoked when a tool bar item is pressed in a detached
size hints if tool bar size changes. Seen on Fedora 18 at least. */
struct frame *f = user_data;
if (xg_update_tool_bar_sizes (f))
- x_wm_set_size_hint (f, 0, 0);
+ xg_height_or_width_changed (f);
}
/* Create a tool bar for frame F. */
if (f->n_tool_bar_items != 0)
{
if (! x->toolbar_is_packed)
- xg_pack_tool_bar (f, f->tool_bar_position);
+ xg_pack_tool_bar (f, FRAME_TOOL_BAR_POSITION (f));
gtk_widget_show_all (TOOLBAR_TOP_WIDGET (x));
if (xg_update_tool_bar_sizes (f))
xg_height_or_width_changed (f);
(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". */
+ so we set it to "" which in means "no key". */
gtk_settings_set_string_property (settings,
"gtk-menu-bar-accel",
- "VoidSymbol",
+ "",
EMACS_CLASS);
/* Make GTK text input widgets use Emacs style keybindings. This is
gtk_binding_entry_add_signal (binding_set, GDK_KEY_g, GDK_CONTROL_MASK,
"cancel", 0);
update_theme_scrollbar_width ();
+ update_theme_scrollbar_height ();
#ifdef HAVE_FREETYPE
x_last_font_name = NULL;