1 From 713b51c19644653815b8ff1cd629d706f1074043 Mon Sep 17 00:00:00 2001
2 From: Michael Natterer <mitch@gimp.org>
3 Date: Tue, 10 Jul 2012 14:33:45 +0200
4 Subject: [PATCH 14/68] gtk: add event handling to GtkScrolledWindow's overlay
8 gtk/gtkscrolledwindow.c | 438 +++++++++++++++++++++++++++++++++++++++++++----
9 1 file changed, 403 insertions(+), 35 deletions(-)
11 diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c
12 index 77d485f..70de6ec 100644
13 --- a/gtk/gtkscrolledwindow.c
14 +++ b/gtk/gtkscrolledwindow.c
16 #define OVERSHOOT_INVERSE_ACCELERATION 0.003
17 #define RELEASE_EVENT_TIMEOUT 1000
19 +/* Overlay scrollbars */
20 +#define SCROLL_INTERVAL_INITIAL 300
21 +#define SCROLL_INTERVAL_REPEAT 100
24 gboolean window_placement_set;
25 GtkCornerType real_window_placement;
26 @@ -123,6 +127,19 @@ typedef struct {
27 gboolean sb_fading_in;
28 gint sb_fade_out_delay;
31 + gboolean sb_hovering;
32 + gboolean sb_pointer_grabbed;
33 + gboolean sb_grab_vscroll;
34 + gboolean sb_grab_hscroll;
35 + gboolean sb_drag_slider;
36 + gboolean sb_visible;
38 + gint sb_grab_offset_x;
39 + gint sb_grab_offset_y;
41 + gint sb_scroll_direction;
42 + guint sb_scroll_timeout_id;
43 } GtkScrolledWindowPrivate;
45 #define GTK_SCROLLED_WINDOW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_SCROLLED_WINDOW, GtkScrolledWindowPrivate))
46 @@ -219,8 +236,24 @@ static gboolean _gtk_scrolled_window_set_adjustment_value (GtkScrolledWindo
47 gboolean snap_to_border);
49 static void gtk_scrolled_window_cancel_animation (GtkScrolledWindow *scrolled_window);
50 +static void gtk_scrolled_window_start_fade_out_timeout (GtkScrolledWindow *scrolled_window);
51 +static void gtk_scrolled_window_stop_fade_out_timeout (GtkScrolledWindow *scrolled_window);
52 static void gtk_scrolled_window_start_fade_in_animation (GtkScrolledWindow *scrolled_window);
53 static void gtk_scrolled_window_start_fade_out_animation (GtkScrolledWindow *scrolled_window);
55 + gtk_scrolled_window_over_child_scroll_areas (GtkScrolledWindow *scrolled_window,
59 + gboolean *over_vscroll,
60 + gboolean *over_hscroll);
61 +static void gtk_scrolled_window_get_child_scroll_areas (GtkScrolledWindow *scrolled_window,
63 + GdkWindow *child_window,
64 + GdkRectangle *vbar_rect,
65 + GdkRectangle *vslider_rect,
66 + GdkRectangle *hbar_rect,
67 + GdkRectangle *hslider_rect);
68 static gboolean gtk_scrolled_window_child_expose (GtkWidget *widget,
69 GdkEventExpose *eevent,
70 GtkScrolledWindow *scrolled_window);
71 @@ -2385,8 +2418,8 @@ gtk_scrolled_window_calculate_velocity (GtkScrolledWindow *scrolled_window,
75 -gtk_scrolled_window_captured_button_release (GtkWidget *widget,
77 +gtk_scrolled_window_captured_button_release_kinetic (GtkWidget *widget,
80 GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
81 GtkScrolledWindowPrivate *priv;
82 @@ -2462,8 +2495,8 @@ gtk_scrolled_window_captured_button_release (GtkWidget *widget,
86 -gtk_scrolled_window_captured_motion_notify (GtkWidget *widget,
88 +gtk_scrolled_window_captured_motion_notify_kinetic (GtkWidget *widget,
91 GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
92 GtkScrolledWindowPrivate *priv;
93 @@ -2554,8 +2587,8 @@ gtk_scrolled_window_captured_motion_notify (GtkWidget *widget,
97 -gtk_scrolled_window_captured_button_press (GtkWidget *widget,
99 +gtk_scrolled_window_captured_button_press_kinetic (GtkWidget *widget,
102 GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
103 GtkScrolledWindowPrivate *priv;
104 @@ -2633,29 +2666,283 @@ gtk_scrolled_window_captured_button_press (GtkWidget *widget,
109 +gtk_scrolled_window_scroll_step (GtkScrolledWindow *scrolled_window)
111 + GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
112 + GtkAdjustment *adj;
115 + if (priv->sb_grab_vscroll)
117 + adj = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar));
119 + else if (priv->sb_grab_hscroll)
121 + adj = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar));
124 + value = adj->value + (priv->sb_scroll_direction * adj->page_size);
125 + value = CLAMP (value, adj->lower, adj->upper - adj->page_size);
127 + gtk_adjustment_set_value (adj, value);
131 +gtk_scrolled_window_scroll_step_timeout (gpointer data)
133 + GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (data);
134 + GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
136 + gtk_scrolled_window_scroll_step (scrolled_window);
138 + g_source_remove (priv->sb_scroll_timeout_id);
140 + priv->sb_scroll_timeout_id =
141 + gdk_threads_add_timeout (SCROLL_INTERVAL_REPEAT,
142 + gtk_scrolled_window_scroll_step_timeout,
149 +gtk_scrolled_window_captured_button_press_scrollbar (GtkWidget *widget,
152 + GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
153 + GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
154 + GdkEventButton *bevent = (GdkEventButton *) event;
156 + if (bevent->button != 1)
159 + if (gtk_scrolled_window_over_child_scroll_areas (scrolled_window, event,
160 + bevent->x, bevent->y,
161 + &priv->sb_grab_vscroll,
162 + &priv->sb_grab_hscroll))
164 + GdkRectangle vbar_rect;
165 + GdkRectangle vslider_rect;
166 + GdkRectangle hbar_rect;
167 + GdkRectangle hslider_rect;
169 + priv->sb_pointer_grabbed = TRUE;
170 + gtk_grab_add (widget);
172 + gtk_scrolled_window_get_child_scroll_areas (scrolled_window,
173 + gtk_bin_get_child (GTK_BIN (widget)),
175 + &vbar_rect, &vslider_rect,
176 + &hbar_rect, &hslider_rect);
178 + if (priv->sb_grab_vscroll)
180 + /* we consider the entire width of the scrollbar clickable */
181 + vslider_rect.x = vbar_rect.x;
182 + vslider_rect.width = vbar_rect.width;
184 + if (bevent->x >= vslider_rect.x &&
185 + bevent->x < (vslider_rect.x + vslider_rect.width) &&
186 + bevent->y >= vslider_rect.y &&
187 + bevent->y < (vslider_rect.y + vslider_rect.height))
189 + priv->sb_drag_slider = TRUE;
190 + priv->sb_grab_offset_y = bevent->y - vslider_rect.y;
194 + priv->sb_drag_slider = FALSE;
195 + priv->sb_grab_offset_y = bevent->y - vbar_rect.y;
197 + if (bevent->y < vslider_rect.y)
198 + priv->sb_scroll_direction = -1;
200 + priv->sb_scroll_direction = 1;
203 + else if (priv->sb_grab_hscroll)
205 + /* we consider the entire height of the scrollbar clickable */
206 + hslider_rect.y = hbar_rect.y;
207 + hslider_rect.height = hbar_rect.height;
209 + if (bevent->x >= hslider_rect.x &&
210 + bevent->x < (hslider_rect.x + hslider_rect.width) &&
211 + bevent->y >= hslider_rect.y &&
212 + bevent->y < (hslider_rect.y + hslider_rect.height))
214 + priv->sb_drag_slider = TRUE;
215 + priv->sb_grab_offset_x = bevent->x - hslider_rect.x;
219 + priv->sb_drag_slider = FALSE;
220 + priv->sb_grab_offset_x = bevent->x - hbar_rect.x;
222 + if (bevent->x < hslider_rect.x)
223 + priv->sb_scroll_direction = -1;
225 + priv->sb_scroll_direction = 1;
229 + if ((priv->sb_grab_vscroll || priv->sb_grab_hscroll) &&
230 + !priv->sb_drag_slider)
232 + gtk_scrolled_window_scroll_step (scrolled_window);
234 + priv->sb_scroll_timeout_id =
235 + gdk_threads_add_timeout (SCROLL_INTERVAL_INITIAL,
236 + gtk_scrolled_window_scroll_step_timeout,
247 +gtk_scrolled_window_captured_button_release_scrollbar (GtkWidget *widget,
250 + GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
251 + GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
252 + GdkEventButton *bevent = (GdkEventButton *) event;
254 + if (bevent->button != 1)
257 + gtk_grab_remove (widget);
258 + priv->sb_pointer_grabbed = FALSE;
260 + if (priv->sb_scroll_timeout_id)
262 + g_source_remove (priv->sb_scroll_timeout_id);
263 + priv->sb_scroll_timeout_id = 0;
270 +gtk_scrolled_window_captured_motion_notify_scrollbar (GtkWidget *widget,
273 + GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
274 + GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
275 + GdkEventMotion *mevent = (GdkEventMotion *) event;
277 + if (priv->sb_pointer_grabbed)
279 + if (priv->sb_drag_slider)
281 + GdkRectangle vbar_rect;
282 + GdkRectangle vslider_rect;
283 + GdkRectangle hbar_rect;
284 + GdkRectangle hslider_rect;
285 + GtkAdjustment *adj;
287 + gint visible_range;
290 + gtk_scrolled_window_get_child_scroll_areas (scrolled_window,
291 + gtk_bin_get_child (GTK_BIN (widget)),
293 + &vbar_rect, &vslider_rect,
294 + &hbar_rect, &hslider_rect);
296 + if (priv->sb_grab_vscroll)
298 + adj = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar));
299 + pos = mevent->y - priv->sb_grab_offset_y - vbar_rect.y;
300 + visible_range = vbar_rect.height - vslider_rect.height;
302 + else if (priv->sb_grab_hscroll)
304 + adj = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar));
305 + pos = mevent->x - priv->sb_grab_offset_x - hbar_rect.x;
306 + visible_range = hbar_rect.width - hslider_rect.width;
309 + pos = CLAMP (pos, 0, visible_range);
311 + value = (adj->upper - adj->page_size - adj->lower) * pos / visible_range;
313 + gtk_adjustment_set_value (adj, value);
320 + if (gtk_scrolled_window_over_child_scroll_areas (scrolled_window, event,
321 + mevent->x, mevent->y,
324 + priv->sb_hovering = TRUE;
325 + priv->sb_visible = TRUE;
327 + gtk_scrolled_window_start_fade_in_animation (scrolled_window);
328 + gtk_scrolled_window_stop_fade_out_timeout (scrolled_window);
330 + /* needed when entering the scrollbar */
331 + gtk_scrolled_window_expose_scrollbars (NULL, scrolled_window);
336 + priv->sb_hovering = FALSE;
338 + if (priv->sb_visible || gtk_adjustment_get_value (priv->opacity) > 0.0)
340 + /* keep visible scrollbars visible while the mouse is moving */
341 + gtk_scrolled_window_start_fade_in_animation (scrolled_window);
342 + gtk_scrolled_window_stop_fade_out_timeout (scrolled_window);
343 + gtk_scrolled_window_start_fade_out_timeout (scrolled_window);
351 gtk_scrolled_window_captured_event (GtkWidget *widget,
354 - gboolean retval = FALSE;
355 + GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
356 GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (widget);
357 + gboolean retval = FALSE;
361 case GDK_BUTTON_PRESS:
362 - retval = gtk_scrolled_window_captured_button_press (widget, event);
363 + retval = gtk_scrolled_window_captured_button_press_scrollbar (widget, event);
365 + retval = gtk_scrolled_window_captured_button_press_kinetic (widget, event);
367 case GDK_BUTTON_RELEASE:
368 - if (priv->pointer_grabbed)
369 - retval = gtk_scrolled_window_captured_button_release (widget, event);
370 + if (priv->sb_pointer_grabbed)
371 + retval = gtk_scrolled_window_captured_button_release_scrollbar (widget, event);
372 + else if (priv->pointer_grabbed)
373 + retval = gtk_scrolled_window_captured_button_release_kinetic (widget, event);
375 priv->last_button_event_valid = FALSE;
377 case GDK_MOTION_NOTIFY:
378 - if (priv->pointer_grabbed)
379 - retval = gtk_scrolled_window_captured_motion_notify (widget, event);
380 + if (priv->sb_pointer_grabbed || !priv->pointer_grabbed)
381 + retval = gtk_scrolled_window_captured_motion_notify_scrollbar (widget, event);
382 + else if (priv->pointer_grabbed)
383 + retval = gtk_scrolled_window_captured_motion_notify_kinetic (widget, event);
385 case GDK_LEAVE_NOTIFY:
386 + if (!priv->in_drag && !priv->sb_pointer_grabbed)
388 + gtk_scrolled_window_start_fade_out_timeout (scrolled_window);
389 + priv->sb_hovering = FALSE;
391 case GDK_ENTER_NOTIFY:
393 event->crossing.mode != GDK_CROSSING_GRAB)
394 @@ -3016,6 +3303,17 @@ gtk_scrolled_window_grab_notify (GtkWidget *widget,
396 priv->last_button_event_valid = FALSE;
399 + if (priv->sb_pointer_grabbed && !was_grabbed)
401 + priv->sb_pointer_grabbed = FALSE;
403 + if (priv->sb_scroll_timeout_id)
405 + g_source_remove (priv->sb_scroll_timeout_id);
406 + priv->sb_scroll_timeout_id = 0;
412 @@ -3057,6 +3355,56 @@ gtk_scrolled_window_rounded_rectangle (cairo_t *cr,
413 cairo_close_path (cr);
417 +gtk_scrolled_window_over_child_scroll_areas (GtkScrolledWindow *scrolled_window,
421 + gboolean *over_vscroll,
422 + gboolean *over_hscroll)
424 + GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
426 + GdkRectangle vbar_rect;
427 + GdkRectangle hbar_rect;
428 + gboolean over_v = FALSE;
429 + gboolean over_h = FALSE;
431 + child = gtk_bin_get_child (GTK_BIN (scrolled_window));
435 + if (gtk_get_event_widget (event) != child)
438 + if (gtk_adjustment_get_value (priv->opacity) == 0.0)
441 + gtk_scrolled_window_get_child_scroll_areas (scrolled_window,
443 + ((GdkEventAny *) event)->window,
447 + if (vbar_rect.width > 0 &&
448 + x >= vbar_rect.x && x < (vbar_rect.x + vbar_rect.width) &&
449 + y >= vbar_rect.y && y < (vbar_rect.y + vbar_rect.height))
453 + else if (hbar_rect.width > 0 &&
454 + x >= hbar_rect.x && x < (hbar_rect.x + hbar_rect.width) &&
455 + y >= hbar_rect.y && y < (hbar_rect.y + hbar_rect.height))
460 + if (over_vscroll) *over_vscroll = over_v;
461 + if (over_hscroll) *over_hscroll = over_h;
463 + return over_v || over_h;
467 gtk_scrolled_window_get_child_scroll_areas (GtkScrolledWindow *scrolled_window,
469 @@ -3083,6 +3431,8 @@ gtk_scrolled_window_get_child_scroll_areas (GtkScrolledWindow *scrolled_window,
472 gint viewport_height;
476 window_width = gdk_window_get_width (child_window);
477 window_height = gdk_window_get_height (child_window);
478 @@ -3106,6 +3456,12 @@ gtk_scrolled_window_get_child_scroll_areas (GtkScrolledWindow *scrolled_window,
479 value_h = gtk_adjustment_get_value (adj);
482 + if (window_width > allocation.width)
483 + offset_x = value_h;
485 + if (window_height > allocation.height)
486 + offset_y = value_v;
488 if ((vbar_rect || vslider_rect) && scrolled_window->vscrollbar)
490 adj = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar));
491 @@ -3127,16 +3483,13 @@ gtk_scrolled_window_get_child_scroll_areas (GtkScrolledWindow *scrolled_window,
492 y = ratio * (viewport_height - (2 * priv->sb_padding) - height) + priv->sb_padding;
493 x = viewport_width - priv->sb_width - priv->sb_padding;
495 - if (window_width > allocation.width)
498 - if (window_height > allocation.height)
505 vbar_rect->x = x - priv->sb_padding;
507 + vbar_rect->y = offset_y;
508 vbar_rect->width = priv->sb_width + 2 * priv->sb_padding;
509 vbar_rect->height = viewport_height;
511 @@ -3190,15 +3543,12 @@ gtk_scrolled_window_get_child_scroll_areas (GtkScrolledWindow *scrolled_window,
512 x = ratio * (viewport_width - (2 * priv->sb_padding) - width) + priv->sb_padding;
513 y = viewport_height - priv->sb_width - priv->sb_padding;
515 - if (window_width > allocation.width)
518 - if (window_height > allocation.height)
526 + hbar_rect->x = offset_x;
527 hbar_rect->y = y - priv->sb_padding;
528 hbar_rect->width = viewport_width;
529 hbar_rect->height = priv->sb_width + 2 * priv->sb_padding;
530 @@ -3255,7 +3605,7 @@ gtk_scrolled_window_child_expose (GtkWidget *widget,
531 &vbar_rect, &vslider_rect,
532 &hbar_rect, &hslider_rect);
535 + if (priv->sb_visible)
537 if (scrolled_window->vscrollbar && vbar_rect.width > 0)
538 gdk_cairo_rectangle (cr, &vbar_rect);
539 @@ -3263,7 +3613,7 @@ gtk_scrolled_window_child_expose (GtkWidget *widget,
540 if (scrolled_window->hscrollbar && hbar_rect.width > 0)
541 gdk_cairo_rectangle (cr, &hbar_rect);
543 - cairo_set_source_rgba (cr, 0, 0, 0, 0.2);
544 + cairo_set_source_rgba (cr, 0, 0, 0, gtk_adjustment_get_value (priv->opacity) / 2.0);
548 @@ -3307,11 +3657,7 @@ gtk_scrolled_window_cancel_animation (GtkScrolledWindow *scrolled_window)
549 _gb_animation_stop (anim);
552 - if (priv->sb_fade_out_id)
554 - g_source_remove (priv->sb_fade_out_id);
555 - priv->sb_fade_out_id = 0;
557 + gtk_scrolled_window_stop_fade_out_timeout (scrolled_window);
559 priv->sb_fading_in = FALSE;
561 @@ -3325,6 +3671,30 @@ gtk_scrolled_window_fade_out_timeout (GtkScrolledWindow *scrolled_window)
565 +gtk_scrolled_window_start_fade_out_timeout (GtkScrolledWindow *scrolled_window)
567 + GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
569 + if (! priv->sb_fade_out_id)
570 + priv->sb_fade_out_id =
571 + gdk_threads_add_timeout (priv->sb_fade_out_delay,
572 + (GSourceFunc) gtk_scrolled_window_fade_out_timeout,
577 +gtk_scrolled_window_stop_fade_out_timeout (GtkScrolledWindow *scrolled_window)
579 + GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
581 + if (priv->sb_fade_out_id)
583 + g_source_remove (priv->sb_fade_out_id);
584 + priv->sb_fade_out_id = 0;
589 gtk_scrolled_window_start_fade_in_animation (GtkScrolledWindow *scrolled_window)
591 GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
592 @@ -3336,6 +3706,7 @@ gtk_scrolled_window_start_fade_in_animation (GtkScrolledWindow *scrolled_window)
593 gtk_scrolled_window_cancel_animation (scrolled_window);
595 priv->sb_fading_in = TRUE;
596 + priv->sb_visible = priv->sb_hovering;
598 upper = gtk_adjustment_get_upper (priv->opacity);
599 priv->opacity_anim = _gb_object_animate (priv->opacity,
600 @@ -3346,10 +3717,7 @@ gtk_scrolled_window_start_fade_in_animation (GtkScrolledWindow *scrolled_window)
601 g_object_add_weak_pointer (G_OBJECT (priv->opacity_anim),
602 (gpointer *) &priv->opacity_anim);
604 - priv->sb_fade_out_id =
605 - gdk_threads_add_timeout (priv->sb_fade_out_delay,
606 - (GSourceFunc) gtk_scrolled_window_fade_out_timeout,
608 + gtk_scrolled_window_start_fade_out_timeout (scrolled_window);
613 1.7.10.2 (Apple Git-33)