emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Addition to emacsbug.el


From: Stefan Monnier
Subject: Re: Addition to emacsbug.el
Date: Wed, 27 Oct 2004 09:27:15 -0400
User-agent: Gnus/5.11 (Gnus v5.11) Emacs/21.3.50 (gnu/linux)

> I'm working on the GTK scroll bars again, trying to get overscrolling to
> work as in the native scroll bars.  But I see that depending on what GTK
> version and what X server version I run on (specifically with DAMAGE
> extension or not), I sometimes get different behaviour.  Therefore I would
> like to have this information inserted by report-emacs-bug.  The GTK version
> is already in emacs-version, so I propose this patch to emacsbug.el:

BTW, with the Xaw3d scrollbars (which had/have the same problem), I've been
using the following trick very happily:
- use the "normal" thumb position and size (the same as was used for the
  non-toolkit scroll bars).
- at the beginning of a thumb-drag, set the thumb size to 0.
- at the end of a thumb-drag reset the thumb-size to its real value.

I find this to be the best solution to the problem: from the code's point of
view, it's clean and simple (much cleaner and simpler than the hacks that
are currently used in xterm.c).  From the user's point of view, it makes
dragging a bit strange at first because the thumb almost disappears under
the mouse cursor, but to make up for it, the actual behavior during dragging
is now flawless and so is the rest of the behavior.
Since we can't have a perfect behavior I find this trade off to be much
better than anything I've seen so far.

And also I suggest to merge xg_set_toolkit_scroll_bar_thumb back into
x_set_toolkit_scroll_bar_thumb.

Here is my current patch to xterm.c (barely tested under Gtk, tho).


        Stefan


*** orig/src/xterm.c
--- mod/src/xterm.c
***************
*** 4019,4030 ****
  
  static Boolean xaw3d_arrow_scroll;
  
- /* Whether the drag scrolling maintains the mouse at the top of the
-    thumb.  If not, resizing the thumb needs to be done more carefully
-    to avoid jerkyness.  */
- 
- static Boolean xaw3d_pick_top;
- 
  extern void set_vertical_scroll_bar P_ ((struct window *));
  
  /* Action hook installed via XtAppAddActionHook when toolkit scroll
--- 4019,4024 ----
***************
*** 4183,4193 ****
  }
  
  
! #ifdef USE_MOTIF
  
! /* Minimum and maximum values used for Motif scroll bars.  */
  
! #define XM_SB_MAX 10000000
  
  
  /* Scroll bar callback for Motif scroll bars.  WIDGET is the scroll
--- 4177,4187 ----
  }
  
  
! /* Maximum size value used for some scroll bars.  */
  
! #define SB_MAX 10000000
  
! #ifdef USE_MOTIF
  
  
  /* Scroll bar callback for Motif scroll bars.  WIDGET is the scroll
***************
*** 4244,4250 ****
        XtVaGetValues (widget, XmNsliderSize, &slider_size, NULL);
        UNBLOCK_INPUT;
  
!       whole = XM_SB_MAX - slider_size;
        portion = min (cs->value, whole);
        part = scroll_bar_handle;
        bar->dragging = make_number (cs->value);
--- 4238,4244 ----
        XtVaGetValues (widget, XmNsliderSize, &slider_size, NULL);
        UNBLOCK_INPUT;
  
!       whole = SB_MAX - slider_size;
        portion = min (cs->value, whole);
        part = scroll_bar_handle;
        bar->dragging = make_number (cs->value);
***************
*** 4263,4271 ****
      }
  }
  
  
- #else /* !USE_MOTIF, i.e. Xaw or GTK */
- #ifdef USE_GTK
  /* Scroll bar callback for GTK scroll bars.  WIDGET is the scroll
     bar widget.  DATA is a pointer to the scroll_bar structure. */
  
--- 4257,4264 ----
      }
  }
  
+ #elif defined USE_GTK
  
  /* Scroll bar callback for GTK scroll bars.  WIDGET is the scroll
     bar widget.  DATA is a pointer to the scroll_bar structure. */
  
***************
*** 4336,4342 ****
      }
  }
  
