X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/5d59504a3198da6173a8cc1d4125a76b657b4538..259a0b6d3bc6ffe0d5d24368e415fa46f439a844:/src/gtkutil.c diff --git a/src/gtkutil.c b/src/gtkutil.c index 752cc8ec60..595e6e0bb6 100644 --- a/src/gtkutil.c +++ b/src/gtkutil.c @@ -115,6 +115,7 @@ along with GNU Emacs. If not, see . */ #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 @@ -507,16 +508,16 @@ get_utf8_string (const char *str) && 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) @@ -821,7 +822,7 @@ xg_set_geometry (struct frame *f) /* 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) @@ -883,6 +884,8 @@ xg_frame_resized (struct frame *f, int pixelwidth, int pixelheight) change_frame_size (f, width, height, 0, 1, 0, 1); SET_FRAME_GARBAGED (f); cancel_mouse_face (f); + + do_pending_window_change (0); } } @@ -927,7 +930,7 @@ xg_frame_set_char_size (struct frame *f, int width, int height) x_wait_for_event (f, ConfigureNotify); } else - change_frame_size (f, width, height, 0, 1, 0, 1); + adjust_frame_size (f, -1, -1, 5, 0); } /* Handle height/width changes (i.e. add/remove/move menu/toolbar). @@ -1017,6 +1020,7 @@ style_changed_cb (GObject *go, 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. */ @@ -1031,6 +1035,7 @@ style_changed_cb (GObject *go, && FRAME_X_DISPLAY (f) == dpy) { x_set_scroll_bar_default_width (f); + x_set_scroll_bar_default_height (f); xg_frame_set_char_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f)); } } @@ -1314,13 +1319,12 @@ x_wm_set_size_hint (struct frame *f, long int flags, bool user_position) base_height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, 1) + FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f); - check_frame_size (f, &min_cols, &min_rows, 0); 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 * FRAME_COLUMN_WIDTH (f);; + 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 @@ -1537,6 +1541,7 @@ create_dialog (widget_value *wv, 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 { @@ -1553,11 +1558,6 @@ create_dialog (widget_value *wv, { if (make_two_rows) cur_box = GTK_BOX (whbox_down); - else - gtk_box_pack_start (cur_box, - gtk_label_new (""), - TRUE, TRUE, - button_spacing); } } @@ -3374,7 +3374,7 @@ xg_event_is_for_menubar (struct frame *f, const XEvent *event) 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; @@ -3419,9 +3419,9 @@ xg_event_is_for_menubar (struct frame *f, const XEvent *event) 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 @@ -3524,12 +3524,41 @@ update_theme_scrollbar_width (void) 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. */ @@ -3628,6 +3657,74 @@ xg_create_scroll_bar (struct frame *f, 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. */ @@ -3710,6 +3807,73 @@ xg_update_scrollbar_pos (struct frame *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) + { + 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. */ + + x_sync (f); + SET_FRAME_GARBAGED (f); + cancel_mouse_face (f); + } +} + + /* Get the current value of the range, truncated to an integer. */ static int @@ -3804,6 +3968,48 @@ xg_set_toolkit_scroll_bar_thumb (struct scroll_bar *bar, } } +/* 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 + 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 @@ -5010,6 +5216,7 @@ xg_initialize (void) 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;