From: Jan Djärv Date: Sun, 23 Mar 2003 00:59:23 +0000 (+0000) Subject: Finally (?) fix flicker in scroll bar. X-Git-Tag: ttn-vms-21-2-B4~10780 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=7863d62580ba300daabda98db9f908ada25fd43b;p=emacs.git Finally (?) fix flicker in scroll bar. --- diff --git a/src/ChangeLog b/src/ChangeLog index 0171759825a..bad3aee2925 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,24 @@ +2003-03-23 Jan Dj,Ad(Brv + + * gtkutil.h: Take two more arguments to xg_update_scrollbar_pos. + (XG_SB_RANGE): New define. + + * gtkutil.c (xg_fixed_handle_expose): New function. + (xg_create_frame_widgets): Call xg_fixed_handle_expose for + expose events. + (xg_update_scrollbar_pos): Take two more arguments, left and width + of scroll bar including borders. + Clear left and right part outside scroll bar separately as some + themes have bars that are not an even number of pixels. + Don't set reallocate_redraws, don't call + gdk_window_process_all_updates. + (xg_set_toolkit_scroll_bar_thumb): Upper value is fixed, + so no need to change it. Calculate size and value with XG_SB_RANGE. + + * xterm.c (x_scroll_bar_create, XTset_vertical_scroll_bar): Pass + left and width of scroll bar including borders to + xg_update_scrollbar_pos. + 2003-03-22 Thien-Thi Nguyen * Makefile.in: Make sure space precedes end-of-line backslashes. diff --git a/src/gtkutil.c b/src/gtkutil.c index 61e79749354..dc054426d04 100644 --- a/src/gtkutil.c +++ b/src/gtkutil.c @@ -151,7 +151,7 @@ xg_process_timeouts (timer) /* Start the xg_timer with an interval of 0.1 seconds, if not already started. xg_process_timeouts is called when the timer expires. The timer - stared is continuous, i.e. runs until xg_stop_timer is called. */ + started is continuous, i.e. runs until xg_stop_timer is called. */ static void xg_start_timer () { @@ -412,6 +412,54 @@ xg_pix_to_gcolor (w, pixel, c) gdk_colormap_query_color (map, pixel, c); } +/* Turning off double buffering for our GtkFixed widget has the side + effect of turning it off also for its children (scroll bars). + But we want those to be double buffered to not flicker so handle + expose manually here. + WIDGET is the GtkFixed widget that gets exposed. + EVENT is the expose event. + USER_DATA is unused. + + Return TRUE to tell GTK that this expose event has been fully handeled + and that GTK shall do nothing more with it. */ +static gboolean +xg_fixed_handle_expose(GtkWidget *widget, + GdkEventExpose *event, + gpointer user_data) +{ + GList *iter; + + for (iter = GTK_FIXED (widget)->children; iter; iter = g_list_next (iter)) + { + GtkFixedChild *child_data = (GtkFixedChild *) iter->data; + GtkWidget *child = child_data->widget; + GdkWindow *window = child->window; + GdkRegion *region = gtk_widget_region_intersect (child, event->region); + + if (! gdk_region_empty (region)) + { + GdkEvent child_event; + child_event.expose = *event; + child_event.expose.region = region; + + /* Turn on double buffering, i.e. draw to an off screen area. */ + gdk_window_begin_paint_region (window, region); + + /* Tell child to redraw itself. */ + gdk_region_get_clipbox (region, &child_event.expose.area); + gtk_widget_send_expose (child, &child_event); + gdk_window_process_updates (window, TRUE); + + /* Copy off screen area to the window. */ + gdk_window_end_paint (window); + } + + gdk_region_destroy (region); + } + + return TRUE; +} + /* Create and set up the GTK widgets for frame F. Return 0 if creation failed, non-zero otherwise. */ int @@ -478,9 +526,19 @@ xg_create_frame_widgets (f) if (FRAME_EXTERNAL_TOOL_BAR (f) && FRAME_TOOLBAR_HEIGHT (f) == 0) FRAME_TOOLBAR_HEIGHT (f) = 34; - gtk_widget_set_double_buffered (wvbox, FALSE); + + /* 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 + will make the widget blank, and then Emacs redraws it. This flickers + a lot, so we turn off double buffering. */ gtk_widget_set_double_buffered (wfixed, FALSE); - gtk_widget_set_double_buffered (wtop, FALSE); + + /* Turning off double buffering above has the side effect of turning + it off also for its children (scroll bars). But we want those + to be double buffered to not flicker so handle expose manually. */ + g_signal_connect (G_OBJECT (wfixed), "expose-event", + G_CALLBACK (xg_fixed_handle_expose), 0); /* GTK documents says use gtk_window_set_resizable. But then a user can't shrink the window from its starting size. */ @@ -1159,6 +1217,7 @@ make_widget_for_menu_item (utf8_label, utf8_key) gtk_widget_set_name (wlbl, MENU_ITEM_NAME); gtk_widget_set_name (wkey, MENU_ITEM_NAME); + gtk_widget_set_name (wbox, MENU_ITEM_NAME); return wbox; } @@ -2497,7 +2556,8 @@ xg_find_top_left_in_fixed (w, wfixed, left, top) 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_scrollbar_pos (f, scrollbar_id, top, left, width, height) +xg_update_scrollbar_pos (f, scrollbar_id, top, left, width, height, + real_left, canon_width) FRAME_PTR f; int scrollbar_id; int top; @@ -2507,19 +2567,18 @@ xg_update_scrollbar_pos (f, scrollbar_id, top, left, width, height) { GtkWidget *wscroll = xg_get_widget_from_map (scrollbar_id); - + if (wscroll) { GtkWidget *wfixed = f->output_data.x->edit_widget; int gheight = max (height, 1); - int canon_width = FRAME_SCROLL_BAR_COLS (f) * CANON_X_UNIT (f); int winextra = canon_width > width ? (canon_width - width) / 2 : 0; int bottom = top + gheight; gint slider_width; int oldtop, oldleft, oldbottom; GtkRequisition req; - + /* Get old values. */ xg_find_top_left_in_fixed (wscroll, wfixed, &oldleft, &oldtop); gtk_widget_size_request (wscroll, &req); @@ -2547,49 +2606,57 @@ xg_update_scrollbar_pos (f, scrollbar_id, top, left, width, height) the remains of the mode line can be seen in these blank spaces. So we must clear them explicitly. GTK scroll bars should do that, but they don't. - Also, the scroll bar canonical width may be wider than the width - passed in here. */ + Also, the canonical width may be wider than the width for the + scroll bar so that there is some space (typically 1 pixel) between + the scroll bar and the edge of the window and between the scroll + bar and the fringe. */ if (oldtop != -1 && oldleft != -1) { - int gtkextra; - int xl, xr, wblank; + int gtkextral, gtkextrah; + int xl, xr, wbl, wbr; int bottomdiff, topdiff; gtk_widget_style_get (wscroll, "slider_width", &slider_width, NULL); - gtkextra = width > slider_width ? (width - slider_width) / 2 : 0; - - xl = left - winextra; - wblank = gtkextra + winextra; - xr = left + gtkextra + slider_width; + gtkextral = width > slider_width ? (width - slider_width) / 2 : 0; + gtkextrah = gtkextral ? (width - slider_width - gtkextral) : 0; + + xl = real_left; + wbl = gtkextral + winextra; + wbr = gtkextrah + winextra; + xr = left + gtkextral + slider_width; bottomdiff = abs (oldbottom - bottom); topdiff = abs (oldtop - top); + if (oldleft != left) + { + gdk_window_clear_area (wfixed->window, xl, top, wbl, gheight); + gdk_window_clear_area (wfixed->window, xr, top, wbr, gheight); + } + if (oldtop > top) { - gdk_window_clear_area (wfixed->window, xl, top, wblank, topdiff); - gdk_window_clear_area (wfixed->window, xr, top, wblank, topdiff); + gdk_window_clear_area (wfixed->window, xl, top, wbl, topdiff); + gdk_window_clear_area (wfixed->window, xr, top, wbr, topdiff); } else if (oldtop < top) { - gdk_window_clear_area (wfixed->window, xl, oldtop, wblank, - topdiff); - gdk_window_clear_area (wfixed->window, xr, oldtop, wblank, - topdiff); + gdk_window_clear_area (wfixed->window, xl, oldtop, wbl, topdiff); + gdk_window_clear_area (wfixed->window, xr, oldtop, wbr, topdiff); } if (oldbottom > bottom) { - gdk_window_clear_area (wfixed->window, xl, bottom, wblank, + gdk_window_clear_area (wfixed->window, xl, bottom, wbl, bottomdiff); - gdk_window_clear_area (wfixed->window, xr, bottom, wblank, + gdk_window_clear_area (wfixed->window, xr, bottom, wbr, bottomdiff); } else if (oldbottom < bottom) { - gdk_window_clear_area (wfixed->window, xl, oldbottom, wblank, + gdk_window_clear_area (wfixed->window, xl, oldbottom, wbl, bottomdiff); - gdk_window_clear_area (wfixed->window, xr, oldbottom, wblank, + gdk_window_clear_area (wfixed->window, xr, oldbottom, wbr, bottomdiff); } } @@ -2598,12 +2665,6 @@ xg_update_scrollbar_pos (f, scrollbar_id, top, left, width, height) gtk_fixed_move (GTK_FIXED (wfixed), wscroll, left, top); gtk_widget_set_size_request (wscroll, width, gheight); - gtk_container_set_reallocate_redraws (GTK_CONTAINER (wfixed), TRUE); - - /* Make GTK draw the new sizes. We are not using a pure GTK event - loop so we need to do this. */ - gdk_window_process_all_updates (); - SET_FRAME_GARBAGED (f); cancel_mouse_face (f); } @@ -2620,15 +2681,14 @@ xg_set_toolkit_scroll_bar_thumb (bar, portion, position, whole) FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window))); - BLOCK_INPUT; - if (wscroll && NILP (bar->dragging)) { GtkAdjustment *adj; gdouble shown; gdouble top; int size, value; - int new_upper, new_step; + int new_step; + int changed = 0; adj = gtk_range_get_adjustment (GTK_RANGE (wscroll)); @@ -2644,53 +2704,51 @@ xg_set_toolkit_scroll_bar_thumb (bar, portion, position, whole) top = 0, shown = 1; else { - shown = (gdouble) portion / whole; top = (gdouble) position / whole; + shown = (gdouble) portion / whole; } - size = shown * whole; - size = min (size, whole); + size = shown * XG_SB_RANGE; + size = min (size, XG_SB_RANGE); size = max (size, 1); - value = top * whole; - value = min (value, whole - size); + value = top * XG_SB_RANGE; + value = min (value, XG_SB_MAX - size); value = max (value, XG_SB_MIN); - /* gtk_range_set_value invokes the callback. Set - ignore_gtk_scrollbar to make the callback do nothing */ - xg_ignore_gtk_scrollbar = 1; - - new_upper = max (whole, size); - new_step = portion / max (1, FRAME_HEIGHT (f)); + /* Assume all lines are of equal size. */ + new_step = size / max (1, FRAME_HEIGHT (f)); if ((int) adj->page_size != size - || (int) adj->upper != new_upper || (int) adj->step_increment != new_step) { - adj->page_size = (int) size; - - gtk_range_set_range (GTK_RANGE (wscroll), adj->lower, - (gdouble) new_upper); - - /* Assume all lines are of equal size. */ + adj->page_size = size; + adj->step_increment = new_step; /* Assume a page increment is about 95% of the page size */ - gtk_range_set_increments (GTK_RANGE (wscroll), - portion / max (1, FRAME_HEIGHT (f)), - (int) (0.95*adj->page_size)); - + adj->page_increment = (int) (0.95*adj->page_size); + changed = 1; } - if ((int) gtk_range_get_value (GTK_RANGE (wscroll)) != value) - gtk_range_set_value (GTK_RANGE (wscroll), (gdouble)value); + if (changed || (int) gtk_range_get_value (GTK_RANGE (wscroll)) != value) + { + GtkWidget *wfixed = f->output_data.x->edit_widget; - xg_ignore_gtk_scrollbar = 0; + BLOCK_INPUT; - /* Make GTK draw the new thumb. We are not using a pure GTK event - loop so we need to do this. */ - gdk_window_process_all_updates (); - } + /* gtk_range_set_value invokes the callback. Set + ignore_gtk_scrollbar to make the callback do nothing */ + xg_ignore_gtk_scrollbar = 1; - UNBLOCK_INPUT; + if ((int) gtk_range_get_value (GTK_RANGE (wscroll)) != value) + gtk_range_set_value (GTK_RANGE (wscroll), (gdouble)value); + else if (changed) + gtk_adjustment_changed (adj); + + xg_ignore_gtk_scrollbar = 0; + + UNBLOCK_INPUT; + } + } } @@ -3098,7 +3156,7 @@ update_frame_tool_bar (f) /* Must force out update so changed images gets redrawn. */ gdk_window_process_all_updates (); - + if (icon_list) g_list_free (icon_list); UNBLOCK_INPUT; diff --git a/src/gtkutil.h b/src/gtkutil.h index 2284ff6e113..a53a3fd5bdc 100644 --- a/src/gtkutil.h +++ b/src/gtkutil.h @@ -30,8 +30,9 @@ Boston, MA 02111-1307, USA. */ /* Minimum and maximum values used for GTK scroll bars */ -#define XG_SB_MIN 0 +#define XG_SB_MIN 1 #define XG_SB_MAX 10000000 +#define XG_SB_RANGE (XG_SB_MAX-XG_SB_MIN) /* Key for data that is valid for menus in a frame */ #define XG_FRAME_DATA "emacs_frame" @@ -165,7 +166,9 @@ extern void xg_update_scrollbar_pos P_ ((FRAME_PTR f, int top, int left, int width, - int height)); + int height, + int real_left, + int canon_width)); extern void xg_set_toolkit_scroll_bar_thumb P_ ((struct scroll_bar *bar, int portion, diff --git a/src/xterm.c b/src/xterm.c index c8baf8ffe35..d414271091e 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -4780,7 +4780,9 @@ x_scroll_bar_create (w, top, left, width, height) top, left + VERTICAL_SCROLL_BAR_WIDTH_TRIM, width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2, - max (height, 1)); + max (height, 1), + left, + width); xg_show_scroll_bar (SCROLL_BAR_X_WINDOW (bar)); #else /* not USE_GTK */ Widget scroll_bar = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar); @@ -5030,7 +5032,9 @@ XTset_vertical_scroll_bar (w, portion, whole, position) top, sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM, sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2, - max (height, 1)); + max (height, 1), + left, + width); #else /* not USE_GTK */ /* Since toolkit scroll bars are smaller than the space reserved