0a27ac38a7f6431eec34fc359a6f205cace53251
[mono.git] / bockbuild / mac-sdk / patches / gtk / 0011-scrolledwindow-Kinetic-scrolling-support.patch
1 From 5001b3d9a9b6445ac199156c0f91f28c2112e262 Mon Sep 17 00:00:00 2001
2 From: Carlos Garcia Campos <cgarcia@igalia.com>
3 Date: Fri, 11 Feb 2011 13:43:56 +0100
4 Subject: [PATCH 11/68] scrolledwindow: Kinetic scrolling support
5
6 If the scrolling doesn't start after a long press, the scrolling is
7 cancelled and events are handled by child widgets normally.
8
9 When clicked again close to the previous button press location
10 (assuming it had ~0 movement), the scrolled window will allow
11 the child to handle the events immediately.
12
13 This is so the user doesn't have to wait to the press-and-hold
14 timeout in order to operate on the scrolledwindow child.
15
16 The innermost scrolled window always gets to capture the events, all
17 scrolled windows above it just let the event go through. Ideally
18 reaching a limit on the innermost scrolled window would propagate
19 the dragging up the hierarchy in order to keep following the touch
20 coords, although that'd involve rather evil hacks just to cater
21 for broken UIs.
22
23 Conflicts:
24
25         docs/reference/gtk/gtk3-sections.txt
26         gtk/gtk.symbols
27         gtk/gtkscrolledwindow.c
28         gtk/gtkscrolledwindow.h
29 ---
30  gtk/gtk.symbols         |    4 +
31  gtk/gtkscrolledwindow.c | 1061 ++++++++++++++++++++++++++++++++++++++++++++++-
32  gtk/gtkscrolledwindow.h |    8 +
33  3 files changed, 1058 insertions(+), 15 deletions(-)
34
35 diff --git a/gtk/gtk.symbols b/gtk/gtk.symbols
36 index 6d5d5b6..d13ca41 100644
37 --- a/gtk/gtk.symbols
38 +++ b/gtk/gtk.symbols
39 @@ -3730,6 +3730,8 @@ gtk_scrollbar_get_type G_GNUC_CONST
40  gtk_scrolled_window_add_with_viewport
41  gtk_scrolled_window_get_hadjustment
42  gtk_scrolled_window_get_hscrollbar
43 +gtk_scrolled_window_get_kinetic_scrolling
44 +gtk_scrolled_window_get_capture_button_press
45  gtk_scrolled_window_get_placement
46  gtk_scrolled_window_get_policy
47  gtk_scrolled_window_get_shadow_type
48 @@ -3738,6 +3740,8 @@ gtk_scrolled_window_get_vadjustment
49  gtk_scrolled_window_get_vscrollbar
50  gtk_scrolled_window_new
51  gtk_scrolled_window_set_hadjustment
52 +gtk_scrolled_window_set_kinetic_scrolling
53 +gtk_scrolled_window_set_capture_button_press
54  gtk_scrolled_window_set_placement
55  gtk_scrolled_window_set_policy
56  gtk_scrolled_window_set_shadow_type
57 diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c
58 index 2288b2f..694d20a 100644
59 --- a/gtk/gtkscrolledwindow.c
60 +++ b/gtk/gtkscrolledwindow.c
61 @@ -33,6 +33,8 @@
62  #include "gtkwindow.h"
63  #include "gtkprivate.h"
64  #include "gtkintl.h"
65 +#include "gtkmain.h"
66 +#include "gtkdnd.h"
67  #include "gtkalias.h"
68
69
70 @@ -72,14 +74,58 @@
71   */
72
73  #define DEFAULT_SCROLLBAR_SPACING  3
74 +#define TOUCH_BYPASS_CAPTURED_THRESHOLD 30
75 +
76 +/* Kinetic scrolling */
77 +#define FRAME_INTERVAL (1000 / 60)
78 +#define MAX_OVERSHOOT_DISTANCE 50
79 +#define FRICTION_DECELERATION 0.003
80 +#define OVERSHOOT_INVERSE_ACCELERATION 0.003
81 +#define RELEASE_EVENT_TIMEOUT 1000
82
83  typedef struct {
84 -       gboolean window_placement_set;
85 -       GtkCornerType real_window_placement;
86 +  gboolean window_placement_set;
87 +  GtkCornerType real_window_placement;
88 +
89 +  /* Kinetic scrolling */
90 +  GdkEvent              *button_press_event;
91 +  GdkWindow             *overshoot_window;
92 +  guint                  pointer_grabbed           : 1;
93 +  guint                  kinetic_scrolling         : 1;
94 +  guint                  capture_button_press      : 1;
95 +  guint                  in_drag                   : 1;
96 +  guint                  last_button_event_valid   : 1;
97 +
98 +  guint                  release_timeout_id;
99 +  guint                  deceleration_id;
100 +
101 +  gdouble                last_button_event_x_root;
102 +  gdouble                last_button_event_y_root;
103 +
104 +  gdouble                last_motion_event_x_root;
105 +  gdouble                last_motion_event_y_root;
106 +  guint32                last_motion_event_time;
107 +
108 +  gdouble                x_velocity;
109 +  gdouble                y_velocity;
110 +
111 +  gdouble                unclamped_hadj_value;
112 +  gdouble                unclamped_vadj_value;
113  } GtkScrolledWindowPrivate;
114
115  #define GTK_SCROLLED_WINDOW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_SCROLLED_WINDOW, GtkScrolledWindowPrivate))
116
117 +typedef struct
118 +{
119 +  GtkScrolledWindow     *scrolled_window;
120 +  gint64                 last_deceleration_time;
121 +
122 +  gdouble                x_velocity;
123 +  gdouble                y_velocity;
124 +  gdouble                vel_cosine;
125 +  gdouble                vel_sine;
126 +} KineticScrollData;
127 +
128  enum {
129    PROP_0,
130    PROP_HADJUSTMENT,
131 @@ -88,7 +134,8 @@ enum {
132    PROP_VSCROLLBAR_POLICY,
133    PROP_WINDOW_PLACEMENT,
134    PROP_WINDOW_PLACEMENT_SET,
135 -  PROP_SHADOW_TYPE
136 +  PROP_SHADOW_TYPE,
137 +  PROP_KINETIC_SCROLLING
138  };
139
140  /* Signals */
141 @@ -119,6 +166,8 @@ static void     gtk_scrolled_window_size_allocate      (GtkWidget         *widge
142                                                          GtkAllocation     *allocation);
143  static gboolean gtk_scrolled_window_scroll_event       (GtkWidget         *widget,
144                                                          GdkEventScroll    *event);
145 +static gboolean gtk_scrolled_window_captured_event     (GtkWidget         *widget,
146 +                                                        GdkEvent          *event);
147  static gboolean gtk_scrolled_window_focus              (GtkWidget         *widget,
148                                                          GtkDirectionType   direction);
149  static void     gtk_scrolled_window_add                (GtkContainer      *container,
150 @@ -139,9 +188,24 @@ static void     gtk_scrolled_window_relative_allocation(GtkWidget         *widge
151                                                          GtkAllocation     *allocation);
152  static void     gtk_scrolled_window_adjustment_changed (GtkAdjustment     *adjustment,
153                                                          gpointer           data);
154 +static void     gtk_scrolled_window_adjustment_value_changed (GtkAdjustment     *adjustment,
155 +                                                              gpointer           data);
156
157  static void  gtk_scrolled_window_update_real_placement (GtkScrolledWindow *scrolled_window);
158
159 +static void  gtk_scrolled_window_realize               (GtkWidget           *widget);
160 +static void  gtk_scrolled_window_unrealize             (GtkWidget           *widget);
161 +static void  gtk_scrolled_window_map                   (GtkWidget           *widget);
162 +static void  gtk_scrolled_window_unmap                 (GtkWidget           *widget);
163 +static void  gtk_scrolled_window_grab_notify           (GtkWidget           *widget,
164 +                                                        gboolean             was_grabbed);
165 +
166 +static gboolean _gtk_scrolled_window_set_adjustment_value      (GtkScrolledWindow *scrolled_window,
167 +                                                                GtkAdjustment     *adjustment,
168 +                                                                gdouble            value,
169 +                                                                gboolean           allow_overshooting,
170 +                                                                gboolean           snap_to_border);
171 +
172  static guint signals[LAST_SIGNAL] = {0};
173
174  G_DEFINE_TYPE (GtkScrolledWindow, gtk_scrolled_window, GTK_TYPE_BIN)
175 @@ -202,6 +266,11 @@ gtk_scrolled_window_class_init (GtkScrolledWindowClass *class)
176    widget_class->size_allocate = gtk_scrolled_window_size_allocate;
177    widget_class->scroll_event = gtk_scrolled_window_scroll_event;
178    widget_class->focus = gtk_scrolled_window_focus;
179 +  widget_class->realize = gtk_scrolled_window_realize;
180 +  widget_class->unrealize = gtk_scrolled_window_unrealize;
181 +  widget_class->map = gtk_scrolled_window_map;
182 +  widget_class->unmap = gtk_scrolled_window_unmap;
183 +  widget_class->grab_notify = gtk_scrolled_window_grab_notify;
184
185    container_class->add = gtk_scrolled_window_add;
186    container_class->remove = gtk_scrolled_window_remove;
187 @@ -301,6 +370,22 @@ gtk_scrolled_window_class_init (GtkScrolledWindowClass *class)
188                                                              GTK_PARAM_READABLE));
189
190    /**
191 +   * GtkScrolledWindow:kinetic-scrolling:
192 +   *
193 +   * The kinetic scrolling behavior flags.
194 +   *
195 +   * Since: X.XX
196 +   */
197 +  g_object_class_install_property (gobject_class,
198 +                                   PROP_KINETIC_SCROLLING,
199 +                                   g_param_spec_boolean ("kinetic-scrolling",
200 +                                                         P_("Kinetic Scrolling"),
201 +                                                         P_("Kinetic scrolling mode."),
202 +                                                         TRUE,
203 +                                                         GTK_PARAM_READABLE |
204 +                                                         GTK_PARAM_WRITABLE));
205 +
206 +  /**
207     * GtkScrolledWindow::scroll-child:
208     * @scrolled_window: a #GtkScrolledWindow
209     * @scroll: a #GtkScrollType describing how much to scroll
210 @@ -371,6 +456,12 @@ gtk_scrolled_window_init (GtkScrolledWindow *scrolled_window)
211    scrolled_window->focus_out = FALSE;
212    scrolled_window->window_placement = GTK_CORNER_TOP_LEFT;
213    gtk_scrolled_window_update_real_placement (scrolled_window);
214 +
215 +  if (g_getenv ("GTK2_KINETIC_SCROLLING"))
216 +    {
217 +      gtk_scrolled_window_set_kinetic_scrolling (scrolled_window, TRUE);
218 +      gtk_scrolled_window_set_capture_button_press (scrolled_window, TRUE);
219 +    }
220  }
221
222  /**
223 @@ -458,8 +549,13 @@ gtk_scrolled_window_set_hadjustment (GtkScrolledWindow *scrolled_window,
224                     "changed",
225                     G_CALLBACK (gtk_scrolled_window_adjustment_changed),
226                     scrolled_window);
227 +  g_signal_connect (hadjustment,
228 +                   "value-changed",
229 +                   G_CALLBACK (gtk_scrolled_window_adjustment_value_changed),
230 +                   scrolled_window);
231    gtk_scrolled_window_adjustment_changed (hadjustment, scrolled_window);
232 -
233 +  gtk_scrolled_window_adjustment_value_changed (hadjustment, scrolled_window);
234 +
235    if (bin->child)
236      gtk_widget_set_scroll_adjustments (bin->child,
237                                        gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)),
238 @@ -519,7 +615,12 @@ gtk_scrolled_window_set_vadjustment (GtkScrolledWindow *scrolled_window,
239                     "changed",
240                     G_CALLBACK (gtk_scrolled_window_adjustment_changed),
241                     scrolled_window);
242 +  g_signal_connect (vadjustment,
243 +                   "value-changed",
244 +                   G_CALLBACK (gtk_scrolled_window_adjustment_value_changed),
245 +                   scrolled_window);
246    gtk_scrolled_window_adjustment_changed (vadjustment, scrolled_window);
247 +  gtk_scrolled_window_adjustment_value_changed (vadjustment, scrolled_window);
248
249    if (bin->child)
250      gtk_widget_set_scroll_adjustments (bin->child,
251 @@ -842,10 +943,135 @@ gtk_scrolled_window_get_shadow_type (GtkScrolledWindow *scrolled_window)
252    return scrolled_window->shadow_type;
253  }
254
255 +/**
256 + * gtk_scrolled_window_set_kinetic_scrolling:
257 + * @scrolled_window: a #GtkScrolledWindow
258 + * @kinetic_scrolling: %TRUE to enable kinetic scrolling
259 + *
260 + * Turns kinetic scrolling on or off.
261 + * Kinetic scrolling only applies to devices with source
262 + * %GDK_SOURCE_TOUCHSCREEN.
263 + *
264 + * Since: X.XX
265 + **/
266 +void
267 +gtk_scrolled_window_set_kinetic_scrolling (GtkScrolledWindow *scrolled_window,
268 +                                           gboolean           kinetic_scrolling)
269 +{
270 +  GtkScrolledWindowPrivate *priv;
271 +
272 +  g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
273 +
274 +  priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
275 +
276 +  if (priv->kinetic_scrolling == kinetic_scrolling)
277 +    return;
278 +
279 +  priv->kinetic_scrolling = kinetic_scrolling;
280 +  if (priv->kinetic_scrolling)
281 +    {
282 +      _gtk_widget_set_captured_event_handler (GTK_WIDGET (scrolled_window),
283 +                                              gtk_scrolled_window_captured_event);
284 +    }
285 +  else
286 +    {
287 +      _gtk_widget_set_captured_event_handler (GTK_WIDGET (scrolled_window), NULL);
288 +      if (priv->release_timeout_id)
289 +        {
290 +          g_source_remove (priv->release_timeout_id);
291 +          priv->release_timeout_id = 0;
292 +        }
293 +      if (priv->deceleration_id)
294 +        {
295 +          g_source_remove (priv->deceleration_id);
296 +          priv->deceleration_id = 0;
297 +        }
298 +    }
299 +  g_object_notify (G_OBJECT (scrolled_window), "kinetic-scrolling");
300 +}
301 +
302 +/**
303 + * gtk_scrolled_window_get_kinetic_scrolling:
304 + * @scrolled_window: a #GtkScrolledWindow
305 + *
306 + * Returns the specified kinetic scrolling behavior.
307 + *
308 + * Return value: the scrolling behavior flags.
309 + *
310 + * Since: X.XX
311 + */
312 +gboolean
313 +gtk_scrolled_window_get_kinetic_scrolling (GtkScrolledWindow *scrolled_window)
314 +{
315 +  GtkScrolledWindowPrivate *priv;
316 +
317 +  g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), FALSE);
318 +
319 +  priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
320 +
321 +  return priv->kinetic_scrolling;
322 +}
323 +
324 +/**
325 + * gtk_scrolled_window_set_capture_button_press:
326 + * @scrolled_window: a #GtkScrolledWindow
327 + * @capture_button_press: %TRUE to capture button presses
328 + *
329 + * Changes the behaviour of @scrolled_window wrt. to the initial
330 + * event that possibly starts kinetic scrolling. When @capture_button_press
331 + * is set to %TRUE, the event is captured by the scrolled window, and
332 + * then later replayed if it is meant to go to the child widget.
333 + *
334 + * This should be enabled if any child widgets perform non-reversible
335 + * actions on #GtkWidget::button-press-event. If they don't, and handle
336 + * additionally handle #GtkWidget::grab-broken-event, it might be better
337 + * to set @capture_button_press to %FALSE.
338 + *
339 + * This setting only has an effect if kinetic scrolling is enabled.
340 + *
341 + * Since: X.XX
342 + */
343 +void
344 +gtk_scrolled_window_set_capture_button_press (GtkScrolledWindow *scrolled_window,
345 +                                              gboolean           capture_button_press)
346 +{
347 +  GtkScrolledWindowPrivate *priv;
348 +
349 +  g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
350 +
351 +  priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
352 +  priv->capture_button_press = capture_button_press;
353 +}
354 +
355 +/**
356 + * gtk_scrolled_window_get_capture_button_press:
357 + * @scrolled_window: a #GtkScrolledWindow
358 + *
359 + * Return whether button presses are captured during kinetic
360 + * scrolling. See gtk_scrolled_window_set_capture_button_press().
361 + *
362 + * Returns: %TRUE if button presses are captured during kinetic scrolling
363 + *
364 + * Since: X.XX
365 + */
366 +gboolean
367 +gtk_scrolled_window_get_capture_button_press (GtkScrolledWindow *scrolled_window)
368 +{
369 +  GtkScrolledWindowPrivate *priv;
370 +
371 +  g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), FALSE);
372 +
373 +  priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
374 +
375 +  return priv->capture_button_press;
376 +}
377 +
378 +
379  static void
380  gtk_scrolled_window_destroy (GtkObject *object)
381  {
382    GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (object);
383 +  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
384
385    if (scrolled_window->hscrollbar)
386      {
387 @@ -868,6 +1094,23 @@ gtk_scrolled_window_destroy (GtkObject *object)
388        scrolled_window->vscrollbar = NULL;
389      }
390
391 +  if (priv->release_timeout_id)
392 +    {
393 +      g_source_remove (priv->release_timeout_id);
394 +      priv->release_timeout_id = 0;
395 +    }
396 +  if (priv->deceleration_id)
397 +    {
398 +      g_source_remove (priv->deceleration_id);
399 +      priv->deceleration_id = 0;
400 +    }
401 +
402 +  if (priv->button_press_event)
403 +    {
404 +      gdk_event_free (priv->button_press_event);
405 +      priv->button_press_event = NULL;
406 +    }
407 +
408    GTK_OBJECT_CLASS (gtk_scrolled_window_parent_class)->destroy (object);
409  }
410
411 @@ -912,6 +1155,10 @@ gtk_scrolled_window_set_property (GObject      *object,
412        gtk_scrolled_window_set_shadow_type (scrolled_window,
413                                            g_value_get_enum (value));
414        break;
415 +    case PROP_KINETIC_SCROLLING:
416 +      gtk_scrolled_window_set_kinetic_scrolling (scrolled_window,
417 +                                                 g_value_get_boolean (value));
418 +      break;
419      default:
420        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
421        break;
422 @@ -952,6 +1199,9 @@ gtk_scrolled_window_get_property (GObject    *object,
423      case PROP_SHADOW_TYPE:
424        g_value_set_enum (value, scrolled_window->shadow_type);
425        break;
426 +    case PROP_KINETIC_SCROLLING:
427 +      g_value_set_boolean (value, priv->kinetic_scrolling);
428 +      break;
429      default:
430        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
431        break;
432 @@ -1019,10 +1269,10 @@ gtk_scrolled_window_paint (GtkWidget    *widget,
433                            GdkRectangle *area)
434  {
435    GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
436 +  GtkAllocation relative_allocation;
437
438    if (scrolled_window->shadow_type != GTK_SHADOW_NONE)
439      {
440 -      GtkAllocation relative_allocation;
441        gboolean scrollbars_within_bevel;
442
443        gtk_widget_style_get (widget, "scrollbars-within-bevel", &scrollbars_within_bevel, NULL);
444 @@ -1378,6 +1628,111 @@ gtk_scrolled_window_relative_allocation (GtkWidget     *widget,
445      }
446  }
447
448 +static gboolean
449 +_gtk_scrolled_window_get_overshoot (GtkScrolledWindow *scrolled_window,
450 +                                    gint              *overshoot_x,
451 +                                    gint              *overshoot_y)
452 +{
453 +  GtkScrolledWindowPrivate *priv;
454 +  GtkAdjustment *vadjustment, *hadjustment;
455 +  gdouble lower, upper, x, y;
456 +
457 +  priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
458 +
459 +  /* Vertical overshoot */
460 +  vadjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar));
461 +  lower = gtk_adjustment_get_lower (vadjustment);
462 +  upper = gtk_adjustment_get_upper (vadjustment) -
463 +    gtk_adjustment_get_page_size (vadjustment);
464 +
465 +  if (priv->unclamped_vadj_value < lower)
466 +    y = priv->unclamped_vadj_value - lower;
467 +  else if (priv->unclamped_vadj_value > upper)
468 +    y = priv->unclamped_vadj_value - upper;
469 +  else
470 +    y = 0;
471 +
472 +  /* Horizontal overshoot */
473 +  hadjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar));
474 +  lower = gtk_adjustment_get_lower (hadjustment);
475 +  upper = gtk_adjustment_get_upper (hadjustment) -
476 +    gtk_adjustment_get_page_size (hadjustment);
477 +
478 +  if (priv->unclamped_hadj_value < lower)
479 +    x = priv->unclamped_hadj_value - lower;
480 +  else if (priv->unclamped_hadj_value > upper)
481 +    x = priv->unclamped_hadj_value - upper;
482 +  else
483 +    x = 0;
484 +
485 +  if (overshoot_x)
486 +    *overshoot_x = x;
487 +
488 +  if (overshoot_y)
489 +    *overshoot_y = y;
490 +
491 +  return (x != 0 || y != 0);
492 +}
493 +
494 +static void
495 +_gtk_scrolled_window_allocate_overshoot_window (GtkScrolledWindow *scrolled_window)
496 +{
497 +  GtkAllocation window_allocation, relative_allocation, allocation;
498 +  GtkScrolledWindowPrivate *priv;
499 +  GtkWidget *widget = GTK_WIDGET (scrolled_window);
500 +  gint overshoot_x, overshoot_y;
501 +
502 +  if (!gtk_widget_get_realized (widget))
503 +    return;
504 +
505 +  priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
506 +
507 +  gtk_widget_get_allocation (widget, &allocation);
508 +  gtk_scrolled_window_relative_allocation (widget, &relative_allocation);
509 +  _gtk_scrolled_window_get_overshoot (scrolled_window,
510 +                                      &overshoot_x, &overshoot_y);
511 +
512 +  window_allocation = relative_allocation;
513 +  window_allocation.x += allocation.x;
514 +  window_allocation.y += allocation.y;
515 +
516 +  if (overshoot_x < 0)
517 +    window_allocation.x += -overshoot_x;
518 +
519 +  if (overshoot_y < 0)
520 +    window_allocation.y += -overshoot_y;
521 +
522 +  window_allocation.width -= ABS (overshoot_x);
523 +  window_allocation.height -= ABS (overshoot_y);
524 +
525 +  gdk_window_move_resize (priv->overshoot_window,
526 +                          window_allocation.x, window_allocation.y,
527 +                          window_allocation.width, window_allocation.height);
528 +}
529 +
530 +static void
531 +gtk_scrolled_window_allocate_child (GtkScrolledWindow *swindow,
532 +                                   GtkAllocation     *relative_allocation)
533 +{
534 +  GtkWidget     *widget = GTK_WIDGET (swindow), *child;
535 +  GtkAllocation  allocation;
536 +  GtkAllocation  child_allocation;
537 +  gint           overshoot_x, overshoot_y;
538 +
539 +  child = gtk_bin_get_child (GTK_BIN (widget));
540 +
541 +  gtk_widget_get_allocation (widget, &allocation);
542 +
543 +  gtk_scrolled_window_relative_allocation (widget, relative_allocation);
544 +  _gtk_scrolled_window_get_overshoot (swindow, &overshoot_x, &overshoot_y);
545 +
546 +  child_allocation.x = child_allocation.y = 0;
547 +  child_allocation.width = relative_allocation->width;
548 +  child_allocation.height = relative_allocation->height;
549 +
550 +  gtk_widget_size_allocate (child, &child_allocation);
551 +}
552 +
553  static void
554  gtk_scrolled_window_size_allocate (GtkWidget     *widget,
555                                    GtkAllocation *allocation)
556 @@ -1389,7 +1744,7 @@ gtk_scrolled_window_size_allocate (GtkWidget     *widget,
557    GtkAllocation child_allocation;
558    gboolean scrollbars_within_bevel;
559    gint scrollbar_spacing;
560 -
561 +
562    g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget));
563    g_return_if_fail (allocation != NULL);
564
565 @@ -1420,17 +1775,9 @@ gtk_scrolled_window_size_allocate (GtkWidget     *widget,
566
567        do
568         {
569 -         gtk_scrolled_window_relative_allocation (widget, &relative_allocation);
570 -
571 -         child_allocation.x = relative_allocation.x + allocation->x;
572 -         child_allocation.y = relative_allocation.y + allocation->y;
573 -         child_allocation.width = relative_allocation.width;
574 -         child_allocation.height = relative_allocation.height;
575 -
576           previous_hvis = scrolled_window->hscrollbar_visible;
577           previous_vvis = scrolled_window->vscrollbar_visible;
578 -
579 -         gtk_widget_size_allocate (bin->child, &child_allocation);
580 +          gtk_scrolled_window_allocate_child (scrolled_window, &relative_allocation);
581
582           /* If, after the first iteration, the hscrollbar and the
583            * vscrollbar flip visiblity, then we need both.
584 @@ -1442,6 +1789,8 @@ gtk_scrolled_window_size_allocate (GtkWidget     *widget,
585               scrolled_window->hscrollbar_visible = TRUE;
586               scrolled_window->vscrollbar_visible = TRUE;
587
588 +              gtk_scrolled_window_allocate_child (scrolled_window, &relative_allocation);
589 +
590               /* a new resize is already queued at this point,
591                * so we will immediatedly get reinvoked
592                */
593 @@ -1559,6 +1908,8 @@ gtk_scrolled_window_size_allocate (GtkWidget     *widget,
594      }
595    else if (gtk_widget_get_visible (scrolled_window->vscrollbar))
596      gtk_widget_hide (scrolled_window->vscrollbar);
597 +
598 +  _gtk_scrolled_window_allocate_overshoot_window (scrolled_window);
599  }
600
601  static gboolean
602 @@ -1639,6 +1990,555 @@ gtk_scrolled_window_scroll_event (GtkWidget      *widget,
603  }
604
605  static gboolean
606 +_gtk_scrolled_window_set_adjustment_value (GtkScrolledWindow *scrolled_window,
607 +                                           GtkAdjustment     *adjustment,
608 +                                           gdouble            value,
609 +                                           gboolean           allow_overshooting,
610 +                                           gboolean           snap_to_border)
611 +{
612 +  GtkScrolledWindowPrivate *priv;
613 +  gdouble lower, upper, *prev_value;
614 +
615 +  priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
616 +
617 +  lower = gtk_adjustment_get_lower (adjustment);
618 +  upper = gtk_adjustment_get_upper (adjustment) -
619 +    gtk_adjustment_get_page_size (adjustment);
620 +
621 +  if (adjustment == gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)))
622 +    prev_value = &priv->unclamped_hadj_value;
623 +  else if (adjustment == gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar)))
624 +    prev_value = &priv->unclamped_vadj_value;
625 +  else
626 +    return FALSE;
627 +
628 +  if (snap_to_border)
629 +    {
630 +      if (*prev_value < 0 && value > 0)
631 +        value = 0;
632 +      else if (*prev_value > upper && value < upper)
633 +        value = upper;
634 +    }
635 +
636 +  if (allow_overshooting)
637 +    {
638 +      lower -= MAX_OVERSHOOT_DISTANCE;
639 +      upper += MAX_OVERSHOOT_DISTANCE;
640 +    }
641 +
642 +  *prev_value = CLAMP (value, lower, upper);
643 +  gtk_adjustment_set_value (adjustment, *prev_value);
644 +
645 +  return (*prev_value != value);
646 +}
647 +
648 +static gboolean
649 +scrolled_window_deceleration_cb (gpointer user_data)
650 +{
651 +  KineticScrollData *data = user_data;
652 +  GtkScrolledWindow *scrolled_window = data->scrolled_window;
653 +  GtkScrolledWindowPrivate *priv;
654 +  GtkAdjustment *hadjustment, *vadjustment;
655 +  gint old_overshoot_x, old_overshoot_y, overshoot_x, overshoot_y;
656 +  gdouble value;
657 +  gint64 current_time;
658 +  guint elapsed;
659 +
660 +  priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
661 +  hadjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar));
662 +  vadjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar));
663 +
664 +  _gtk_scrolled_window_get_overshoot (scrolled_window,
665 +                                      &old_overshoot_x, &old_overshoot_y);
666 +
667 +  current_time = g_get_monotonic_time ();
668 +  elapsed = (current_time - data->last_deceleration_time) / 1000;
669 +  data->last_deceleration_time = current_time;
670 +
671 +  if (hadjustment && scrolled_window->hscrollbar_visible)
672 +    {
673 +      value = priv->unclamped_hadj_value + (data->x_velocity * elapsed);
674 +
675 +      if (_gtk_scrolled_window_set_adjustment_value (scrolled_window,
676 +                                                     hadjustment,
677 +                                                     value, TRUE, TRUE))
678 +        data->x_velocity = 0;
679 +    }
680 +  else
681 +    data->x_velocity = 0;
682 +
683 +  if (vadjustment && scrolled_window->vscrollbar_visible)
684 +    {
685 +      value = priv->unclamped_vadj_value + (data->y_velocity * elapsed);
686 +
687 +      if (_gtk_scrolled_window_set_adjustment_value (scrolled_window,
688 +                                                     vadjustment,
689 +                                                     value, TRUE, TRUE))
690 +        data->y_velocity = 0;
691 +    }
692 +  else
693 +    data->y_velocity = 0;
694 +
695 +  _gtk_scrolled_window_get_overshoot (scrolled_window,
696 +                                      &overshoot_x, &overshoot_y);
697 +
698 +  if (overshoot_x == 0)
699 +    {
700 +      if (old_overshoot_x != 0)
701 +        {
702 +          /* Overshooting finished snapping back */
703 +          data->x_velocity = 0;
704 +        }
705 +      else if (data->x_velocity > 0)
706 +        {
707 +          data->x_velocity -= FRICTION_DECELERATION * elapsed * data->vel_sine;
708 +          data->x_velocity = MAX (0, data->x_velocity);
709 +        }
710 +      else if (data->x_velocity < 0)
711 +        {
712 +          data->x_velocity += FRICTION_DECELERATION * elapsed * data->vel_sine;
713 +          data->x_velocity = MIN (0, data->x_velocity);
714 +        }
715 +    }
716 +  else if (overshoot_x < 0)
717 +    data->x_velocity += OVERSHOOT_INVERSE_ACCELERATION * elapsed;
718 +  else if (overshoot_x > 0)
719 +    data->x_velocity -= OVERSHOOT_INVERSE_ACCELERATION * elapsed;
720 +
721 +  if (overshoot_y == 0)
722 +    {
723 +      if (old_overshoot_y != 0)
724 +        {
725 +          /* Overshooting finished snapping back */
726 +          data->y_velocity = 0;
727 +        }
728 +      else if (data->y_velocity > 0)
729 +        {
730 +          data->y_velocity -= FRICTION_DECELERATION * elapsed * data->vel_cosine;
731 +          data->y_velocity = MAX (0, data->y_velocity);
732 +        }
733 +      else if (data->y_velocity < 0)
734 +        {
735 +          data->y_velocity += FRICTION_DECELERATION * elapsed * data->vel_cosine;
736 +          data->y_velocity = MIN (0, data->y_velocity);
737 +        }
738 +    }
739 +  else if (overshoot_y < 0)
740 +    data->y_velocity += OVERSHOOT_INVERSE_ACCELERATION * elapsed;
741 +  else if (overshoot_y > 0)
742 +    data->y_velocity -= OVERSHOOT_INVERSE_ACCELERATION * elapsed;
743 +
744 +  if (old_overshoot_x != overshoot_x ||
745 +      old_overshoot_y != overshoot_y)
746 +    _gtk_scrolled_window_allocate_overshoot_window (scrolled_window);
747 +
748 +  if (overshoot_x != 0 || overshoot_y != 0 ||
749 +      data->x_velocity != 0 || data->y_velocity != 0)
750 +    return TRUE;
751 +  else
752 +    {
753 +      priv->deceleration_id = 0;
754 +      return FALSE;
755 +    }
756 +}
757 +
758 +static void
759 +gtk_scrolled_window_cancel_deceleration (GtkScrolledWindow *scrolled_window)
760 +{
761 +  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
762 +
763 +  if (priv->deceleration_id)
764 +    {
765 +      g_source_remove (priv->deceleration_id);
766 +      priv->deceleration_id = 0;
767 +    }
768 +}
769 +
770 +static void
771 +gtk_scrolled_window_start_deceleration (GtkScrolledWindow *scrolled_window)
772 +{
773 +  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
774 +  KineticScrollData *data;
775 +  gdouble angle;
776 +
777 +  data = g_new0 (KineticScrollData, 1);
778 +  data->scrolled_window = scrolled_window;
779 +  data->last_deceleration_time = g_get_monotonic_time ();
780 +  data->x_velocity = priv->x_velocity;
781 +  data->y_velocity = priv->y_velocity;
782 +
783 +  /* We use sine/cosine as a factor to deceleration x/y components
784 +   * of the vector, so we care about the sign later.
785 +   */
786 +  angle = atan2 (ABS (data->x_velocity), ABS (data->y_velocity));
787 +  data->vel_cosine = cos (angle);
788 +  data->vel_sine = sin (angle);
789 +
790 +  priv->deceleration_id =
791 +    gdk_threads_add_timeout_full (G_PRIORITY_DEFAULT,
792 +                                  FRAME_INTERVAL,
793 +                                  scrolled_window_deceleration_cb,
794 +                                  data, (GDestroyNotify) g_free);
795 +}
796 +
797 +static gboolean
798 +gtk_scrolled_window_release_captured_event (GtkScrolledWindow *scrolled_window)
799 +{
800 +  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
801 +
802 +  /* Cancel the scrolling and send the button press
803 +   * event to the child widget
804 +   */
805 +  if (!priv->button_press_event)
806 +    return FALSE;
807 +
808 +  if (priv->pointer_grabbed)
809 +    {
810 +      gtk_grab_remove (GTK_WIDGET (scrolled_window));
811 +      priv->pointer_grabbed = FALSE;
812 +    }
813 +
814 +  if (priv->capture_button_press)
815 +    {
816 +      GtkWidget *event_widget;
817 +
818 +      event_widget = gtk_get_event_widget (priv->button_press_event);
819 +
820 +      if (!_gtk_propagate_captured_event (event_widget,
821 +                                          priv->button_press_event,
822 +                                          gtk_bin_get_child (GTK_BIN (scrolled_window))))
823 +        gtk_propagate_event (event_widget, priv->button_press_event);
824 +
825 +      gdk_event_free (priv->button_press_event);
826 +      priv->button_press_event = NULL;
827 +    }
828 +
829 +  if (_gtk_scrolled_window_get_overshoot (scrolled_window, NULL, NULL))
830 +    gtk_scrolled_window_start_deceleration (scrolled_window);
831 +
832 +  return FALSE;
833 +}
834 +
835 +static gboolean
836 +gtk_scrolled_window_calculate_velocity (GtkScrolledWindow *scrolled_window,
837 +                                       GdkEvent          *event)
838 +{
839 +  GtkScrolledWindowPrivate *priv;
840 +  gdouble x_root, y_root;
841 +  guint32 _time;
842 +
843 +#define STILL_THRESHOLD 40
844 +
845 +  if (!gdk_event_get_root_coords (event, &x_root, &y_root))
846 +    return FALSE;
847 +
848 +  priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
849 +  _time = gdk_event_get_time (event);
850 +
851 +  if (priv->last_motion_event_x_root != x_root ||
852 +      priv->last_motion_event_y_root != y_root ||
853 +      ABS (_time - priv->last_motion_event_time) > STILL_THRESHOLD)
854 +    {
855 +      priv->x_velocity = (priv->last_motion_event_x_root - x_root) /
856 +        (gdouble) (_time - priv->last_motion_event_time);
857 +      priv->y_velocity = (priv->last_motion_event_y_root - y_root) /
858 +        (gdouble) (_time - priv->last_motion_event_time);
859 +    }
860 +
861 +  priv->last_motion_event_x_root = x_root;
862 +  priv->last_motion_event_y_root = y_root;
863 +  priv->last_motion_event_time = _time;
864 +
865 +#undef STILL_THRESHOLD
866 +
867 +  return TRUE;
868 +}
869 +
870 +static gboolean
871 +gtk_scrolled_window_captured_button_release (GtkWidget *widget,
872 +                                             GdkEvent  *event)
873 +{
874 +  GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
875 +  GtkScrolledWindowPrivate *priv;
876 +  GtkWidget *child;
877 +  gboolean overshoot;
878 +  gdouble x_root, y_root;
879 +
880 +  if (event->button.button != 1)
881 +    return FALSE;
882 +
883 +  child = gtk_bin_get_child (GTK_BIN (widget));
884 +  if (!child)
885 +    return FALSE;
886 +
887 +  priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
888 +  gtk_grab_remove (widget);
889 +  priv->pointer_grabbed = FALSE;
890 +
891 +  if (priv->release_timeout_id)
892 +    {
893 +      g_source_remove (priv->release_timeout_id);
894 +      priv->release_timeout_id = 0;
895 +    }
896 +
897 +  overshoot = _gtk_scrolled_window_get_overshoot (scrolled_window, NULL, NULL);
898 +
899 +  if (priv->in_drag)
900 +    gdk_pointer_ungrab (gdk_event_get_time (event));
901 +  else
902 +    {
903 +      /* There hasn't been scrolling at all, so just let the
904 +       * child widget handle the button press normally
905 +       */
906 +      gtk_scrolled_window_release_captured_event (scrolled_window);
907 +
908 +      if (!overshoot)
909 +        return FALSE;
910 +    }
911 +  priv->in_drag = FALSE;
912 +
913 +  if (priv->button_press_event)
914 +    {
915 +      gdk_event_free (priv->button_press_event);
916 +      priv->button_press_event = NULL;
917 +    }
918 +
919 +  gtk_scrolled_window_calculate_velocity (scrolled_window, event);
920 +
921 +  /* Zero out vector components without a visible scrollbar */
922 +  if (!scrolled_window->hscrollbar_visible)
923 +    priv->x_velocity = 0;
924 +  if (!scrolled_window->vscrollbar_visible)
925 +    priv->y_velocity = 0;
926 +
927 +  if (priv->x_velocity != 0 || priv->y_velocity != 0 || overshoot)
928 +    {
929 +      gtk_scrolled_window_start_deceleration (scrolled_window);
930 +      priv->x_velocity = priv->y_velocity = 0;
931 +      priv->last_button_event_valid = FALSE;
932 +    }
933 +  else
934 +    {
935 +      gdk_event_get_root_coords (event, &x_root, &y_root);
936 +      priv->last_button_event_x_root = x_root;
937 +      priv->last_button_event_y_root = y_root;
938 +      priv->last_button_event_valid = TRUE;
939 +    }
940 +
941 +  if (priv->capture_button_press)
942 +    return TRUE;
943 +  else
944 +    return FALSE;
945 +}
946 +
947 +static gboolean
948 +gtk_scrolled_window_captured_motion_notify (GtkWidget *widget,
949 +                                            GdkEvent  *event)
950 +{
951 +  GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
952 +  GtkScrolledWindowPrivate *priv;
953 +  gint old_overshoot_x, old_overshoot_y;
954 +  gint new_overshoot_x, new_overshoot_y;
955 +  GtkWidget *child;
956 +  GtkAdjustment *hadjustment;
957 +  GtkAdjustment *vadjustment;
958 +  gdouble dx, dy;
959 +  GdkModifierType state;
960 +  gdouble x_root, y_root;
961 +
962 +  gdk_event_get_state (event, &state);
963 +  if (!(state & GDK_BUTTON1_MASK))
964 +    return FALSE;
965 +
966 +  child = gtk_bin_get_child (GTK_BIN (widget));
967 +  if (!child)
968 +    return FALSE;
969 +
970 +  priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
971 +
972 +  /* Check if we've passed the drag threshold */
973 +  gdk_event_get_root_coords (event, &x_root, &y_root);
974 +  if (!priv->in_drag)
975 +    {
976 +      if (gtk_drag_check_threshold (widget,
977 +                                    priv->last_button_event_x_root,
978 +                                    priv->last_button_event_y_root,
979 +                                    x_root, y_root))
980 +        {
981 +          if (priv->release_timeout_id)
982 +            {
983 +              g_source_remove (priv->release_timeout_id);
984 +              priv->release_timeout_id = 0;
985 +            }
986 +
987 +          priv->last_button_event_valid = FALSE;
988 +          priv->in_drag = TRUE;
989 +        }
990 +      else
991 +        return TRUE;
992 +    }
993 +
994 +  gdk_pointer_grab (gtk_widget_get_window (widget),
995 +                    TRUE,
996 +                    GDK_BUTTON_RELEASE_MASK | GDK_BUTTON1_MOTION_MASK,
997 +                    NULL, NULL,
998 +                    gdk_event_get_time (event));
999 +
1000 +  priv->last_button_event_valid = FALSE;
1001 +
1002 +  if (priv->button_press_event)
1003 +    {
1004 +      gdk_event_free (priv->button_press_event);
1005 +      priv->button_press_event = NULL;
1006 +    }
1007 +
1008 +  _gtk_scrolled_window_get_overshoot (scrolled_window,
1009 +                                      &old_overshoot_x, &old_overshoot_y);
1010 +
1011 +  hadjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar));
1012 +  if (hadjustment && scrolled_window->hscrollbar_visible)
1013 +    {
1014 +      dx = (priv->last_motion_event_x_root - x_root) + priv->unclamped_hadj_value;
1015 +      _gtk_scrolled_window_set_adjustment_value (scrolled_window, hadjustment,
1016 +                                                 dx, TRUE, FALSE);
1017 +    }
1018 +
1019 +  vadjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar));
1020 +  if (vadjustment && scrolled_window->vscrollbar_visible)
1021 +    {
1022 +      dy = (priv->last_motion_event_y_root - y_root) + priv->unclamped_vadj_value;
1023 +      _gtk_scrolled_window_set_adjustment_value (scrolled_window, vadjustment,
1024 +                                                 dy, TRUE, FALSE);
1025 +    }
1026 +
1027 +  _gtk_scrolled_window_get_overshoot (scrolled_window,
1028 +                                      &new_overshoot_x, &new_overshoot_y);
1029 +
1030 +  if (old_overshoot_x != new_overshoot_x ||
1031 +      old_overshoot_y != new_overshoot_y)
1032 +    _gtk_scrolled_window_allocate_overshoot_window (scrolled_window);
1033 +
1034 +  gtk_scrolled_window_calculate_velocity (scrolled_window, event);
1035 +
1036 +  return TRUE;
1037 +}
1038 +
1039 +static gboolean
1040 +gtk_scrolled_window_captured_button_press (GtkWidget *widget,
1041 +                                           GdkEvent  *event)
1042 +{
1043 +  GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
1044 +  GtkScrolledWindowPrivate *priv;
1045 +  GtkWidget *child;
1046 +  GtkWidget *event_widget;
1047 +  gdouble x_root, y_root;
1048 +
1049 +  /* If scrollbars are not visible, we don't do kinetic scrolling */
1050 +  if (!scrolled_window->vscrollbar_visible &&
1051 +      !scrolled_window->hscrollbar_visible)
1052 +    return FALSE;
1053 +
1054 +  priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
1055 +
1056 +  event_widget = gtk_get_event_widget (event);
1057 +
1058 +  /* If there's another scrolled window between the widget
1059 +   * receiving the event and this capturing scrolled window,
1060 +   * let it handle the events.
1061 +   */
1062 +  if (widget != gtk_widget_get_ancestor (event_widget, GTK_TYPE_SCROLLED_WINDOW))
1063 +    return FALSE;
1064 +
1065 +  /* Check whether the button press is close to the previous one,
1066 +   * take that as a shortcut to get the child widget handle events
1067 +   */
1068 +  gdk_event_get_root_coords (event, &x_root, &y_root);
1069 +  if (priv->last_button_event_valid &&
1070 +      ABS (x_root - priv->last_button_event_x_root) < TOUCH_BYPASS_CAPTURED_THRESHOLD &&
1071 +      ABS (y_root - priv->last_button_event_y_root) < TOUCH_BYPASS_CAPTURED_THRESHOLD)
1072 +    {
1073 +      priv->last_button_event_valid = FALSE;
1074 +      return FALSE;
1075 +    }
1076 +
1077 +  priv->last_button_event_x_root = priv->last_motion_event_x_root = x_root;
1078 +  priv->last_button_event_y_root = priv->last_motion_event_y_root = y_root;
1079 +  priv->last_motion_event_time = gdk_event_get_time (event);
1080 +  priv->last_button_event_valid = TRUE;
1081 +
1082 +  if (event->button.button != 1)
1083 +    return FALSE;
1084 +
1085 +  child = gtk_bin_get_child (GTK_BIN (widget));
1086 +  if (!child)
1087 +    return FALSE;
1088 +
1089 +  if (scrolled_window->hscrollbar == event_widget ||
1090 +      scrolled_window->vscrollbar == event_widget)
1091 +    return FALSE;
1092 +
1093 +  priv->pointer_grabbed = TRUE;
1094 +  gtk_grab_add (widget);
1095 +
1096 +  gtk_scrolled_window_cancel_deceleration (scrolled_window);
1097 +
1098 +  /* Only set the timeout if we're going to store an event */
1099 +  if (priv->capture_button_press)
1100 +    priv->release_timeout_id =
1101 +      gdk_threads_add_timeout (RELEASE_EVENT_TIMEOUT,
1102 +                               (GSourceFunc) gtk_scrolled_window_release_captured_event,
1103 +                               scrolled_window);
1104 +
1105 +  priv->in_drag = FALSE;
1106 +
1107 +  if (priv->capture_button_press)
1108 +    {
1109 +      /* Store the button press event in
1110 +       * case we need to propagate it later
1111 +       */
1112 +      priv->button_press_event = gdk_event_copy (event);
1113 +      return TRUE;
1114 +    }
1115 +  else
1116 +    return FALSE;
1117 +}
1118 +
1119 +static gboolean
1120 +gtk_scrolled_window_captured_event (GtkWidget *widget,
1121 +                                    GdkEvent  *event)
1122 +{
1123 +  gboolean retval = FALSE;
1124 +  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (widget);
1125 +
1126 +  switch (event->type)
1127 +    {
1128 +    case GDK_BUTTON_PRESS:
1129 +      retval = gtk_scrolled_window_captured_button_press (widget, event);
1130 +      break;
1131 +    case GDK_BUTTON_RELEASE:
1132 +      if (priv->pointer_grabbed)
1133 +        retval = gtk_scrolled_window_captured_button_release (widget, event);
1134 +      else
1135 +        priv->last_button_event_valid = FALSE;
1136 +      break;
1137 +    case GDK_MOTION_NOTIFY:
1138 +      if (priv->pointer_grabbed)
1139 +        retval = gtk_scrolled_window_captured_motion_notify (widget, event);
1140 +      break;
1141 +    case GDK_LEAVE_NOTIFY:
1142 +    case GDK_ENTER_NOTIFY:
1143 +      if (priv->in_drag &&
1144 +          event->crossing.mode != GDK_CROSSING_GRAB)
1145 +        retval = TRUE;
1146 +      break;
1147 +    default:
1148 +      break;
1149 +    }
1150 +
1151 +  return retval;
1152 +}
1153 +
1154 +static gboolean
1155  gtk_scrolled_window_focus (GtkWidget        *widget,
1156                            GtkDirectionType  direction)
1157  {
1158 @@ -1714,17 +2614,42 @@ gtk_scrolled_window_adjustment_changed (GtkAdjustment *adjustment,
1159  }
1160
1161  static void
1162 +gtk_scrolled_window_adjustment_value_changed (GtkAdjustment *adjustment,
1163 +                                              gpointer       user_data)
1164 +{
1165 +  GtkScrolledWindow *scrolled_window = user_data;
1166 +  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
1167 +
1168 +  /* Allow overshooting for kinetic scrolling operations */
1169 +  if (priv->pointer_grabbed || priv->deceleration_id)
1170 +    return;
1171 +
1172 +  /* Ensure GtkAdjustment and unclamped values are in sync */
1173 +  if (scrolled_window->vscrollbar &&
1174 +      adjustment == gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar)))
1175 +    priv->unclamped_vadj_value = gtk_adjustment_get_value (adjustment);
1176 +  else if (scrolled_window->hscrollbar &&
1177 +           adjustment == gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)))
1178 +    priv->unclamped_hadj_value = gtk_adjustment_get_value (adjustment);
1179 +}
1180 +
1181 +static void
1182  gtk_scrolled_window_add (GtkContainer *container,
1183                          GtkWidget    *child)
1184  {
1185    GtkScrolledWindow *scrolled_window;
1186 +  GtkScrolledWindowPrivate *priv;
1187    GtkBin *bin;
1188
1189    bin = GTK_BIN (container);
1190 +  priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (container);
1191    g_return_if_fail (bin->child == NULL);
1192
1193    scrolled_window = GTK_SCROLLED_WINDOW (container);
1194
1195 +  if (gtk_widget_get_realized (GTK_WIDGET (bin)))
1196 +    gtk_widget_set_parent_window (child, priv->overshoot_window);
1197 +
1198    bin->child = child;
1199    gtk_widget_set_parent (child, GTK_WIDGET (bin));
1200
1201 @@ -1837,5 +2762,111 @@ _gtk_scrolled_window_get_scrollbar_spacing (GtkScrolledWindow *scrolled_window)
1202      }
1203  }
1204
1205 +static void
1206 +gtk_scrolled_window_realize (GtkWidget *widget)
1207 +{
1208 +  GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
1209 +  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
1210 +  GtkAllocation allocation, relative_allocation;
1211 +  GdkWindowAttr attributes;
1212 +  GtkWidget *child_widget;
1213 +  gint attributes_mask;
1214 +
1215 +  gtk_widget_set_realized (widget, TRUE);
1216 +  gtk_widget_get_allocation (widget, &allocation);
1217 +  gtk_scrolled_window_relative_allocation (widget, &relative_allocation);
1218 +
1219 +  attributes.window_type = GDK_WINDOW_CHILD;
1220 +  attributes.x = allocation.x + relative_allocation.x;
1221 +  attributes.y = allocation.y + relative_allocation.y;
1222 +  attributes.width = relative_allocation.width;
1223 +  attributes.height = relative_allocation.height;
1224 +  attributes.wclass = GDK_INPUT_OUTPUT;
1225 +  attributes.visual = gtk_widget_get_visual (widget);
1226 +  attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK |
1227 +    GDK_BUTTON_MOTION_MASK;
1228 +
1229 +  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
1230 +
1231 +  priv->overshoot_window =
1232 +    gdk_window_new (gtk_widget_get_parent_window (widget),
1233 +                    &attributes, attributes_mask);
1234 +
1235 +  gdk_window_set_user_data (priv->overshoot_window, widget);
1236 +
1237 +  child_widget = gtk_bin_get_child (GTK_BIN (widget));
1238 +
1239 +  if (child_widget)
1240 +    gtk_widget_set_parent_window (child_widget,
1241 +                                  priv->overshoot_window);
1242 +
1243 +  GTK_WIDGET_CLASS (gtk_scrolled_window_parent_class)->realize (widget);
1244 +}
1245 +
1246 +static void
1247 +gtk_scrolled_window_unrealize (GtkWidget *widget)
1248 +{
1249 +  GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
1250 +  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
1251 +
1252 +  gdk_window_set_user_data (priv->overshoot_window, NULL);
1253 +  gdk_window_destroy (priv->overshoot_window);
1254 +  priv->overshoot_window = NULL;
1255 +
1256 +  gtk_widget_set_realized (widget, FALSE);
1257 +
1258 +  GTK_WIDGET_CLASS (gtk_scrolled_window_parent_class)->unrealize (widget);
1259 +}
1260 +
1261 +static void
1262 +gtk_scrolled_window_map (GtkWidget *widget)
1263 +{
1264 +  GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
1265 +  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
1266 +
1267 +  gdk_window_show (priv->overshoot_window);
1268 +
1269 +  GTK_WIDGET_CLASS (gtk_scrolled_window_parent_class)->map (widget);
1270 +}
1271 +
1272 +static void
1273 +gtk_scrolled_window_unmap (GtkWidget *widget)
1274 +{
1275 +  GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
1276 +  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
1277 +
1278 +  gdk_window_hide (priv->overshoot_window);
1279 +
1280 +  GTK_WIDGET_CLASS (gtk_scrolled_window_parent_class)->unmap (widget);
1281 +}
1282 +
1283 +static void
1284 +gtk_scrolled_window_grab_notify (GtkWidget *widget,
1285 +                                 gboolean   was_grabbed)
1286 +{
1287 +  GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
1288 +  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
1289 +
1290 +  if (priv->pointer_grabbed && !was_grabbed)
1291 +    {
1292 +      gdk_pointer_ungrab (gtk_get_current_event_time ());
1293 +      priv->pointer_grabbed = FALSE;
1294 +      priv->in_drag = FALSE;
1295 +
1296 +      if (priv->release_timeout_id)
1297 +        {
1298 +          g_source_remove (priv->release_timeout_id);
1299 +          priv->release_timeout_id = 0;
1300 +        }
1301 +
1302 +      if (_gtk_scrolled_window_get_overshoot (scrolled_window, NULL, NULL))
1303 +        gtk_scrolled_window_start_deceleration (scrolled_window);
1304 +      else
1305 +        gtk_scrolled_window_cancel_deceleration (scrolled_window);
1306 +
1307 +      priv->last_button_event_valid = FALSE;
1308 +    }
1309 +}
1310 +
1311  #define __GTK_SCROLLED_WINDOW_C__
1312  #include "gtkaliasdef.c"
1313 diff --git a/gtk/gtkscrolledwindow.h b/gtk/gtkscrolledwindow.h
1314 index 5407547..1f555e0 100644
1315 --- a/gtk/gtkscrolledwindow.h
1316 +++ b/gtk/gtkscrolledwindow.h
1317 @@ -127,6 +127,14 @@ GtkShadowType  gtk_scrolled_window_get_shadow_type   (GtkScrolledWindow *scrolle
1318  void          gtk_scrolled_window_add_with_viewport (GtkScrolledWindow *scrolled_window,
1319                                                       GtkWidget         *child);
1320
1321 +void           gtk_scrolled_window_set_kinetic_scrolling  (GtkScrolledWindow        *scrolled_window,
1322 +                                                           gboolean                  kinetic_scrolling);
1323 +gboolean       gtk_scrolled_window_get_kinetic_scrolling  (GtkScrolledWindow        *scrolled_window);
1324 +
1325 +void           gtk_scrolled_window_set_capture_button_press (GtkScrolledWindow      *scrolled_window,
1326 +                                                             gboolean                capture_button_press);
1327 +gboolean       gtk_scrolled_window_get_capture_button_press (GtkScrolledWindow      *scrolled_window);
1328 +
1329  gint _gtk_scrolled_window_get_scrollbar_spacing (GtkScrolledWindow *scrolled_window);
1330
1331
1332 --
1333 1.7.10.2 (Apple Git-33)