! #else /* not USE_GTK */
  
  /* Xaw scroll bar callback.  Invoked when the thumb is dragged.
     WIDGET is the scroll bar widget.  CLIENT_DATA is a pointer to the
--- 4329,4335 ----
      }
  }
  
! #else /* not USE_GTK and not USE_MOTIF */
  
  /* Xaw scroll bar callback.  Invoked when the thumb is dragged.
     WIDGET is the scroll bar widget.  CLIENT_DATA is a pointer to the
***************
*** 4350,4376 ****
  {
    struct scroll_bar *bar = (struct scroll_bar *) client_data;
    float top = *(float *) call_data;
!   float shown;
!   int whole, portion, height;
    int part;
  
!   /* Get the size of the thumb, a value between 0 and 1.  */
!   BLOCK_INPUT;
!   XtVaGetValues (widget, XtNshown, &shown, XtNheight, &height, NULL);
!   UNBLOCK_INPUT;
! 
!   whole = 10000000;
!   portion = shown < 1 ? top * whole : 0;
! 
!   if (shown < 1 && (abs (top + shown - 1) < 1.0/height))
!     /* Some derivatives of Xaw refuse to shrink the thumb when you reach
!        the bottom, so we force the scrolling whenever we see that we're
!        too close to the bottom (in x_set_toolkit_scroll_bar_thumb
!        we try to ensure that we always stay two pixels away from the
!        bottom).  */
!     part = scroll_bar_down_arrow;
!   else
!     part = scroll_bar_handle;
  
    window_being_scrolled = bar->window;
    bar->dragging = make_number (portion);
--- 4343,4357 ----
  {
    struct scroll_bar *bar = (struct scroll_bar *) client_data;
    float top = *(float *) call_data;
!   int whole, portion;
    int part;
  
!   whole = SB_MAX;
!   portion = min (SB_MAX * top, whole);
!   part = scroll_bar_handle;
!   /* The thumb can't be resized while dragging and could thus prevent us
!      from reaching the end: let's set it to 0 temporarily.  */
!   XawScrollbarSetThumb (widget, top, 0);
  
    window_being_scrolled = bar->window;
    bar->dragging = make_number (portion);
***************
*** 4419,4426 ****
    x_send_scroll_bar_event (bar->window, part, position, height);
  }
  
! #endif /* not USE_GTK */
! #endif /* not USE_MOTIF */
  
  #define SCROLL_BAR_NAME "verticalScrollBar"
  
--- 4400,4406 ----
    x_send_scroll_bar_event (bar->window, part, position, height);
  }
  
! #endif /* not USE_GTK and not USE_MOTIF */
  
  #define SCROLL_BAR_NAME "verticalScrollBar"
  
***************
*** 4461,4467 ****
    /* Set resources.  Create the widget.  */
    XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
    XtSetArg (av[ac], XmNminimum, 0); ++ac;
!   XtSetArg (av[ac], XmNmaximum, XM_SB_MAX); ++ac;
    XtSetArg (av[ac], XmNorientation, XmVERTICAL); ++ac;
    XtSetArg (av[ac], XmNprocessingDirection, XmMAX_ON_BOTTOM), ++ac;
    XtSetArg (av[ac], XmNincrement, 1); ++ac;
--- 4441,4447 ----
    /* Set resources.  Create the widget.  */
    XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
    XtSetArg (av[ac], XmNminimum, 0); ++ac;
!   XtSetArg (av[ac], XmNmaximum, SB_MAX); ++ac;
    XtSetArg (av[ac], XmNorientation, XmVERTICAL); ++ac;
    XtSetArg (av[ac], XmNprocessingDirection, XmMAX_ON_BOTTOM), ++ac;
    XtSetArg (av[ac], XmNincrement, 1); ++ac;
***************
*** 4593,4600 ****
    {
      char *initial = "";
      char *val = initial;
!     XtVaGetValues (widget, XtNscrollVCursor, (XtPointer) &val,
!                  XtNpickTop, (XtPointer) &xaw3d_pick_top, NULL);
      if (val == initial)
        {       /* ARROW_SCROLL */
        xaw3d_arrow_scroll = True;
--- 4573,4579 ----
    {
      char *initial = "";
      char *val = initial;
!     XtVaGetValues (widget, XtNscrollVCursor, (XtPointer) &val, NULL);
      if (val == initial)
        {       /* ARROW_SCROLL */
        xaw3d_arrow_scroll = True;
***************
*** 4631,4675 ****
  /* Set the thumb size and position of scroll bar BAR.  We are currently
     displaying PORTION out of a whole WHOLE, and our position POSITION.  */
  
- #ifdef USE_GTK
  static void
  x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
       struct scroll_bar *bar;
       int portion, position, whole;
  {
-   xg_set_toolkit_scroll_bar_thumb (bar, portion, position, whole);
- }
- 
- #else /* not USE_GTK */
- static void
- x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
-      struct scroll_bar *bar;
-      int portion, position, whole;
- {
-   struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
-   Widget widget = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar);
    float top, shown;
  
-   BLOCK_INPUT;
- 
- #ifdef USE_MOTIF
- 
-   /* We use an estimate of 30 chars per line rather than the real
-      `portion' value.  This has the disadvantage that the thumb size
-      is not very representative, but it makes our life a lot easier.
-      Otherwise, we have to constantly adjust the thumb size, which
-      we can't always do quickly enough: while dragging, the size of
-      the thumb might prevent the user from dragging the thumb all the
-      way to the end.  but Motif and some versions of Xaw3d don't allow
-      updating the thumb size while dragging.  Also, even if we can update
-      its size, the update will often happen too late.
-      If you don't believe it, check out revision 1.650 of xterm.c to see
-      what hoops we were going through and the still poor behavior we got.  */
-   portion = WINDOW_TOTAL_LINES (XWINDOW (bar->window)) * 30;
-   /* When the thumb is at the bottom, position == whole.
-      So we need to increase `whole' to make space for the thumb.  */
-   whole += portion;
- 
    if (whole <= 0)
      top = 0, shown = 1;
    else
--- 4610,4622 ----
***************
*** 4678,4768 ****
        shown = (float) portion / whole;
      }
  
    if (NILP (bar->dragging))
      {
        int size, value;
  
        /* Slider size.  Must be in the range [1 .. MAX - MIN] where MAX
           is the scroll bar's maximum and MIN is the scroll bar's minimum
         value.  */
!       size = shown * XM_SB_MAX;
!       size = min (size, XM_SB_MAX);
        size = max (size, 1);
  
        /* Position.  Must be in the range [MIN .. MAX - SLIDER_SIZE].  */
!       value = top * XM_SB_MAX;
!       value = min (value, XM_SB_MAX - size);
  
        XmScrollBarSetValues (widget, value, size, 0, 0, False);
!     }
! #else /* !USE_MOTIF i.e. use Xaw */
  
!   if (whole == 0)
!     top = 0, shown = 1;
!   else
!     {
!       top = (float) position / whole;
!       shown = (float) portion / whole;
!     }
  
!   {
!     float old_top, old_shown;
!     Dimension height;
!     XtVaGetValues (widget,
!                  XtNtopOfThumb, &old_top,
!                  XtNshown, &old_shown,
!                  XtNheight, &height,
!                  NULL);
! 
!     /* Massage the top+shown values.  */
!     if (NILP (bar->dragging) || last_scroll_bar_part == scroll_bar_down_arrow)
!       top = max (0, min (1, top));
!     else
!       top = old_top;
!     /* Keep two pixels available for moving the thumb down.  */
!     shown = max (0, min (1 - top - (2.0 / height), shown));
! 
!     /* If the call to XawScrollbarSetThumb below doesn't seem to work,
!        check that your system's configuration file contains a define
!        for `NARROWPROTO'.  See s/freebsd.h for an example.  */
!     if (top != old_top || shown != old_shown)
!       {
!       if (NILP (bar->dragging))
!         XawScrollbarSetThumb (widget, top, shown);
!       else
          {
! #ifdef HAVE_XAW3D
!           ScrollbarWidget sb = (ScrollbarWidget) widget;
!           int scroll_mode = 0;
  
!           /* `scroll_mode' only exists with Xaw3d + ARROW_SCROLLBAR.  */
!           if (xaw3d_arrow_scroll)
!             {
!               /* Xaw3d stupidly ignores resize requests while dragging
!                  so we have to make it believe it's not in dragging mode.  */
!               scroll_mode = sb->scrollbar.scroll_mode;
!               if (scroll_mode == 2)
!                 sb->scrollbar.scroll_mode = 0;
!             }
! #endif
!           /* Try to make the scrolling a tad smoother.  */
!           if (!xaw3d_pick_top)
!             shown = min (shown, old_shown);
! 
!           XawScrollbarSetThumb (widget, top, shown);
! 
! #ifdef HAVE_XAW3D
!           if (xaw3d_arrow_scroll && scroll_mode == 2)
!             sb->scrollbar.scroll_mode = scroll_mode;
! #endif
          }
        }
!   }
  #endif /* !USE_MOTIF */
  
    UNBLOCK_INPUT;
  }
- #endif /* not USE_GTK */
  
  #endif /* USE_TOOLKIT_SCROLL_BARS */
  
--- 4625,4709 ----
        shown = (float) portion / whole;
      }
  
+   BLOCK_INPUT;
+ 
    if (NILP (bar->dragging))
      {
+       FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
+ #ifdef USE_GTK
+       GtkWidget *wscroll = xg_get_widget_from_map (SCROLL_BAR_X_WINDOW (bar));
+ #else
+       Widget widget = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar);
+ #endif
+ 
+ #if defined USE_MOTIF || defined USE_GTK
        int size, value;
  
        /* Slider size.  Must be in the range [1 .. MAX - MIN] where MAX
           is the scroll bar's maximum and MIN is the scroll bar's minimum
         value.  */
!       size = shown * SB_MAX;
!       size = min (size, SB_MAX);
        size = max (size, 1);
  
        /* Position.  Must be in the range [MIN .. MAX - SLIDER_SIZE].  */
!       value = top * SB_MAX;
!       value = min (value, SB_MAX - size);
  
+ #ifdef USE_MOTIF
        XmScrollBarSetValues (widget, value, size, 0, 0, False);
! #else  /* USE_GTK */
!       {
!       GtkAdjustment *adj;
!       int new_step;
!       int changed = 0;
  
!       adj = gtk_range_get_adjustment (GTK_RANGE (wscroll));
  
!       /* Assume all lines are of equal size.  */
!       new_step = size / max (1, FRAME_HEIGHT (f));
! 
!       if ((int) adj->page_size != size
!           || (int) adj->step_increment != new_step)
          {
!           adj->page_size = size;
!           adj->step_increment = new_step;
!           /* Assume a page increment is about 95% of the page size  */
!           adj->page_increment = (int) (0.95*adj->page_size);
!           changed = 1;
!         }
  
!       if (changed || (int) gtk_range_get_value (GTK_RANGE (wscroll)) != value)
!         {
!           GtkWidget *wfixed = f->output_data.x->edit_widget;
!           
!           BLOCK_INPUT;
!           
!           /* gtk_range_set_value invokes the callback.  Set
!              ignore_gtk_scrollbar to make the callback do nothing  */
!           xg_ignore_gtk_scrollbar = 1;
!           
!           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;
          }
        }
! #endif
! #else /* not USE_MOTIF and not USE_GTK  i.e. use Xaw */
!       /* If the call to XawScrollbarSetThumb below doesn't seem to work,
!        check that your system's configuration file contains a define
!        for `NARROWPROTO'.  See s/freebsd.h for an example.  */
!       XawScrollbarSetThumb (widget, top, shown);
  #endif /* !USE_MOTIF */
+     }
  
    UNBLOCK_INPUT;
  }
  
  #endif /* USE_TOOLKIT_SCROLL_BARS */
  
***************
*** 4878,4883 ****
--- 4819,4826 ----
  }
  
  
+ #ifndef USE_TOOLKIT_SCROLL_BARS
+ 
  /* Draw BAR's handle in the proper position.
  
     If the handle is already drawn from START to END, don't bother
***************
*** 4891,4898 ****
     the bar's top is as far down as it goes; otherwise, there's no way
     to move to the very end of the buffer.  */
  
- #ifndef USE_TOOLKIT_SCROLL_BARS
- 
  static void
  x_scroll_bar_set_handle (bar, start, end, rebuild)
       struct scroll_bar *bar;
--- 4834,4839 ----
***************
*** 10840,10846 ****
  #ifdef USE_TOOLKIT_SCROLL_BARS
  #ifndef USE_GTK
    xaw3d_arrow_scroll = False;
-   xaw3d_pick_top = True;
  #endif
  #endif
  
--- 10780,10785 ----




reply via email to

[Prev in Thread] Current Thread [Next in Thread]