Merge lp:~cimi/overlay-scrollbar/new-thumb-functionalities into lp:overlay-scrollbar

Proposed by Andrea Cimitan
Status: Merged
Merged at revision: 311
Proposed branch: lp:~cimi/overlay-scrollbar/new-thumb-functionalities
Merge into: lp:overlay-scrollbar
Diff against target: 4177 lines (+1568/-1308)
5 files modified
os/Makefile.am (+1/-1)
os/os-bar.c (+454/-355)
os/os-private.h (+63/-53)
os/os-scrollbar.c (+1008/-866)
os/os-thumb.c (+42/-33)
To merge this branch: bzr merge lp:~cimi/overlay-scrollbar/new-thumb-functionalities
Reviewer Review Type Date Requested Status
Ted Gould (community) Approve
Review via email: mp+79140@code.launchpad.net

Description of the change

Big changes... are you really sure you want to review that? :-)

To post a comment you must log in.
Revision history for this message
Marco Trevisan (Treviño) (3v1n0) wrote :

I do :)

Revision history for this message
Marco Trevisan (Treviño) (3v1n0) wrote :

From an usability point of view I'd reduce the value of TIMEOUT_THUMB_SHOW to 50ms. It seems better here.

Revision history for this message
Andrea Cimitan (cimi) wrote :

Marco, I'm thinking about increasing it to 150 :-) Please notice that the timeout is not respected when the thumb is touching the screen edge.

Anyway, the branch is still in progress :-) Not ready for review (see the "Status"!)

Revision history for this message
Ted Gould (ted) wrote :

In general, I'm a little uncomfortable with all the bit twittling for the state variable. I think that you should put that into its own function. Two reasons, it's easy to mess up. And it seems to be likely someplace you'll want to put a g_debug() statement when things are going wrong.

Also, the diffs would be a lot smaller if the name changes weren't included with the logic changes. I think next time you should split those out into two different merge requests.

Other than that, it was a big diff! :-) I didn't see anything on a general read through.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'os/Makefile.am'
2--- os/Makefile.am 2011-10-05 12:24:21 +0000
3+++ os/Makefile.am 2011-10-12 17:16:23 +0000
4@@ -16,8 +16,8 @@
5
6 source_c = \
7 $(srcdir)/os-animation.c \
8+ $(srcdir)/os-bar.c \
9 $(srcdir)/os-log.c \
10- $(srcdir)/os-pager.c \
11 $(srcdir)/os-scrollbar.c \
12 $(srcdir)/os-thumb.c \
13 $(srcdir)/os-utils.c
14
15=== renamed file 'os/os-pager.c' => 'os/os-bar.c'
16--- os/os-pager.c 2011-10-05 12:24:21 +0000
17+++ os/os-bar.c 2011-10-12 17:16:23 +0000
18@@ -29,78 +29,45 @@
19 #include <cairo-xlib.h>
20 #include <gdk/gdkx.h>
21
22-/* Rate of the fade. */
23-#define RATE_FADE 30
24-
25 /* Duration of the fade-in. */
26 #define DURATION_FADE_IN 200
27
28 /* Duration of the fade-out. */
29 #define DURATION_FADE_OUT 400
30
31+/* Max duration of the retracting tail. */
32+#define MAX_DURATION_TAIL 600
33+
34+/* Min duration of the retracting tail. */
35+#define MIN_DURATION_TAIL 100
36+
37 #ifdef USE_GTK3
38 #define SHAPE_REGION(x) (cairo_region_create_rectangle (x))
39 #else
40 #define SHAPE_REGION(x) (gdk_region_rectangle (x))
41 #endif
42
43-struct _OsPagerPrivate {
44- GdkWindow *pager_window;
45- GdkWindow *connection_window;
46+struct _OsBarPrivate {
47+ GdkRectangle bar_mask;
48+ GdkRectangle tail_mask; /* In theory not needed, but easier to read. */
49+ GdkRectangle allocation;
50+ GdkWindow *bar_window;
51+ GdkWindow *tail_window;
52 GtkWidget *parent;
53- GdkRectangle mask;
54- GdkRectangle connection_mask; /* In theory not needed, but easier to read. */
55- GdkRectangle allocation;
56- OsAnimation *animation;
57+ OsAnimation *state_animation;
58+ OsAnimation *tail_animation;
59 gboolean active;
60 gboolean detached;
61 gboolean visible;
62 gfloat weight;
63- gulong handler_id;
64 };
65
66-static void os_pager_dispose (GObject *object);
67-static void os_pager_finalize (GObject *object);
68-
69-/* Draw on the connection_window. */
70-static void
71-draw_connection (OsPager *pager)
72-{
73-#ifdef USE_GTK3
74- GdkRGBA color;
75- GtkStyleContext *style_context;
76-#else
77- GdkColor color;
78- GtkStyle *style;
79-#endif
80- OsPagerPrivate *priv;
81-
82- priv = pager->priv;
83-
84-#ifdef USE_GTK3
85- style_context = gtk_widget_get_style_context (priv->parent);
86-
87- gtk_style_context_get_background_color (style_context, GTK_STATE_FLAG_ACTIVE, &color);
88-
89- color.alpha = 1.0;
90-
91- gdk_window_set_background_rgba (priv->connection_window, &color);
92-#else
93- style = gtk_widget_get_style (priv->parent);
94-
95- color = style->bg[GTK_STATE_ACTIVE];
96-
97- gdk_colormap_alloc_color (gdk_drawable_get_colormap (priv->connection_window), &color, FALSE, TRUE);
98-
99- gdk_window_set_background (priv->connection_window, &color);
100-#endif
101-
102- gdk_window_invalidate_rect (gtk_widget_get_window (priv->parent), &priv->allocation, TRUE);
103-}
104-
105-/* Draw on the pager_window. */
106-static void
107-draw_pager (OsPager *pager)
108+static void os_bar_dispose (GObject *object);
109+static void os_bar_finalize (GObject *object);
110+
111+/* Draw on the bar_window. */
112+static void
113+draw_bar (OsBar *bar)
114 {
115 #ifdef USE_GTK3
116 GdkRGBA c1, c2, color;
117@@ -109,10 +76,10 @@
118 GdkColor c1, c2, color;
119 GtkStyle *style;
120 #endif
121- OsPagerPrivate *priv;
122+ OsBarPrivate *priv;
123 gfloat weight;
124
125- priv = pager->priv;
126+ priv = bar->priv;
127
128 weight = priv->weight;
129
130@@ -135,7 +102,7 @@
131 color.blue = weight * c1.blue + (1.0 - weight) * c2.blue;
132 color.alpha = 1.0;
133
134- gdk_window_set_background_rgba (priv->pager_window, &color);
135+ gdk_window_set_background_rgba (priv->bar_window, &color);
136 #else
137 style = gtk_widget_get_style (priv->parent);
138
139@@ -154,9 +121,45 @@
140 color.green = weight * c1.green + (1.0 - weight) * c2.green;
141 color.blue = weight * c1.blue + (1.0 - weight) * c2.blue;
142
143- gdk_colormap_alloc_color (gdk_drawable_get_colormap (priv->pager_window), &color, FALSE, TRUE);
144-
145- gdk_window_set_background (priv->pager_window, &color);
146+ gdk_colormap_alloc_color (gdk_drawable_get_colormap (priv->bar_window), &color, FALSE, TRUE);
147+
148+ gdk_window_set_background (priv->bar_window, &color);
149+#endif
150+
151+ gdk_window_invalidate_rect (gtk_widget_get_window (priv->parent), &priv->allocation, TRUE);
152+}
153+
154+/* Draw on the tail_window. */
155+static void
156+draw_tail (OsBar *bar)
157+{
158+#ifdef USE_GTK3
159+ GdkRGBA color;
160+ GtkStyleContext *style_context;
161+#else
162+ GdkColor color;
163+ GtkStyle *style;
164+#endif
165+ OsBarPrivate *priv;
166+
167+ priv = bar->priv;
168+
169+#ifdef USE_GTK3
170+ style_context = gtk_widget_get_style_context (priv->parent);
171+
172+ gtk_style_context_get_background_color (style_context, GTK_STATE_FLAG_ACTIVE, &color);
173+
174+ color.alpha = 1.0;
175+
176+ gdk_window_set_background_rgba (priv->tail_window, &color);
177+#else
178+ style = gtk_widget_get_style (priv->parent);
179+
180+ color = style->bg[GTK_STATE_ACTIVE];
181+
182+ gdk_colormap_alloc_color (gdk_drawable_get_colormap (priv->tail_window), &color, FALSE, TRUE);
183+
184+ gdk_window_set_background (priv->tail_window, &color);
185 #endif
186
187 gdk_window_invalidate_rect (gtk_widget_get_window (priv->parent), &priv->allocation, TRUE);
188@@ -167,35 +170,35 @@
189 change_state_cb (gfloat weight,
190 gpointer user_data)
191 {
192- OsPager *pager;
193- OsPagerPrivate *priv;
194-
195- pager = OS_PAGER (user_data);
196-
197- priv = pager->priv;
198+ OsBar *bar;
199+ OsBarPrivate *priv;
200+
201+ bar = OS_BAR (user_data);
202+
203+ priv = bar->priv;
204
205 priv->weight = weight;
206
207 if (priv->parent == NULL)
208 return;
209
210- draw_pager (pager);
211+ draw_bar (bar);
212 }
213
214 /* Stop function called by the change-state animation. */
215 static void
216 change_state_stop_cb (gpointer user_data)
217 {
218- OsPager *pager;
219- OsPagerPrivate *priv;
220-
221- pager = OS_PAGER (user_data);
222-
223- priv = pager->priv;
224+ OsBar *bar;
225+ OsBarPrivate *priv;
226+
227+ bar = OS_BAR (user_data);
228+
229+ priv = bar->priv;
230
231 priv->weight = 1.0f;
232
233- draw_pager (pager);
234+ draw_bar (bar);
235 }
236
237 /* Callback called when the Gtk+ theme changes. */
238@@ -204,19 +207,19 @@
239 GParamSpec* pspec,
240 gpointer user_data)
241 {
242- OsPager *pager;
243- OsPagerPrivate *priv;
244+ OsBar *bar;
245+ OsBarPrivate *priv;
246
247- pager = OS_PAGER (user_data);
248- priv = pager->priv;
249+ bar = OS_BAR (user_data);
250+ priv = bar->priv;
251
252 if (priv->parent == NULL ||
253- priv->pager_window == NULL ||
254- priv->connection_window == NULL)
255+ priv->bar_window == NULL ||
256+ priv->tail_window == NULL)
257 return;
258
259- draw_connection (pager);
260- draw_pager (pager);
261+ draw_tail (bar);
262+ draw_bar (bar);
263 }
264
265 /* Check if two GdkRectangle are different. */
266@@ -232,29 +235,93 @@
267 return FALSE;
268 }
269
270-G_DEFINE_TYPE (OsPager, os_pager, G_TYPE_OBJECT);
271-
272-static void
273-os_pager_class_init (OsPagerClass *class)
274+/* Callback called by the retract-tail animation. */
275+static void
276+retract_tail_cb (gfloat weight,
277+ gpointer user_data)
278+{
279+ GdkRectangle tail_mask;
280+ OsBar *bar;
281+ OsBarPrivate *priv;
282+
283+ bar = OS_BAR (user_data);
284+
285+ priv = bar->priv;
286+
287+ if (priv->parent == NULL)
288+ return;
289+
290+ tail_mask = priv->tail_mask;
291+
292+ if (priv->allocation.height >= priv->allocation.width)
293+ {
294+ tail_mask.height = tail_mask.height * (1.0 - weight);
295+
296+ if (priv->tail_mask.y + priv->tail_mask.height < priv->bar_mask.y + priv->bar_mask.height)
297+ tail_mask.y = priv->tail_mask.y + priv->tail_mask.height - tail_mask.height;
298+ }
299+ else
300+ {
301+ tail_mask.width = tail_mask.width * (1.0 - weight);
302+
303+ if (priv->tail_mask.x + priv->tail_mask.width < priv->bar_mask.x + priv->bar_mask.width)
304+ tail_mask.x = priv->tail_mask.x + priv->tail_mask.width - tail_mask.width;
305+ }
306+
307+ if (weight < 1.0)
308+ gdk_window_shape_combine_region (priv->tail_window,
309+ SHAPE_REGION(&tail_mask),
310+ 0, 0);
311+ else
312+ {
313+ /* Store the new tail_mask and hide the tail_window. */
314+ priv->tail_mask = tail_mask;
315+ gdk_window_hide (priv->tail_window);
316+ }
317+}
318+
319+/* Stop function called by the retract-tail animation. */
320+static void
321+retract_tail_stop_cb (gpointer user_data)
322+{
323+ OsBar *bar;
324+ OsBarPrivate *priv;
325+
326+ bar = OS_BAR (user_data);
327+
328+ priv = bar->priv;
329+
330+ if (priv->parent == NULL)
331+ return;
332+
333+ gdk_window_shape_combine_region (priv->tail_window,
334+ SHAPE_REGION(&priv->tail_mask),
335+ 0, 0);
336+}
337+
338+G_DEFINE_TYPE (OsBar, os_bar, G_TYPE_OBJECT);
339+
340+static void
341+os_bar_class_init (OsBarClass *class)
342 {
343 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
344
345- gobject_class->dispose = os_pager_dispose;
346- gobject_class->finalize = os_pager_finalize;
347+ gobject_class->dispose = os_bar_dispose;
348+ gobject_class->finalize = os_bar_finalize;
349
350- g_type_class_add_private (gobject_class, sizeof (OsPagerPrivate));
351+ g_type_class_add_private (gobject_class, sizeof (OsBarPrivate));
352 }
353
354 static void
355-os_pager_init (OsPager *pager)
356+os_bar_init (OsBar *bar)
357 {
358 GdkRectangle allocation, mask;
359- OsPagerPrivate *priv;
360+ OsBarPrivate *priv;
361
362- pager->priv = G_TYPE_INSTANCE_GET_PRIVATE (pager,
363- OS_TYPE_PAGER,
364- OsPagerPrivate);
365- priv = pager->priv;
366+ bar->priv = G_TYPE_INSTANCE_GET_PRIVATE (bar,
367+ OS_TYPE_BAR,
368+ OsBarPrivate);
369+ priv = bar->priv;
370
371 allocation.x = 0;
372 allocation.y = 0;
373@@ -268,8 +335,8 @@
374 mask.width = 1;
375 mask.height = 1;
376
377- priv->connection_mask = mask;
378- priv->mask = mask;
379+ priv->bar_mask = mask;
380+ priv->tail_mask = mask;
381
382 priv->active = FALSE;
383 priv->detached = FALSE;
384@@ -277,217 +344,227 @@
385
386 priv->weight = 1.0f;
387
388- priv->animation = os_animation_new (RATE_FADE, DURATION_FADE_OUT,
389- change_state_cb, NULL, pager);
390-
391- priv->handler_id = g_signal_connect (gtk_settings_get_default (), "notify::gtk-theme-name",
392- G_CALLBACK (notify_gtk_theme_name_cb), pager);
393-}
394-
395-static void
396-os_pager_dispose (GObject *object)
397-{
398- OsPager *pager;
399- OsPagerPrivate *priv;
400-
401- pager = OS_PAGER (object);
402- priv = pager->priv;
403-
404- if (priv->animation != NULL)
405- {
406- g_object_unref (priv->animation);
407- priv->animation = NULL;
408- }
409-
410- if (priv->connection_window != NULL)
411- {
412- /* From the Gdk documentation:
413- * "Note that a window will not be destroyed
414- * automatically when its reference count
415- * reaches zero. You must call
416- * gdk_window_destroy ()
417- * yourself before that happens". */
418- gdk_window_destroy (priv->connection_window);
419-
420- g_object_unref (priv->connection_window);
421- priv->connection_window = NULL;
422- }
423-
424- if (priv->pager_window != NULL)
425- {
426- /* From the Gdk documentation:
427- * "Note that a window will not be destroyed
428- * automatically when its reference count
429- * reaches zero. You must call
430- * gdk_window_destroy ()
431- * yourself before that happens". */
432- gdk_window_destroy (priv->pager_window);
433-
434- g_object_unref (priv->pager_window);
435- priv->pager_window = NULL;
436- }
437-
438- os_pager_set_parent (pager, NULL);
439-
440- g_signal_handler_disconnect (gtk_settings_get_default (),
441- priv->handler_id);
442-
443- G_OBJECT_CLASS (os_pager_parent_class)->dispose (object);
444-}
445-
446-static void
447-os_pager_finalize (GObject *object)
448-{
449- G_OBJECT_CLASS (os_pager_parent_class)->finalize (object);
450+ priv->state_animation = os_animation_new (RATE_ANIMATION, DURATION_FADE_OUT,
451+ change_state_cb, NULL, bar);
452+ priv->tail_animation = os_animation_new (RATE_ANIMATION, MAX_DURATION_TAIL,
453+ retract_tail_cb, NULL, bar);
454+
455+ g_signal_connect (gtk_settings_get_default (), "notify::gtk-theme-name",
456+ G_CALLBACK (notify_gtk_theme_name_cb), bar);
457+}
458+
459+static void
460+os_bar_dispose (GObject *object)
461+{
462+ OsBar *bar;
463+ OsBarPrivate *priv;
464+
465+ bar = OS_BAR (object);
466+ priv = bar->priv;
467+
468+ if (priv->tail_animation != NULL)
469+ {
470+ g_object_unref (priv->tail_animation);
471+ priv->tail_animation = NULL;
472+ }
473+
474+ if (priv->state_animation != NULL)
475+ {
476+ g_object_unref (priv->state_animation);
477+ priv->state_animation = NULL;
478+ }
479+
480+ if (priv->tail_window != NULL)
481+ {
482+ /* From the Gdk documentation:
483+ * "Note that a window will not be destroyed
484+ * automatically when its reference count
485+ * reaches zero. You must call
486+ * gdk_window_destroy ()
487+ * yourself before that happens". */
488+ gdk_window_destroy (priv->tail_window);
489+
490+ g_object_unref (priv->tail_window);
491+ priv->tail_window = NULL;
492+ }
493+
494+ if (priv->bar_window != NULL)
495+ {
496+ /* From the Gdk documentation:
497+ * "Note that a window will not be destroyed
498+ * automatically when its reference count
499+ * reaches zero. You must call
500+ * gdk_window_destroy ()
501+ * yourself before that happens". */
502+ gdk_window_destroy (priv->bar_window);
503+
504+ g_object_unref (priv->bar_window);
505+ priv->bar_window = NULL;
506+ }
507+
508+ os_bar_set_parent (bar, NULL);
509+
510+ G_OBJECT_CLASS (os_bar_parent_class)->dispose (object);
511+}
512+
513+static void
514+os_bar_finalize (GObject *object)
515+{
516+ G_OBJECT_CLASS (os_bar_parent_class)->finalize (object);
517 }
518
519 /* Public functions. */
520
521 /**
522- * os_pager_new:
523- *
524- * Creates a new #OsPager instance.
525- *
526- * Returns: the new #OsPager instance.
527+ * os_bar_new:
528+ *
529+ * Creates a new #OsBar instance.
530+ *
531+ * Returns: the new #OsBar instance.
532 **/
533-OsPager*
534-os_pager_new (void)
535+OsBar*
536+os_bar_new (void)
537 {
538- return g_object_new (OS_TYPE_PAGER, NULL);
539+ return g_object_new (OS_TYPE_BAR, NULL);
540 }
541
542-/* Move a mask on the connection_window, fake movement. */
543+/* Move a mask on the tail_window, fake movement. */
544 static void
545-mask_connection (OsPager *pager)
546+mask_tail (OsBar *bar)
547 {
548- OsPagerPrivate *priv;
549-
550- priv = pager->priv;
551-
552- gdk_window_shape_combine_region (priv->connection_window,
553- SHAPE_REGION(&priv->connection_mask),
554+ OsBarPrivate *priv;
555+
556+ priv = bar->priv;
557+
558+ gdk_window_shape_combine_region (priv->tail_window,
559+ SHAPE_REGION(&priv->tail_mask),
560 0, 0);
561 }
562
563 /**
564- * os_pager_connect:
565- * @pager: a #OsPager
566- * @mask: a #GdkRectangle with the position and dimension of the connection
567- *
568- * Moves and resizes connection.
569- **/
570-void
571-os_pager_connect (OsPager *pager,
572- GdkRectangle mask)
573-{
574- OsPagerPrivate *priv;
575-
576- g_return_if_fail (OS_IS_PAGER (pager));
577-
578- priv = pager->priv;
579-
580- if (!rectangle_changed (priv->connection_mask, mask))
581- return;
582-
583- priv->connection_mask = mask;
584-
585- if (priv->parent == NULL)
586- return;
587-
588- mask_connection (pager);
589-}
590-
591-/**
592- * os_pager_hide:
593- * @pager: a #OsPager
594- *
595- * Hides the #OsPager.
596- **/
597-void
598-os_pager_hide (OsPager *pager)
599-{
600- OsPagerPrivate *priv;
601-
602- g_return_if_fail (OS_IS_PAGER (pager));
603-
604- priv = pager->priv;
605-
606- priv->visible = FALSE;
607-
608- if (priv->parent == NULL)
609+ * os_bar_connect:
610+ * @bar: a #OsBar
611+ * @mask: a #GdkRectangle with the position and dimension of the tail
612+ *
613+ * Moves and resizes tail.
614+ **/
615+void
616+os_bar_connect (OsBar *bar,
617+ GdkRectangle mask)
618+{
619+ OsBarPrivate *priv;
620+
621+ g_return_if_fail (OS_IS_BAR (bar));
622+
623+ priv = bar->priv;
624+
625+ if (!os_animation_is_running (priv->tail_animation) &&
626+ !rectangle_changed (priv->tail_mask, mask))
627 return;
628
629 /* If there's an animation currently running, stop it. */
630- os_animation_stop (priv->animation, change_state_stop_cb);
631-
632- gdk_window_hide (priv->connection_window);
633- gdk_window_hide (priv->pager_window);
634-}
635-
636-/* Move a mask on the pager_window, fake movement. */
637+ os_animation_stop (priv->tail_animation, NULL);
638+
639+ priv->tail_mask = mask;
640+
641+ if (priv->parent == NULL)
642+ return;
643+
644+ mask_tail (bar);
645+}
646+
647+/**
648+ * os_bar_hide:
649+ * @bar: a #OsBar
650+ *
651+ * Hides the #OsBar.
652+ **/
653+void
654+os_bar_hide (OsBar *bar)
655+{
656+ OsBarPrivate *priv;
657+
658+ g_return_if_fail (OS_IS_BAR (bar));
659+
660+ priv = bar->priv;
661+
662+ priv->visible = FALSE;
663+
664+ if (priv->parent == NULL)
665+ return;
666+
667+ /* Immediately hide, then stop animations. */
668+ gdk_window_hide (priv->tail_window);
669+ gdk_window_hide (priv->bar_window);
670+
671+ os_animation_stop (priv->tail_animation, retract_tail_stop_cb);
672+ os_animation_stop (priv->state_animation, change_state_stop_cb);
673+}
674+
675+/* Move a mask on the bar_window, fake movement. */
676 static void
677-mask_pager (OsPager *pager)
678+mask_bar (OsBar *bar)
679 {
680- OsPagerPrivate *priv;
681-
682- priv = pager->priv;
683-
684- gdk_window_shape_combine_region (priv->pager_window,
685- SHAPE_REGION(&priv->mask),
686+ OsBarPrivate *priv;
687+
688+ priv = bar->priv;
689+
690+ gdk_window_shape_combine_region (priv->bar_window,
691+ SHAPE_REGION(&priv->bar_mask),
692 0, 0);
693 }
694
695 /**
696- * os_pager_move_resize:
697- * @pager: a #OsPager
698- * @mask: a #GdkRectangle with the position and dimension of the #OsPager
699+ * os_bar_move_resize:
700+ * @bar: a #OsBar
701+ * @mask: a #GdkRectangle with the position and dimension of the #OsBar
702 *
703- * Moves and resizes @pager.
704+ * Moves and resizes @bar.
705 **/
706 void
707-os_pager_move_resize (OsPager *pager,
708- GdkRectangle mask)
709+os_bar_move_resize (OsBar *bar,
710+ GdkRectangle mask)
711 {
712- OsPagerPrivate *priv;
713-
714- g_return_if_fail (OS_IS_PAGER (pager));
715-
716- priv = pager->priv;
717-
718- if (!rectangle_changed (priv->mask, mask))
719+ OsBarPrivate *priv;
720+
721+ g_return_if_fail (OS_IS_BAR (bar));
722+
723+ priv = bar->priv;
724+
725+ if (!rectangle_changed (priv->bar_mask, mask))
726 return;
727
728- priv->mask = mask;
729+ priv->bar_mask = mask;
730
731 if (priv->parent == NULL)
732 return;
733
734- mask_pager (pager);
735+ mask_bar (bar);
736 }
737
738 /**
739- * os_pager_set_active:
740- * @pager: a #OsPager
741+ * os_bar_set_active:
742+ * @bar: a #OsBar
743 * @active: whether is active or not
744- * @animation: whether animate it or not
745+ * @animate: whether animate it or not
746 *
747- * Changes the activity state of @pager.
748+ * Changes the activity state of @bar.
749 **/
750 void
751-os_pager_set_active (OsPager *pager,
752- gboolean active,
753- gboolean animate)
754+os_bar_set_active (OsBar *bar,
755+ gboolean active,
756+ gboolean animate)
757 {
758- OsPagerPrivate *priv;
759-
760- g_return_if_fail (OS_IS_PAGER (pager));
761-
762- priv = pager->priv;
763-
764- /* Set the state and draw even if there's an animation running, that is
765- * (!animate && os_animation_is_running (priv->animation)). */
766+ OsBarPrivate *priv;
767+
768+ g_return_if_fail (OS_IS_BAR (bar));
769+
770+ priv = bar->priv;
771+
772+ /* Set the state and draw even if there's a state_animation running, that is
773+ * (!animate && os_animation_is_running (priv->state_animation)). */
774 if ((priv->active != active) ||
775- (!animate && os_animation_is_running (priv->animation)))
776+ (!animate && os_animation_is_running (priv->state_animation)))
777 {
778 gboolean visible;
779
780@@ -496,43 +573,45 @@
781 if (priv->parent == NULL)
782 return;
783
784- visible = gdk_window_is_visible (priv->pager_window);
785+ visible = gdk_window_is_visible (priv->bar_window);
786
787 if (visible)
788- os_animation_stop (priv->animation, NULL);
789+ os_animation_stop (priv->state_animation, NULL);
790
791 if (visible && animate)
792 {
793- os_animation_set_duration (priv->animation, priv->active ? DURATION_FADE_IN :
794- DURATION_FADE_OUT);
795- os_animation_start (priv->animation);
796+ os_animation_set_duration (priv->state_animation, priv->active ? DURATION_FADE_IN :
797+ DURATION_FADE_OUT);
798+ os_animation_start (priv->state_animation);
799 }
800
801 if (!visible || !animate)
802 {
803 priv->weight = 1.0f;
804
805- draw_pager (pager);
806+ draw_bar (bar);
807 }
808 }
809 }
810
811 /**
812- * os_pager_set_detached:
813- * @pager: a #OsPager
814- * @detached: whether the pager is detached or not
815+ * os_bar_set_detached:
816+ * @bar: a #OsBar
817+ * @detached: whether the bar is detached or not
818+ * @animate: whether animate it or not
819 *
820- * Changes the detached state of @pager.
821+ * Changes the detached state of @bar.
822 **/
823 void
824-os_pager_set_detached (OsPager *pager,
825- gboolean detached)
826+os_bar_set_detached (OsBar *bar,
827+ gboolean detached,
828+ gboolean animate)
829 {
830- OsPagerPrivate *priv;
831-
832- g_return_if_fail (OS_IS_PAGER (pager));
833-
834- priv = pager->priv;
835+ OsBarPrivate *priv;
836+
837+ g_return_if_fail (OS_IS_BAR (bar));
838+
839+ priv = bar->priv;
840
841 if (priv->detached != detached)
842 {
843@@ -543,27 +622,49 @@
844
845 if (priv->detached)
846 {
847- gdk_window_show (priv->connection_window);
848- gdk_window_raise (priv->pager_window);
849+ /* If there's a tail animation currently running, stop it. */
850+ os_animation_stop (priv->tail_animation, retract_tail_stop_cb);
851+
852+ /* No tail connection animation yet. */
853+ gdk_window_show (priv->tail_window);
854+ gdk_window_raise (priv->bar_window);
855+ }
856+ else if (animate)
857+ {
858+ gint32 duration;
859+
860+ /* The detached state should already stop this. */
861+ OS_DCHECK (!os_animation_is_running (priv->tail_animation));
862+
863+ /* Calculate and set the duration. */
864+ if (priv->allocation.height >= priv->allocation.width)
865+ duration = MIN_DURATION_TAIL + ((gdouble) priv->tail_mask.height / priv->allocation.height) *
866+ (MAX_DURATION_TAIL - MIN_DURATION_TAIL);
867+ else
868+ duration = MIN_DURATION_TAIL + ((gdouble) priv->tail_mask.width / priv->allocation.width) *
869+ (MAX_DURATION_TAIL - MIN_DURATION_TAIL);
870+ os_animation_set_duration (priv->tail_animation, duration);
871+
872+ os_animation_start (priv->tail_animation);
873 }
874 else
875- gdk_window_hide (priv->connection_window);
876+ gdk_window_hide (priv->tail_window);
877 }
878 }
879
880-/* Create connection_window and pager_window. */
881+/* Create tail_window and bar_window. */
882 static void
883-create_windows (OsPager *pager)
884+create_windows (OsBar *bar)
885 {
886 GdkWindowAttr attributes;
887- OsPagerPrivate *priv;
888+ OsBarPrivate *priv;
889
890- priv = pager->priv;
891+ priv = bar->priv;
892
893 /* Instead reparenting,
894 * which doesn't seem to work well,
895 * destroy the two windows. */
896- if (priv->connection_window != NULL)
897+ if (priv->tail_window != NULL)
898 {
899 /* From the Gdk documentation:
900 * "Note that a window will not be destroyed
901@@ -571,13 +672,13 @@
902 * reaches zero. You must call
903 * gdk_window_destroy ()
904 * yourself before that happens". */
905- gdk_window_destroy (priv->connection_window);
906+ gdk_window_destroy (priv->tail_window);
907
908- g_object_unref (priv->connection_window);
909- priv->connection_window = NULL;
910+ g_object_unref (priv->tail_window);
911+ priv->tail_window = NULL;
912 }
913
914- if (priv->pager_window != NULL)
915+ if (priv->bar_window != NULL)
916 {
917 /* From the Gdk documentation:
918 * "Note that a window will not be destroyed
919@@ -585,10 +686,10 @@
920 * reaches zero. You must call
921 * gdk_window_destroy ()
922 * yourself before that happens". */
923- gdk_window_destroy (priv->pager_window);
924+ gdk_window_destroy (priv->bar_window);
925
926- g_object_unref (priv->pager_window);
927- priv->pager_window = NULL;
928+ g_object_unref (priv->bar_window);
929+ priv->bar_window = NULL;
930 }
931
932 attributes.event_mask = 0;
933@@ -601,8 +702,8 @@
934 attributes.colormap = gtk_widget_get_colormap (priv->parent);
935 #endif
936
937- /* connection_window. */
938- priv->connection_window = gdk_window_new (gtk_widget_get_window (priv->parent),
939+ /* tail_window. */
940+ priv->tail_window = gdk_window_new (gtk_widget_get_window (priv->parent),
941 &attributes,
942 #ifdef USE_GTK3
943 GDK_WA_VISUAL);
944@@ -610,13 +711,13 @@
945 GDK_WA_VISUAL | GDK_WA_COLORMAP);
946 #endif
947
948- g_object_ref_sink (priv->connection_window);
949+ g_object_ref_sink (priv->tail_window);
950
951- gdk_window_set_transient_for (priv->connection_window,
952+ gdk_window_set_transient_for (priv->tail_window,
953 gtk_widget_get_window (priv->parent));
954
955 /* FIXME(Cimi) maybe this is not required with 0 as event mask. */
956- gdk_window_input_shape_combine_region (priv->connection_window,
957+ gdk_window_input_shape_combine_region (priv->tail_window,
958 #ifdef USE_GTK3
959 cairo_region_create (),
960 #else
961@@ -624,22 +725,22 @@
962 #endif
963 0, 0);
964
965- /* pager_window. */
966- priv->pager_window = gdk_window_new (gtk_widget_get_window (priv->parent),
967- &attributes,
968+ /* bar_window. */
969+ priv->bar_window = gdk_window_new (gtk_widget_get_window (priv->parent),
970+ &attributes,
971 #ifdef USE_GTK3
972- GDK_WA_VISUAL);
973+ GDK_WA_VISUAL);
974 #else
975- GDK_WA_VISUAL | GDK_WA_COLORMAP);
976+ GDK_WA_VISUAL | GDK_WA_COLORMAP);
977 #endif
978
979- g_object_ref_sink (priv->pager_window);
980+ g_object_ref_sink (priv->bar_window);
981
982- gdk_window_set_transient_for (priv->pager_window,
983+ gdk_window_set_transient_for (priv->bar_window,
984 gtk_widget_get_window (priv->parent));
985
986 /* FIXME(Cimi) maybe this is not required with 0 as event mask. */
987- gdk_window_input_shape_combine_region (priv->pager_window,
988+ gdk_window_input_shape_combine_region (priv->bar_window,
989 #ifdef USE_GTK3
990 cairo_region_create (),
991 #else
992@@ -649,30 +750,30 @@
993 }
994
995 /**
996- * os_pager_set_parent:
997- * @pager: a #OsPager
998+ * os_bar_set_parent:
999+ * @bar: a #OsBar
1000 * @parent: a #GtkWidget
1001 *
1002 * Sets the parent widget
1003 **/
1004 void
1005-os_pager_set_parent (OsPager *pager,
1006- GtkWidget *parent)
1007+os_bar_set_parent (OsBar *bar,
1008+ GtkWidget *parent)
1009 {
1010- OsPagerPrivate *priv;
1011-
1012- g_return_if_fail (OS_IS_PAGER (pager));
1013-
1014- priv = pager->priv;
1015-
1016- /* Stop currently running animation. */
1017- if (priv->animation != NULL)
1018- os_animation_stop (priv->animation, NULL);
1019+ OsBarPrivate *priv;
1020+
1021+ g_return_if_fail (OS_IS_BAR (bar));
1022+
1023+ priv = bar->priv;
1024+
1025+ /* Stop currently running animations. */
1026+ if (priv->tail_animation != NULL)
1027+ os_animation_stop (priv->tail_animation, retract_tail_stop_cb);
1028+ if (priv->state_animation != NULL)
1029+ os_animation_stop (priv->state_animation, NULL);
1030
1031 if (priv->parent != NULL)
1032- {
1033- g_object_unref (priv->parent);
1034- }
1035+ g_object_unref (priv->parent);
1036
1037 priv->parent = parent;
1038
1039@@ -682,69 +783,67 @@
1040
1041 priv->weight = 1.0f;
1042
1043- create_windows (pager);
1044- draw_connection (pager);
1045- draw_pager (pager);
1046- mask_pager (pager);
1047+ create_windows (bar);
1048+ draw_tail (bar);
1049+ draw_bar (bar);
1050+ mask_bar (bar);
1051
1052- gdk_window_move_resize (priv->connection_window,
1053+ gdk_window_move_resize (priv->tail_window,
1054 priv->allocation.x,
1055 priv->allocation.y,
1056 priv->allocation.width,
1057 priv->allocation.height);
1058
1059- gdk_window_move_resize (priv->pager_window,
1060+ gdk_window_move_resize (priv->bar_window,
1061 priv->allocation.x,
1062 priv->allocation.y,
1063 priv->allocation.width,
1064 priv->allocation.height);
1065
1066 if (priv->visible)
1067- {
1068- gdk_window_show (priv->pager_window);
1069- }
1070+ gdk_window_show (priv->bar_window);
1071 }
1072 }
1073
1074 /**
1075- * os_pager_show:
1076- * @pager: a #OsPager
1077+ * os_bar_show:
1078+ * @bar: a #OsBar
1079 *
1080- * Shows @pager.
1081+ * Shows @bar.
1082 **/
1083 void
1084-os_pager_show (OsPager *pager)
1085+os_bar_show (OsBar *bar)
1086 {
1087- OsPagerPrivate *priv;
1088-
1089- g_return_if_fail (OS_IS_PAGER (pager));
1090-
1091- priv = pager->priv;
1092+ OsBarPrivate *priv;
1093+
1094+ g_return_if_fail (OS_IS_BAR (bar));
1095+
1096+ priv = bar->priv;
1097
1098 priv->visible = TRUE;
1099
1100 if (priv->parent == NULL)
1101 return;
1102
1103- gdk_window_show (priv->pager_window);
1104+ gdk_window_show (priv->bar_window);
1105 }
1106
1107 /**
1108- * os_pager_size_allocate:
1109- * @pager: a #OsPager
1110+ * os_bar_size_allocate:
1111+ * @bar: a #OsBar
1112 * @rectangle: a #GdkRectangle
1113 *
1114 * Sets the position and dimension of the whole area.
1115 **/
1116 void
1117-os_pager_size_allocate (OsPager *pager,
1118- GdkRectangle rectangle)
1119+os_bar_size_allocate (OsBar *bar,
1120+ GdkRectangle rectangle)
1121 {
1122- OsPagerPrivate *priv;
1123-
1124- g_return_if_fail (OS_IS_PAGER (pager));
1125-
1126- priv = pager->priv;
1127+ OsBarPrivate *priv;
1128+
1129+ g_return_if_fail (OS_IS_BAR (bar));
1130+
1131+ priv = bar->priv;
1132
1133 if (!rectangle_changed (priv->allocation, rectangle))
1134 return;
1135@@ -754,13 +853,13 @@
1136 if (priv->parent == NULL)
1137 return;
1138
1139- gdk_window_move_resize (priv->connection_window,
1140+ gdk_window_move_resize (priv->tail_window,
1141 rectangle.x,
1142 rectangle.y,
1143 rectangle.width,
1144 rectangle.height);
1145
1146- gdk_window_move_resize (priv->pager_window,
1147+ gdk_window_move_resize (priv->bar_window,
1148 rectangle.x,
1149 rectangle.y,
1150 rectangle.width,
1151
1152=== modified file 'os/os-private.h'
1153--- os/os-private.h 2011-10-05 12:24:21 +0000
1154+++ os/os-private.h 2011-10-12 17:16:23 +0000
1155@@ -30,7 +30,11 @@
1156 #pragma GCC visibility push(hidden)
1157 #endif /* __GNUC__ */
1158
1159+/* Rate of the animations (frames per second). */
1160+#define RATE_ANIMATION 30
1161+
1162 /* Size of the thumb in pixels. */
1163+#define MIN_THUMB_HEIGHT 35
1164 #define THUMB_WIDTH 17
1165 #define THUMB_HEIGHT 69
1166
1167@@ -39,14 +43,19 @@
1168
1169 G_BEGIN_DECLS
1170
1171+typedef struct
1172+{
1173+ gint x;
1174+ gint y;
1175+} OsCoordinate;
1176+
1177 typedef enum
1178 {
1179 OS_EVENT_NONE = 0,
1180 OS_EVENT_BUTTON_PRESS = 1,
1181 OS_EVENT_ENTER_NOTIFY = 2,
1182- OS_EVENT_MOTION_NOTIFY = 4,
1183- OS_EVENT_VALUE_CHANGED = 8
1184-} OsEvent;
1185+ OS_EVENT_MOTION_NOTIFY = 4
1186+} OsEventFlags;
1187
1188 /* os-log.c */
1189
1190@@ -150,6 +159,57 @@
1191 void os_animation_stop (OsAnimation *animation,
1192 OsAnimationStopFunc stop_func);
1193
1194+/* os-bar.c */
1195+
1196+#define OS_TYPE_BAR (os_bar_get_type ())
1197+#define OS_BAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), OS_TYPE_BAR, OsBar))
1198+#define OS_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), OS_TYPE_BAR, OsBarClass))
1199+#define OS_IS_BAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), OS_TYPE_BAR))
1200+#define OS_IS_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), OS_TYPE_BAR))
1201+#define OS_BAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), OS_TYPE_BAR, OsBarClass))
1202+
1203+typedef struct _OsBar OsBar;
1204+typedef struct _OsBarClass OsBarClass;
1205+typedef struct _OsBarPrivate OsBarPrivate;
1206+
1207+struct _OsBar {
1208+ GObject parent_instance;
1209+
1210+ OsBarPrivate *priv;
1211+};
1212+
1213+struct _OsBarClass {
1214+ GObjectClass parent_class;
1215+};
1216+
1217+GType os_bar_get_type (void) G_GNUC_CONST;
1218+
1219+OsBar* os_bar_new (void);
1220+
1221+void os_bar_hide (OsBar *bar);
1222+
1223+void os_bar_connect (OsBar *bar,
1224+ GdkRectangle mask);
1225+
1226+void os_bar_move_resize (OsBar *bar,
1227+ GdkRectangle mask);
1228+
1229+void os_bar_set_active (OsBar *bar,
1230+ gboolean active,
1231+ gboolean animate);
1232+
1233+void os_bar_set_detached (OsBar *bar,
1234+ gboolean detached,
1235+ gboolean animate);
1236+
1237+void os_bar_set_parent (OsBar *bar,
1238+ GtkWidget *parent);
1239+
1240+void os_bar_show (OsBar *bar);
1241+
1242+void os_bar_size_allocate (OsBar *bar,
1243+ GdkRectangle rectangle);
1244+
1245 /* os-thumb.c */
1246
1247 #define OS_TYPE_THUMB (os_thumb_get_type ())
1248@@ -184,56 +244,6 @@
1249 void os_thumb_set_detached (OsThumb *thumb,
1250 gboolean detached);
1251
1252-/* os-pager.c */
1253-
1254-#define OS_TYPE_PAGER (os_pager_get_type ())
1255-#define OS_PAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), OS_TYPE_PAGER, OsPager))
1256-#define OS_PAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), OS_TYPE_PAGER, OsPagerClass))
1257-#define OS_IS_PAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), OS_TYPE_PAGER))
1258-#define OS_IS_PAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), OS_TYPE_PAGER))
1259-#define OS_PAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), OS_TYPE_PAGER, OsPagerClass))
1260-
1261-typedef struct _OsPager OsPager;
1262-typedef struct _OsPagerClass OsPagerClass;
1263-typedef struct _OsPagerPrivate OsPagerPrivate;
1264-
1265-struct _OsPager {
1266- GObject parent_instance;
1267-
1268- OsPagerPrivate *priv;
1269-};
1270-
1271-struct _OsPagerClass {
1272- GObjectClass parent_class;
1273-};
1274-
1275-GType os_pager_get_type (void) G_GNUC_CONST;
1276-
1277-OsPager* os_pager_new (void);
1278-
1279-void os_pager_hide (OsPager *pager);
1280-
1281-void os_pager_connect (OsPager *pager,
1282- GdkRectangle mask);
1283-
1284-void os_pager_move_resize (OsPager *pager,
1285- GdkRectangle mask);
1286-
1287-void os_pager_set_active (OsPager *pager,
1288- gboolean active,
1289- gboolean animate);
1290-
1291-void os_pager_set_detached (OsPager *pager,
1292- gboolean detached);
1293-
1294-void os_pager_set_parent (OsPager *pager,
1295- GtkWidget *parent);
1296-
1297-void os_pager_show (OsPager *pager);
1298-
1299-void os_pager_size_allocate (OsPager *pager,
1300- GdkRectangle rectangle);
1301-
1302 G_END_DECLS
1303
1304 #ifdef __GNUC__
1305
1306=== modified file 'os/os-scrollbar.c'
1307--- os/os-scrollbar.c 2011-10-05 12:24:21 +0000
1308+++ os/os-scrollbar.c 2011-10-12 17:16:23 +0000
1309@@ -34,20 +34,17 @@
1310 #include <X11/Xutil.h>
1311 #include <X11/extensions/XInput2.h>
1312
1313-/* Size of the pager in pixels. */
1314-#define PAGER_SIZE 3
1315+/* Size of the bar in pixels. */
1316+#define BAR_SIZE 3
1317
1318 /* Size of the proximity effect in pixels. */
1319 #define PROXIMITY_SIZE 30
1320
1321-/* Rate of the paging. */
1322-#define RATE_PAGING 30
1323-
1324-/* Max duration of the paging. */
1325-#define MAX_DURATION_PAGING 1000
1326-
1327-/* Min duration of the paging. */
1328-#define MIN_DURATION_PAGING 250
1329+/* Max duration of the scrolling. */
1330+#define MAX_DURATION_SCROLLING 1000
1331+
1332+/* Min duration of the scrolling. */
1333+#define MIN_DURATION_SCROLLING 250
1334
1335 /* Timeout assumed for PropertyNotify _NET_ACTIVE_WINDOW event. */
1336 #define TIMEOUT_PRESENT_WINDOW 400
1337@@ -58,6 +55,9 @@
1338 /* Timeout before hiding in ms, after leaving the thumb. */
1339 #define TIMEOUT_THUMB_HIDE 200
1340
1341+/* Timeout before showing in ms, after entering the proximity. */
1342+#define TIMEOUT_THUMB_SHOW 100
1343+
1344 /* Timeout before hiding in ms, after leaving the toplevel. */
1345 #define TIMEOUT_TOPLEVEL_HIDE 200
1346
1347@@ -71,48 +71,60 @@
1348
1349 typedef enum
1350 {
1351+ OS_STATE_NONE = 0,
1352+ OS_STATE_CONNECTED = 1,
1353+ OS_STATE_DETACHED = 2,
1354+ OS_STATE_FULLSIZE = 4,
1355+ OS_STATE_INTERNAL = 8,
1356+ OS_STATE_LOCKED = 16,
1357+ OS_STATE_RECONNECTING = 32
1358+} OsStateFlags;
1359+
1360+typedef enum
1361+{
1362 OS_STRUT_SIDE_NONE = 0,
1363 OS_STRUT_SIDE_TOP = 1,
1364 OS_STRUT_SIDE_BOTTOM = 2,
1365 OS_STRUT_SIDE_LEFT = 4,
1366 OS_STRUT_SIDE_RIGHT = 8
1367-} OsStrutSide;
1368+} OsStrutSideFlags;
1369+
1370+typedef struct
1371+{
1372+ gboolean proximity;
1373+ gboolean running;
1374+} OsWindowFilter;
1375
1376 struct _OsScrollbarPrivate
1377 {
1378 GdkRectangle overlay;
1379 GdkRectangle slider;
1380 GdkRectangle trough;
1381- GtkAllocation pager_all;
1382+ GtkAllocation bar_all;
1383 GtkAllocation thumb_all;
1384 GtkAdjustment *adjustment;
1385 GtkOrientation orientation;
1386 GtkWidget *thumb;
1387 GtkWindowGroup *window_group;
1388 OsAnimation *animation;
1389- OsPager *pager;
1390+ OsBar *bar;
1391+ OsCoordinate pointer;
1392+ OsCoordinate thumb_win;
1393+ OsEventFlags event;
1394+ OsStateFlags state;
1395 OsSide side;
1396- OsEvent event;
1397+ OsWindowFilter filter;
1398 gboolean active_window;
1399- gboolean can_deactivate_pager;
1400- gboolean can_hide;
1401- gboolean detached_scroll;
1402- gboolean filter;
1403- gboolean fullsize;
1404- gboolean internal;
1405- gboolean lock_position;
1406- gboolean proximity;
1407- gboolean toplevel_button_press;
1408+ gboolean deactivable_bar;
1409+ gboolean hidable_thumb;
1410+ gboolean window_button_press; /* FIXME(Cimi) to replace with X11 input events. */
1411 gdouble value;
1412- gint win_x;
1413- gint win_y;
1414 gint slide_initial_slider_position;
1415 gint slide_initial_coordinate;
1416- gint pointer_x;
1417- gint pointer_y;
1418 gint64 present_time;
1419- guint32 source_deactivate_pager_id;
1420+ guint32 source_deactivate_bar_id;
1421 guint32 source_hide_thumb_id;
1422+ guint32 source_show_thumb_id;
1423 guint32 source_unlock_thumb_id;
1424 };
1425
1426@@ -159,10 +171,10 @@
1427 static void os_scrollbar_dispose (GObject *object);
1428 static void os_scrollbar_finalize (GObject *object);
1429
1430-/* Calculate pager layout info. */
1431+/* Calculate bar layout info. */
1432 static void
1433-calc_layout_pager (OsScrollbar *scrollbar,
1434- gdouble adjustment_value)
1435+calc_layout_bar (OsScrollbar *scrollbar,
1436+ gdouble adjustment_value)
1437 {
1438 OsScrollbarPrivate *priv;
1439
1440@@ -279,6 +291,23 @@
1441 }
1442 }
1443
1444+/* Calculate the position of the thumb window. */
1445+static void
1446+calc_thumb_window_position (OsScrollbar *scrollbar)
1447+{
1448+ OsScrollbarPrivate *priv;
1449+ gint x_pos, y_pos;
1450+
1451+ priv = scrollbar->priv;
1452+
1453+ /* In reality, I'm storing widget's window, not the toplevel.
1454+ * Is that the same with gdk_window_get_origin? */
1455+ gdk_window_get_origin (gtk_widget_get_window (GTK_WIDGET (scrollbar)), &x_pos, &y_pos);
1456+
1457+ priv->thumb_win.x = x_pos + priv->thumb_all.x;
1458+ priv->thumb_win.y = y_pos + priv->thumb_all.y;
1459+}
1460+
1461 /* Calculate the workarea using _UNITY_NET_WORKAREA_REGION. */
1462 static void
1463 calc_workarea (Display *display,
1464@@ -327,21 +356,114 @@
1465 }
1466 }
1467
1468-/* Deactivate the pager if it's the case. */
1469-static void
1470-deactivate_pager (OsScrollbar *scrollbar)
1471-{
1472- OsScrollbarPrivate *priv;
1473-
1474- priv = scrollbar->priv;
1475-
1476- if (priv->pager != NULL && priv->can_deactivate_pager)
1477- os_pager_set_active (priv->pager, FALSE, TRUE);
1478-}
1479-
1480-/* Timeout before deactivating the pager. */
1481+/* Check whether the thumb movement can be considered connected or not. */
1482+static void
1483+check_connection (OsScrollbar *scrollbar)
1484+{
1485+ OsScrollbarPrivate *priv;
1486+ gint x_pos, y_pos;
1487+
1488+ priv = scrollbar->priv;
1489+
1490+ /* This seems to be required to get proper values. */
1491+ calc_layout_bar (scrollbar, gtk_adjustment_get_value (priv->adjustment));
1492+ calc_layout_slider (scrollbar, gtk_adjustment_get_value (priv->adjustment));
1493+
1494+ gdk_window_get_origin (gtk_widget_get_window (priv->thumb), &x_pos, &y_pos);
1495+
1496+ if (priv->orientation == GTK_ORIENTATION_VERTICAL)
1497+ {
1498+ if (priv->overlay.height > priv->slider.height)
1499+ {
1500+ if (y_pos >= priv->thumb_win.y + priv->overlay.y &&
1501+ y_pos + priv->slider.height <= priv->thumb_win.y + priv->overlay.y + priv->overlay.height)
1502+ priv->state |= OS_STATE_CONNECTED;
1503+ else
1504+ priv->state &= ~(OS_STATE_CONNECTED);
1505+ }
1506+ else
1507+ {
1508+ if (y_pos == priv->thumb_win.y + priv->slider.y)
1509+ priv->state |= OS_STATE_CONNECTED;
1510+ else
1511+ priv->state &= ~(OS_STATE_CONNECTED);
1512+ }
1513+ }
1514+ else
1515+ {
1516+ if (priv->overlay.width > priv->slider.width)
1517+ {
1518+ if (x_pos >= priv->thumb_win.x + priv->overlay.x &&
1519+ x_pos + priv->slider.width <= priv->thumb_win.x + priv->overlay.x + priv->overlay.width)
1520+ priv->state |= OS_STATE_CONNECTED;
1521+ else
1522+ priv->state &= ~(OS_STATE_CONNECTED);
1523+ }
1524+ else
1525+ {
1526+ if (x_pos == priv->thumb_win.x + priv->slider.x)
1527+ priv->state |= OS_STATE_CONNECTED;
1528+ else
1529+ priv->state &= ~(OS_STATE_CONNECTED);
1530+ }
1531+ }
1532+}
1533+
1534+/* Traduce coordinates into GtkRange values. */
1535+static gdouble
1536+coord_to_value (OsScrollbar *scrollbar,
1537+ gint coord)
1538+{
1539+ OsScrollbarPrivate *priv;
1540+ gdouble frac;
1541+ gdouble value;
1542+ gint trough_length;
1543+ gint slider_length;
1544+
1545+ priv = scrollbar->priv;
1546+
1547+ if (priv->orientation == GTK_ORIENTATION_VERTICAL)
1548+ {
1549+ trough_length = priv->trough.height;
1550+ slider_length = MAX (priv->slider.height, priv->overlay.height);
1551+ }
1552+ else
1553+ {
1554+ trough_length = priv->trough.width;
1555+ slider_length = MAX (priv->slider.width, priv->overlay.width);
1556+ }
1557+
1558+ if (trough_length == slider_length)
1559+ frac = 1.0;
1560+ else
1561+ frac = (MAX (0, coord) / (gdouble) (trough_length - slider_length));
1562+
1563+ value = gtk_adjustment_get_lower (priv->adjustment) + frac * (gtk_adjustment_get_upper (priv->adjustment) -
1564+ gtk_adjustment_get_lower (priv->adjustment) -
1565+ gtk_adjustment_get_page_size (priv->adjustment));
1566+
1567+ value = CLAMP (value,
1568+ gtk_adjustment_get_lower (priv->adjustment),
1569+ gtk_adjustment_get_upper (priv->adjustment) - gtk_adjustment_get_page_size (priv->adjustment));
1570+
1571+ return value;
1572+}
1573+
1574+/* Deactivate the bar if it's the case. */
1575+static void
1576+deactivate_bar (OsScrollbar *scrollbar)
1577+{
1578+ OsScrollbarPrivate *priv;
1579+
1580+ priv = scrollbar->priv;
1581+
1582+ if (priv->bar != NULL && priv->deactivable_bar)
1583+ os_bar_set_active (priv->bar, FALSE, TRUE);
1584+}
1585+
1586+/* Timeout before deactivating the bar. */
1587 static gboolean
1588-deactivate_pager_cb (gpointer user_data)
1589+deactivate_bar_cb (gpointer user_data)
1590 {
1591 OsScrollbar *scrollbar;
1592 OsScrollbarPrivate *priv;
1593@@ -351,8 +473,8 @@
1594
1595 OS_DCHECK (!priv->active_window);
1596
1597- deactivate_pager (scrollbar);
1598- priv->source_deactivate_pager_id = 0;
1599+ deactivate_bar (scrollbar);
1600+ priv->source_deactivate_bar_id = 0;
1601
1602 return FALSE;
1603 }
1604@@ -365,7 +487,7 @@
1605
1606 priv = scrollbar->priv;
1607
1608- if (priv->can_hide)
1609+ if (priv->hidable_thumb)
1610 gtk_widget_hide (priv->thumb);
1611 }
1612
1613@@ -396,9 +518,9 @@
1614 #endif
1615 }
1616
1617-/* Move the pager. */
1618+/* Move the bar. */
1619 static void
1620-move_pager (OsScrollbar *scrollbar)
1621+move_bar (OsScrollbar *scrollbar)
1622 {
1623 GdkRectangle mask;
1624 OsScrollbarPrivate *priv;
1625@@ -409,7 +531,7 @@
1626 {
1627 mask.x = 0;
1628 mask.y = priv->overlay.y;
1629- mask.width = priv->pager_all.width;
1630+ mask.width = priv->bar_all.width;
1631 mask.height = priv->overlay.height;
1632 }
1633 else
1634@@ -417,10 +539,10 @@
1635 mask.x = priv->overlay.x;
1636 mask.y = 0;
1637 mask.width = priv->overlay.width;
1638- mask.height = priv->pager_all.height;
1639+ mask.height = priv->bar_all.height;
1640 }
1641
1642- os_pager_move_resize (priv->pager, mask);
1643+ os_bar_move_resize (priv->bar, mask);
1644 }
1645
1646 /* Sanitize x coordinate of thumb window. */
1647@@ -481,7 +603,7 @@
1648
1649 for (i = 0; i < cairo_region_num_rectangles (struts_region); i++)
1650 {
1651- OsStrutSide strut_side;
1652+ OsStrutSideFlags strut_side;
1653 gint count;
1654
1655 cairo_region_get_rectangle (struts_region, i, &tmp_rect);
1656@@ -548,7 +670,7 @@
1657 (n_monitor != gdk_screen_get_monitor_at_point (screen, monitor_x + priv->thumb_all.width, y) ||
1658 monitor_x + priv->thumb_all.width >= screen_width))
1659 {
1660- priv->internal = TRUE;
1661+ priv->state |= OS_STATE_INTERNAL;
1662 return MAX (x - priv->thumb_all.width, screen_width - priv->thumb_all.width);
1663 }
1664
1665@@ -556,12 +678,12 @@
1666 (n_monitor != gdk_screen_get_monitor_at_point (screen, monitor_x - priv->thumb_all.width, y) ||
1667 monitor_x - priv->thumb_all.width <= screen_x))
1668 {
1669- priv->internal = TRUE;
1670+ priv->state |= OS_STATE_INTERNAL;
1671 return MAX (x, screen_x);
1672 }
1673
1674 if (priv->orientation == GTK_ORIENTATION_VERTICAL)
1675- priv->internal = FALSE;
1676+ priv->state &= ~(OS_STATE_INTERNAL);
1677
1678 return x;
1679 }
1680@@ -624,7 +746,7 @@
1681
1682 for (i = 0; i < cairo_region_num_rectangles (struts_region); i++)
1683 {
1684- OsStrutSide strut_side;
1685+ OsStrutSideFlags strut_side;
1686 gint count;
1687
1688 cairo_region_get_rectangle (struts_region, i, &tmp_rect);
1689@@ -691,7 +813,7 @@
1690 (n_monitor != gdk_screen_get_monitor_at_point (screen, x, monitor_y + priv->thumb_all.height) ||
1691 monitor_y + priv->thumb_all.height >= screen_height))
1692 {
1693- priv->internal = TRUE;
1694+ priv->state |= OS_STATE_INTERNAL;
1695 return MAX (y - priv->thumb_all.height, screen_height - priv->thumb_all.height);
1696 }
1697
1698@@ -699,12 +821,12 @@
1699 (n_monitor != gdk_screen_get_monitor_at_point (screen, x, monitor_y - priv->thumb_all.height) ||
1700 monitor_y - priv->thumb_all.height <= screen_y))
1701 {
1702- priv->internal = TRUE;
1703+ priv->state |= OS_STATE_INTERNAL;
1704 return MAX (y, screen_y);
1705 }
1706
1707 if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
1708- priv->internal = FALSE;
1709+ priv->state &= ~(OS_STATE_INTERNAL);
1710
1711 return y;
1712 }
1713@@ -752,10 +874,10 @@
1714 swap_thumb (scrollbar, os_thumb_new (priv->orientation));
1715 }
1716
1717-/* Callback called by the paging animation. */
1718+/* Callback called by the scrolling animation. */
1719 static void
1720-paging_cb (gfloat weight,
1721- gpointer user_data)
1722+scrolling_cb (gfloat weight,
1723+ gpointer user_data)
1724 {
1725 gdouble new_value;
1726 OsScrollbar *scrollbar;
1727@@ -779,6 +901,22 @@
1728 gtk_adjustment_set_value (priv->adjustment, new_value);
1729 }
1730
1731+/* End function called by the scrolling animation. */
1732+static void
1733+scrolling_end_cb (gpointer user_data)
1734+{
1735+ OsScrollbar *scrollbar;
1736+ OsScrollbarPrivate *priv;
1737+
1738+ scrollbar = OS_SCROLLBAR (user_data);
1739+
1740+ priv = scrollbar->priv;
1741+
1742+ priv->state &= ~(OS_STATE_RECONNECTING);
1743+
1744+ check_connection (scrollbar);
1745+}
1746+
1747 /* Swap adjustment pointer. */
1748 static void
1749 swap_adjustment (OsScrollbar *scrollbar,
1750@@ -879,8 +1017,8 @@
1751 scrollbar = OS_SCROLLBAR (user_data);
1752 priv = scrollbar->priv;
1753
1754- if (priv->can_hide)
1755- priv->lock_position = FALSE;
1756+ if (priv->hidable_thumb)
1757+ priv->state &= ~(OS_STATE_LOCKED);
1758
1759 priv->source_unlock_thumb_id = 0;
1760
1761@@ -899,43 +1037,43 @@
1762 scrollbar = OS_SCROLLBAR (user_data);
1763 priv = scrollbar->priv;
1764
1765- /* FIXME(Cimi) we should control each time os_pager_show()/hide()
1766- * is called here and in map()/unmap().
1767+ /* FIXME(Cimi) we should control each time os_bar_show ()/hide ()
1768+ * is called here and in map ()/unmap ().
1769 * We are arbitrary calling that and I'm frightened we should show or keep
1770- * hidden a pager that is meant to be hidden/shown.
1771- * I don't want to see pagers reappearing because
1772- * of a change in the adjustment of an invisible pager or viceversa. */
1773+ * hidden a bar that is meant to be hidden/shown.
1774+ * I don't want to see bars reappearing because
1775+ * of a change in the adjustment of an invisible bar or viceversa. */
1776 if (gtk_adjustment_get_upper (adjustment) - gtk_adjustment_get_lower (adjustment) >
1777 gtk_adjustment_get_page_size (adjustment))
1778 {
1779- priv->fullsize = FALSE;
1780- if (priv->proximity != FALSE)
1781- os_pager_show (priv->pager);
1782+ priv->state &= ~(OS_STATE_FULLSIZE);
1783+ if (priv->filter.proximity)
1784+ os_bar_show (priv->bar);
1785 }
1786 else
1787 {
1788- priv->fullsize = TRUE;
1789- if (priv->proximity != FALSE)
1790+ priv->state |= OS_STATE_FULLSIZE;
1791+ if (priv->filter.proximity)
1792 {
1793- os_pager_hide (priv->pager);
1794+ os_bar_hide (priv->bar);
1795
1796 gtk_widget_hide (priv->thumb);
1797 }
1798 }
1799
1800- calc_layout_pager (scrollbar, gtk_adjustment_get_value (adjustment));
1801+ calc_layout_bar (scrollbar, gtk_adjustment_get_value (adjustment));
1802 calc_layout_slider (scrollbar, gtk_adjustment_get_value (adjustment));
1803
1804 if (!(priv->event & OS_EVENT_ENTER_NOTIFY) &&
1805 !(priv->event & OS_EVENT_MOTION_NOTIFY))
1806 gtk_widget_hide (priv->thumb);
1807
1808- move_pager (scrollbar);
1809+ move_bar (scrollbar);
1810 }
1811
1812-/* Update the visual connection between pager and thumb. */
1813+/* Update the tail (visual connection) between bar and thumb. */
1814 static void
1815-update_visual_connection (OsScrollbar *scrollbar)
1816+update_tail (OsScrollbar *scrollbar)
1817 {
1818 OsScrollbarPrivate *priv;
1819 gint x_pos, y_pos;
1820@@ -946,73 +1084,85 @@
1821
1822 if (priv->orientation == GTK_ORIENTATION_VERTICAL)
1823 {
1824- if (priv->win_y + priv->overlay.y >= y_pos + priv->slider.height)
1825+ if (priv->thumb_win.y + priv->overlay.y >= y_pos + priv->slider.height)
1826 {
1827 GdkRectangle mask;
1828
1829 mask.x = 0;
1830- mask.y = y_pos + priv->slider.height / 2 - priv->win_y;
1831- mask.width = priv->pager_all.width;
1832+ mask.y = y_pos + priv->slider.height / 2 - priv->thumb_win.y;
1833+ mask.width = priv->bar_all.width;
1834 mask.height = priv->overlay.y - mask.y;
1835
1836- os_pager_connect (priv->pager, mask);
1837- os_pager_set_detached (priv->pager, TRUE);
1838-
1839+ os_bar_connect (priv->bar, mask);
1840+
1841+ priv->state |= OS_STATE_DETACHED;
1842+
1843+ os_bar_set_detached (priv->bar, TRUE, FALSE);
1844 os_thumb_set_detached (OS_THUMB (priv->thumb), TRUE);
1845 }
1846- else if (priv->win_y + priv->overlay.y + priv->overlay.height <= y_pos)
1847+ else if (priv->thumb_win.y + priv->overlay.y + priv->overlay.height <= y_pos)
1848 {
1849 GdkRectangle mask;
1850
1851 mask.x = 0;
1852 mask.y = priv->overlay.y + priv->overlay.height;
1853- mask.width = priv->pager_all.width;
1854- mask.height = y_pos + priv->slider.height / 2 - priv->win_y - mask.y;
1855-
1856- os_pager_connect (priv->pager, mask);
1857- os_pager_set_detached (priv->pager, TRUE);
1858-
1859+ mask.width = priv->bar_all.width;
1860+ mask.height = y_pos + priv->slider.height / 2 - priv->thumb_win.y - mask.y;
1861+
1862+ os_bar_connect (priv->bar, mask);
1863+
1864+ priv->state |= OS_STATE_DETACHED;
1865+
1866+ os_bar_set_detached (priv->bar, TRUE, FALSE);
1867 os_thumb_set_detached (OS_THUMB (priv->thumb), TRUE);
1868 }
1869- else
1870+ else
1871 {
1872- os_pager_set_detached (priv->pager, FALSE);
1873+ priv->state &= ~(OS_STATE_DETACHED);
1874+
1875+ os_bar_set_detached (priv->bar, FALSE, FALSE);
1876 os_thumb_set_detached (OS_THUMB (priv->thumb), FALSE);
1877 }
1878 }
1879 else
1880 {
1881- if (priv->win_x + priv->overlay.x >= x_pos + priv->slider.width)
1882+ if (priv->thumb_win.x + priv->overlay.x >= x_pos + priv->slider.width)
1883 {
1884 GdkRectangle mask;
1885
1886- mask.x = x_pos + priv->slider.width / 2 - priv->win_x;
1887+ mask.x = x_pos + priv->slider.width / 2 - priv->thumb_win.x;
1888 mask.y = 0;
1889 mask.width = priv->overlay.x - mask.x;
1890- mask.height = priv->pager_all.height;
1891-
1892- os_pager_connect (priv->pager, mask);
1893- os_pager_set_detached (priv->pager, TRUE);
1894-
1895+ mask.height = priv->bar_all.height;
1896+
1897+ os_bar_connect (priv->bar, mask);
1898+
1899+ priv->state |= OS_STATE_DETACHED;
1900+
1901+ os_bar_set_detached (priv->bar, TRUE, FALSE);
1902 os_thumb_set_detached (OS_THUMB (priv->thumb), TRUE);
1903 }
1904- else if (priv->win_x + priv->overlay.x + priv->overlay.width <= x_pos)
1905+ else if (priv->thumb_win.x + priv->overlay.x + priv->overlay.width <= x_pos)
1906 {
1907 GdkRectangle mask;
1908
1909 mask.x = priv->overlay.x + priv->overlay.width;
1910 mask.y = 0;
1911- mask.width = x_pos + priv->slider.width / 2 - priv->win_x - mask.x;
1912- mask.height = priv->pager_all.height;
1913-
1914- os_pager_connect (priv->pager, mask);
1915- os_pager_set_detached (priv->pager, TRUE);
1916-
1917+ mask.width = x_pos + priv->slider.width / 2 - priv->thumb_win.x - mask.x;
1918+ mask.height = priv->bar_all.height;
1919+
1920+ os_bar_connect (priv->bar, mask);
1921+
1922+ priv->state |= OS_STATE_DETACHED;
1923+
1924+ os_bar_set_detached (priv->bar, TRUE, FALSE);
1925 os_thumb_set_detached (OS_THUMB (priv->thumb), TRUE);
1926 }
1927 else
1928 {
1929- os_pager_set_detached (priv->pager, FALSE);
1930+ priv->state &= ~(OS_STATE_DETACHED);
1931+
1932+ os_bar_set_detached (priv->bar, FALSE, FALSE);
1933 os_thumb_set_detached (OS_THUMB (priv->thumb), FALSE);
1934 }
1935 }
1936@@ -1028,35 +1178,28 @@
1937 scrollbar = OS_SCROLLBAR (user_data);
1938 priv = scrollbar->priv;
1939
1940- calc_layout_pager (scrollbar, gtk_adjustment_get_value (adjustment));
1941+ calc_layout_bar (scrollbar, gtk_adjustment_get_value (adjustment));
1942 calc_layout_slider (scrollbar, gtk_adjustment_get_value (adjustment));
1943
1944 if (!(priv->event & OS_EVENT_ENTER_NOTIFY) &&
1945 !(priv->event & OS_EVENT_MOTION_NOTIFY))
1946 gtk_widget_hide (priv->thumb);
1947
1948- if (gtk_widget_get_mapped (priv->thumb))
1949- {
1950- /* If we're dragging the thumb, it can't be detached. */
1951- if (priv->event & OS_EVENT_MOTION_NOTIFY)
1952- {
1953- os_pager_set_detached (priv->pager, FALSE);
1954- os_thumb_set_detached (OS_THUMB (priv->thumb), FALSE);
1955- }
1956- else
1957- update_visual_connection (scrollbar);
1958- }
1959+ if (gtk_widget_get_mapped (priv->thumb) &&
1960+ !((priv->event & OS_EVENT_MOTION_NOTIFY) &&
1961+ (priv->state & OS_STATE_CONNECTED)))
1962+ update_tail (scrollbar);
1963
1964- move_pager (scrollbar);
1965+ move_bar (scrollbar);
1966 }
1967
1968-/* Pager functions. */
1969+/* Bar functions. */
1970
1971-/* Set the state of the pager checking mouse position. */
1972+/* Set the state of the bar checking mouse position. */
1973 static void
1974-pager_set_state_from_pointer (OsScrollbar *scrollbar,
1975- gint x,
1976- gint y)
1977+bar_set_state_from_pointer (OsScrollbar *scrollbar,
1978+ gint x,
1979+ gint y)
1980 {
1981 GtkAllocation allocation;
1982 OsScrollbarPrivate *priv;
1983@@ -1070,13 +1213,13 @@
1984 if ((x > allocation.x && x < allocation.x + allocation.width) &&
1985 (y > allocation.y && y < allocation.y + allocation.height))
1986 {
1987- priv->can_deactivate_pager = FALSE;
1988- os_pager_set_active (priv->pager, TRUE, TRUE);
1989+ priv->deactivable_bar = FALSE;
1990+ os_bar_set_active (priv->bar, TRUE, TRUE);
1991 }
1992 else
1993 {
1994- priv->can_deactivate_pager = TRUE;
1995- os_pager_set_active (priv->pager, FALSE, TRUE);
1996+ priv->deactivable_bar = TRUE;
1997+ os_bar_set_active (priv->bar, FALSE, TRUE);
1998 }
1999 }
2000
2001@@ -1105,16 +1248,16 @@
2002 gdk_screen_get_active_window (gtk_widget_get_screen (GTK_WIDGET (scrollbar))))
2003 {
2004 /* Stops potential running timeout. */
2005- if (priv->source_deactivate_pager_id != 0)
2006+ if (priv->source_deactivate_bar_id != 0)
2007 {
2008- g_source_remove (priv->source_deactivate_pager_id);
2009- priv->source_deactivate_pager_id = 0;
2010+ g_source_remove (priv->source_deactivate_bar_id);
2011+ priv->source_deactivate_bar_id = 0;
2012 }
2013
2014 priv->active_window = TRUE;
2015
2016- priv->can_deactivate_pager = FALSE;
2017- os_pager_set_active (priv->pager, TRUE, TRUE);
2018+ priv->deactivable_bar = FALSE;
2019+ os_bar_set_active (priv->bar, TRUE, TRUE);
2020 }
2021 else if (priv->active_window)
2022 {
2023@@ -1147,13 +1290,13 @@
2024 /* When the window is unfocused,
2025 * check the position of the pointer
2026 * and set the state accordingly. */
2027- pager_set_state_from_pointer (scrollbar, x, y);
2028+ bar_set_state_from_pointer (scrollbar, x, y);
2029 }
2030 else
2031 {
2032 /* If the pointer is outside of the window, set it inactive. */
2033- priv->can_deactivate_pager = TRUE;
2034- os_pager_set_active (priv->pager, FALSE, TRUE);
2035+ priv->deactivable_bar = TRUE;
2036+ os_bar_set_active (priv->bar, FALSE, TRUE);
2037 }
2038
2039 if ((current_time > end_time) && priv->thumb != NULL)
2040@@ -1251,7 +1394,8 @@
2041 {
2042 if (event->type == GDK_BUTTON_PRESS)
2043 {
2044- if (event->button == 1)
2045+ if (event->button == 1 ||
2046+ event->button == 2)
2047 {
2048 OsScrollbar *scrollbar;
2049 OsScrollbarPrivate *priv;
2050@@ -1268,7 +1412,60 @@
2051 priv->event |= OS_EVENT_BUTTON_PRESS;
2052 priv->event &= ~(OS_EVENT_MOTION_NOTIFY);
2053
2054- priv->detached_scroll = FALSE;
2055+ if (event->button == 2)
2056+ {
2057+ /* Reconnect the thumb with the bar. */
2058+ gdouble new_value;
2059+ gint c, delta;
2060+ gint32 duration;
2061+
2062+ if (priv->orientation == GTK_ORIENTATION_VERTICAL)
2063+ {
2064+ priv->slide_initial_slider_position = event->y_root - priv->thumb_win.y - event->y;
2065+ priv->slide_initial_coordinate = event->y_root;
2066+
2067+ delta = event->y_root - priv->slide_initial_coordinate;
2068+ }
2069+ else
2070+ {
2071+ priv->slide_initial_slider_position = event->x_root - priv->thumb_win.x - event->x;
2072+ priv->slide_initial_coordinate = event->x_root;
2073+
2074+ delta = event->x_root - priv->slide_initial_coordinate;
2075+ }
2076+
2077+ c = priv->slide_initial_slider_position + delta;
2078+
2079+ /* If a scrolling animation is running,
2080+ * stop it and add the new value. */
2081+ os_animation_stop (priv->animation, NULL);
2082+
2083+ new_value = coord_to_value (scrollbar, c);
2084+
2085+ /* Only start the animation if needed. */
2086+ if (new_value != gtk_adjustment_get_value (priv->adjustment))
2087+ {
2088+ priv->state |= OS_STATE_RECONNECTING;
2089+
2090+ priv->value = new_value;
2091+
2092+ /* Calculate and set the duration. */
2093+ if (priv->value > gtk_adjustment_get_value (priv->adjustment))
2094+ duration = MIN_DURATION_SCROLLING + ((priv->value - gtk_adjustment_get_value (priv->adjustment)) /
2095+ (gtk_adjustment_get_upper (priv->adjustment) -
2096+ gtk_adjustment_get_lower (priv->adjustment))) *
2097+ (MAX_DURATION_SCROLLING - MIN_DURATION_SCROLLING);
2098+ else
2099+ duration = MIN_DURATION_SCROLLING + ((gtk_adjustment_get_value (priv->adjustment) - priv->value) /
2100+ (gtk_adjustment_get_upper (priv->adjustment) -
2101+ gtk_adjustment_get_lower (priv->adjustment))) *
2102+ (MAX_DURATION_SCROLLING - MIN_DURATION_SCROLLING);
2103+ os_animation_set_duration (priv->animation, duration);
2104+
2105+ /* Start the scrolling animation. */
2106+ os_animation_start (priv->animation);
2107+ }
2108+ }
2109
2110 if (priv->orientation == GTK_ORIENTATION_VERTICAL)
2111 {
2112@@ -1281,8 +1478,8 @@
2113 priv->slide_initial_coordinate = event->x_root;
2114 }
2115
2116- priv->pointer_x = event->x;
2117- priv->pointer_y = event->y;
2118+ priv->pointer.x = event->x;
2119+ priv->pointer.y = event->y;
2120 }
2121 }
2122
2123@@ -1299,7 +1496,7 @@
2124
2125 priv = scrollbar->priv;
2126
2127- /* If a paging animation is running,
2128+ /* If a scrolling animation is running,
2129 * stop it and add the new value. */
2130 if (os_animation_is_running (priv->animation))
2131 {
2132@@ -1314,13 +1511,17 @@
2133 gtk_adjustment_get_lower (priv->adjustment),
2134 gtk_adjustment_get_upper (priv->adjustment) - gtk_adjustment_get_page_size (priv->adjustment));
2135
2136+ /* There's no need to do start a new animation. */
2137+ if (priv->value == gtk_adjustment_get_value (priv->adjustment))
2138+ return;
2139+
2140 /* Calculate and set the duration. */
2141- duration = MIN_DURATION_PAGING + ((priv->value - gtk_adjustment_get_value (priv->adjustment)) /
2142- gtk_adjustment_get_page_increment (priv->adjustment)) *
2143- (MAX_DURATION_PAGING - MIN_DURATION_PAGING);
2144+ duration = MIN_DURATION_SCROLLING + ((priv->value - gtk_adjustment_get_value (priv->adjustment)) /
2145+ gtk_adjustment_get_page_increment (priv->adjustment)) *
2146+ (MAX_DURATION_SCROLLING - MIN_DURATION_SCROLLING);
2147 os_animation_set_duration (priv->animation, duration);
2148
2149- /* Start the paging animation. */
2150+ /* Start the scrolling animation. */
2151 os_animation_start (priv->animation);
2152 }
2153
2154@@ -1334,7 +1535,7 @@
2155
2156 priv = scrollbar->priv;
2157
2158- /* If a paging animation is running,
2159+ /* If a scrolling animation is running,
2160 * stop it and subtract the new value. */
2161 if (os_animation_is_running (priv->animation))
2162 {
2163@@ -1349,13 +1550,17 @@
2164 gtk_adjustment_get_lower (priv->adjustment),
2165 gtk_adjustment_get_upper (priv->adjustment) - gtk_adjustment_get_page_size (priv->adjustment));
2166
2167+ /* There's no need to do start a new animation. */
2168+ if (priv->value == gtk_adjustment_get_value (priv->adjustment))
2169+ return;
2170+
2171 /* Calculate and set the duration. */
2172- duration = MIN_DURATION_PAGING + ((gtk_adjustment_get_value (priv->adjustment) - priv->value) /
2173- gtk_adjustment_get_page_increment (priv->adjustment)) *
2174- (MAX_DURATION_PAGING - MIN_DURATION_PAGING);
2175+ duration = MIN_DURATION_SCROLLING + ((gtk_adjustment_get_value (priv->adjustment) - priv->value) /
2176+ gtk_adjustment_get_page_increment (priv->adjustment)) *
2177+ (MAX_DURATION_SCROLLING - MIN_DURATION_SCROLLING);
2178 os_animation_set_duration (priv->animation, duration);
2179
2180- /* Start the paging animation. */
2181+ /* Start the scrolling animation. */
2182 os_animation_start (priv->animation);
2183 }
2184
2185@@ -1366,7 +1571,8 @@
2186 {
2187 if (event->type == GDK_BUTTON_RELEASE)
2188 {
2189- if (event->button == 1)
2190+ if (event->button == 1 ||
2191+ event->button == 2)
2192 {
2193 OsScrollbar *scrollbar;
2194 OsScrollbarPrivate *priv;
2195@@ -1376,24 +1582,23 @@
2196
2197 gtk_window_set_transient_for (GTK_WINDOW (widget), NULL);
2198
2199- if (!(priv->event & OS_EVENT_MOTION_NOTIFY) && !priv->detached_scroll)
2200+ if (event->button == 1 &&
2201+ !(priv->event & OS_EVENT_MOTION_NOTIFY))
2202 {
2203 if (priv->orientation == GTK_ORIENTATION_VERTICAL)
2204 {
2205- if (priv->pointer_y < priv->slider.height / 2)
2206+ if (priv->pointer.y < priv->slider.height / 2)
2207 page_up (scrollbar);
2208 else
2209 page_down (scrollbar);
2210 }
2211 else
2212 {
2213- if (priv->pointer_x < priv->slider.width / 2)
2214+ if (priv->pointer.x < priv->slider.width / 2)
2215 page_up (scrollbar);
2216 else
2217 page_down (scrollbar);
2218 }
2219-
2220- priv->event |= OS_EVENT_VALUE_CHANGED;
2221 }
2222
2223 priv->event &= ~(OS_EVENT_BUTTON_PRESS | OS_EVENT_MOTION_NOTIFY);
2224@@ -1416,11 +1621,11 @@
2225
2226 priv->event |= OS_EVENT_ENTER_NOTIFY;
2227
2228- priv->can_deactivate_pager = FALSE;
2229- priv->can_hide = FALSE;
2230+ priv->deactivable_bar = FALSE;
2231+ priv->hidable_thumb = FALSE;
2232
2233- if (priv->internal)
2234- priv->lock_position = TRUE;
2235+ if (priv->state & OS_STATE_INTERNAL)
2236+ priv->state |= OS_STATE_LOCKED;
2237
2238 return FALSE;
2239 }
2240@@ -1440,20 +1645,20 @@
2241 * not interacting with the thumb. */
2242 if (!(priv->event & OS_EVENT_BUTTON_PRESS))
2243 {
2244- /* Never deactivate the pager in an active window. */
2245+ /* Never deactivate the bar in an active window. */
2246 if (!priv->active_window)
2247 {
2248- priv->can_deactivate_pager = TRUE;
2249-
2250- if (priv->source_deactivate_pager_id != 0)
2251- g_source_remove (priv->source_deactivate_pager_id);
2252-
2253- priv->source_deactivate_pager_id = g_timeout_add (TIMEOUT_THUMB_HIDE,
2254- deactivate_pager_cb,
2255- scrollbar);
2256+ priv->deactivable_bar = TRUE;
2257+
2258+ if (priv->source_deactivate_bar_id != 0)
2259+ g_source_remove (priv->source_deactivate_bar_id);
2260+
2261+ priv->source_deactivate_bar_id = g_timeout_add (TIMEOUT_THUMB_HIDE,
2262+ deactivate_bar_cb,
2263+ scrollbar);
2264 }
2265
2266- priv->can_hide = TRUE;
2267+ priv->hidable_thumb = TRUE;
2268
2269 if (priv->source_hide_thumb_id != 0)
2270 g_source_remove (priv->source_hide_thumb_id);
2271@@ -1481,9 +1686,9 @@
2272 scrollbar = OS_SCROLLBAR (user_data);
2273 priv = scrollbar->priv;
2274
2275- /* Immediately set the pager to be active. */
2276- priv->can_deactivate_pager = FALSE;
2277- os_pager_set_active (priv->pager, TRUE, FALSE);
2278+ /* Immediately set the bar to be active. */
2279+ priv->deactivable_bar = FALSE;
2280+ os_bar_set_active (priv->bar, TRUE, FALSE);
2281
2282 xid = GDK_WINDOW_XID (gtk_widget_get_window (widget));
2283 xid_parent = GDK_WINDOW_XID (gtk_widget_get_window (gtk_widget_get_toplevel (GTK_WIDGET (scrollbar))));
2284@@ -1542,46 +1747,6 @@
2285 }
2286 }
2287
2288-/* Traduce coordinates into GtkRange values. */
2289-static gdouble
2290-coord_to_value (OsScrollbar *scrollbar,
2291- gint coord)
2292-{
2293- OsScrollbarPrivate *priv;
2294- gdouble frac;
2295- gdouble value;
2296- gint trough_length;
2297- gint slider_length;
2298-
2299- priv = scrollbar->priv;
2300-
2301- if (priv->orientation == GTK_ORIENTATION_VERTICAL)
2302- {
2303- trough_length = priv->trough.height;
2304- slider_length = MAX (priv->slider.height, priv->overlay.height);
2305- }
2306- else
2307- {
2308- trough_length = priv->trough.width;
2309- slider_length = MAX (priv->slider.width, priv->overlay.width);
2310- }
2311-
2312- if (trough_length == slider_length)
2313- frac = 1.0;
2314- else
2315- frac = (MAX (0, coord) / (gdouble) (trough_length - slider_length));
2316-
2317- value = gtk_adjustment_get_lower (priv->adjustment) + frac * (gtk_adjustment_get_upper (priv->adjustment) -
2318- gtk_adjustment_get_lower (priv->adjustment) -
2319- gtk_adjustment_get_page_size (priv->adjustment));
2320-
2321- value = CLAMP (value,
2322- gtk_adjustment_get_lower (priv->adjustment),
2323- gtk_adjustment_get_upper (priv->adjustment) - gtk_adjustment_get_page_size (priv->adjustment));
2324-
2325- return value;
2326-}
2327-
2328 /* From pointer movement, set adjustment value. */
2329 static void
2330 capture_movement (OsScrollbar *scrollbar,
2331@@ -1622,184 +1787,214 @@
2332 {
2333 gint x, y;
2334
2335- /* Thumb and pager are detached.
2336- * Detached scroll: keep the thumb detached during the scroll,
2337- * update the visual connection when reaching an edge. */
2338- if (priv->event & OS_EVENT_VALUE_CHANGED)
2339- {
2340- /* Return if the mouse movement is small. */
2341- if (abs (priv->pointer_x - event->x) <= TOLERANCE_MOTION &&
2342- abs (priv->pointer_y - event->y) <= TOLERANCE_MOTION)
2343- return FALSE;
2344-
2345- priv->detached_scroll = TRUE;
2346-
2347- /* Stop the paging animation if it's running. */
2348- os_animation_stop (priv->animation, NULL);
2349+ /* Use tolerance at the first calls to this motion notify event. */
2350+ if (!(priv->event & OS_EVENT_MOTION_NOTIFY) &&
2351+ abs (priv->pointer.x - event->x) <= TOLERANCE_MOTION &&
2352+ abs (priv->pointer.y - event->y) <= TOLERANCE_MOTION)
2353+ return FALSE;
2354+
2355+ if (!(priv->event & OS_EVENT_MOTION_NOTIFY))
2356+ {
2357+ /* Check if we can consider the thumb movement connected with the overlay. */
2358+ check_connection (scrollbar);
2359+
2360+ priv->event |= OS_EVENT_MOTION_NOTIFY;
2361+ }
2362+
2363+ /* Before stopping the animation,
2364+ * check if it's reconnecting.
2365+ * In this case we need to update the slide values
2366+ * with the current position. */
2367+ if (os_animation_is_running (priv->animation))
2368+ {
2369+ if (priv->state & OS_STATE_RECONNECTING)
2370+ {
2371+ /* It's a reconnecting animation. */
2372+ if (priv->orientation == GTK_ORIENTATION_VERTICAL)
2373+ {
2374+ priv->slide_initial_slider_position = MIN (priv->slider.y, priv->overlay.y);
2375+ priv->slide_initial_coordinate = event->y_root;
2376+ }
2377+ else
2378+ {
2379+ priv->slide_initial_slider_position = MIN (priv->slider.x, priv->overlay.x);
2380+ priv->slide_initial_coordinate = event->x_root;
2381+ }
2382+ }
2383+ else
2384+ {
2385+ /* Stop the paging animation now. */
2386+ os_animation_stop (priv->animation, NULL);
2387+ }
2388+ }
2389+
2390+ /* Behave differently when the thumb is connected or not. */
2391+ if (priv->state & OS_STATE_CONNECTED)
2392+ {
2393+ /* This is a connected scroll,
2394+ * the thumb movement is kept in sync with the overlay. */
2395+
2396+ if (priv->orientation == GTK_ORIENTATION_VERTICAL)
2397+ {
2398+ if (priv->overlay.height > priv->slider.height)
2399+ {
2400+ /* Limit x and y within the overlay. */
2401+ x = priv->thumb_win.x;
2402+ y = CLAMP (event->y_root - priv->pointer.y,
2403+ priv->thumb_win.y + priv->overlay.y,
2404+ priv->thumb_win.y + priv->overlay.y + priv->overlay.height - priv->slider.height);
2405+ }
2406+ else
2407+ {
2408+ x = priv->thumb_win.x;
2409+ y = priv->thumb_win.y + priv->slider.y;
2410+ }
2411+ }
2412+ else
2413+ {
2414+ if (priv->overlay.width > priv->slider.width)
2415+ {
2416+ /* Limit x and y within the overlay. */
2417+ x = CLAMP (event->x_root - priv->pointer.x,
2418+ priv->thumb_win.x + priv->overlay.x,
2419+ priv->thumb_win.x + priv->overlay.x + priv->overlay.width - priv->slider.width);
2420+ y = priv->thumb_win.y;
2421+ }
2422+ else
2423+ {
2424+ x = priv->thumb_win.x + priv->slider.x;
2425+ y = priv->thumb_win.y;
2426+ }
2427+ }
2428+
2429+ /* There's no need to stop animations,
2430+ * since the reconnecting animation should not have
2431+ * state OS_STATE_CONNECTED, unless it's ended.
2432+ * Just capture the movement and change adjustment's value (scroll). */
2433+ capture_movement (scrollbar, event->x_root, event->y_root);
2434+ }
2435+ else
2436+ {
2437+ /* This is a fine scroll, works subtly different.
2438+ * It has to take care of reconnection,
2439+ * and scrolling is not allowed when hitting an edge. */
2440
2441 /* Limit x and y within the allocation. */
2442 if (priv->orientation == GTK_ORIENTATION_VERTICAL)
2443 {
2444- x = priv->win_x;
2445- y = CLAMP (event->y_root - priv->pointer_y,
2446- priv->win_y,
2447- priv->win_y + priv->thumb_all.height - priv->slider.height);
2448+ x = priv->thumb_win.x;
2449+ y = CLAMP (event->y_root - priv->pointer.y,
2450+ priv->thumb_win.y,
2451+ priv->thumb_win.y + priv->thumb_all.height - priv->slider.height);
2452 }
2453 else
2454 {
2455- x = CLAMP (event->x_root - priv->pointer_x,
2456- priv->win_x,
2457- priv->win_x + priv->thumb_all.width - priv->slider.width);
2458- y = priv->win_y;
2459+ x = CLAMP (event->x_root - priv->pointer.x,
2460+ priv->thumb_win.x,
2461+ priv->thumb_win.x + priv->thumb_all.width - priv->slider.width);
2462+ y = priv->thumb_win.y;
2463 }
2464
2465 /* Fine scroll while detached,
2466 * do not scroll when hitting an edge. */
2467 if ((priv->orientation == GTK_ORIENTATION_VERTICAL &&
2468- y > priv->win_y &&
2469- y < priv->win_y + priv->thumb_all.height - priv->slider.height) ||
2470+ y > priv->thumb_win.y &&
2471+ y < priv->thumb_win.y + priv->thumb_all.height - priv->slider.height) ||
2472 (priv->orientation == GTK_ORIENTATION_HORIZONTAL &&
2473- x > priv->win_x &&
2474- x < priv->win_x + priv->thumb_all.width - priv->slider.width))
2475- capture_movement (scrollbar, event->x_root, event->y_root);
2476-
2477- move_thumb (scrollbar, x, y);
2478-
2479- if (priv->orientation == GTK_ORIENTATION_VERTICAL)
2480- {
2481- if (gtk_adjustment_get_value (priv->adjustment) == 0)
2482- {
2483- update_visual_connection (scrollbar);
2484-
2485- if (priv->overlay.height > priv->slider.height)
2486- {
2487- priv->slide_initial_slider_position = 0;
2488- priv->slide_initial_coordinate = MAX (event->y_root, priv->win_y + priv->pointer_y);
2489- }
2490- else
2491- {
2492- priv->slide_initial_slider_position = 0;
2493- priv->slide_initial_coordinate = event->y_root;
2494- }
2495- }
2496- else if (priv->overlay.y + priv->overlay.height >= priv->trough.height)
2497- {
2498- update_visual_connection (scrollbar);
2499-
2500- if (priv->overlay.height > priv->slider.height)
2501- {
2502- priv->slide_initial_slider_position = priv->trough.height - priv->overlay.height;
2503- priv->slide_initial_coordinate = MAX (event->y_root, priv->win_y + priv->pointer_y);
2504- }
2505- else
2506- {
2507- priv->slide_initial_slider_position = priv->trough.height - priv->slider.height;
2508- priv->slide_initial_coordinate = event->y_root;
2509- }
2510- }
2511- }
2512- else
2513- {
2514- if (gtk_adjustment_get_value (priv->adjustment) == 0)
2515- {
2516- update_visual_connection (scrollbar);
2517-
2518- if (priv->overlay.width > priv->slider.width)
2519- {
2520- priv->slide_initial_slider_position = 0;
2521- priv->slide_initial_coordinate = MAX (event->x_root, priv->win_x + priv->pointer_x);
2522- }
2523- else
2524- {
2525- priv->slide_initial_slider_position = 0;
2526- priv->slide_initial_coordinate = event->x_root;
2527- }
2528- }
2529- else if (priv->overlay.x + priv->overlay.width >= priv->trough.width)
2530- {
2531- update_visual_connection (scrollbar);
2532-
2533- if (priv->overlay.width > priv->slider.width)
2534- {
2535- priv->slide_initial_slider_position = priv->trough.width - priv->overlay.width;
2536- priv->slide_initial_coordinate = MAX (event->x_root, priv->win_x + priv->pointer_x);
2537- }
2538- else
2539- {
2540- priv->slide_initial_slider_position = priv->trough.width - priv->slider.width;
2541- priv->slide_initial_coordinate = event->x_root;
2542- }
2543- }
2544- }
2545-
2546- return FALSE;
2547- }
2548-
2549- OS_DCHECK (!priv->detached_scroll);
2550-
2551- /* Thumb and pager are connected.
2552- * Normal scroll: keep the thumb in sync with the pager,
2553- * do not update the visual connection. */
2554- priv->event |= OS_EVENT_MOTION_NOTIFY;
2555-
2556- capture_movement (scrollbar, event->x_root, event->y_root);
2557-
2558- if (priv->orientation == GTK_ORIENTATION_VERTICAL)
2559- {
2560- if (priv->overlay.height > priv->slider.height)
2561- {
2562- /* Limit x and y within the overlay. */
2563- x = priv->win_x;
2564- y = CLAMP (event->y_root - priv->pointer_y,
2565- priv->win_y + priv->overlay.y,
2566- priv->win_y + priv->overlay.y + priv->overlay.height - priv->slider.height);
2567-
2568- if (gtk_adjustment_get_value (priv->adjustment) == 0)
2569- {
2570- priv->slide_initial_slider_position = 0;
2571- priv->slide_initial_coordinate = MAX (event->y_root, priv->win_y + priv->pointer_y);
2572- }
2573- else if (priv->overlay.y + priv->overlay.height >= priv->trough.height)
2574- {
2575- priv->slide_initial_slider_position = priv->trough.height - priv->overlay.height;
2576- priv->slide_initial_coordinate = MAX (event->y_root, priv->win_y + priv->pointer_y);
2577- }
2578- }
2579- else
2580- {
2581- x = priv->win_x;
2582- y = priv->win_y + priv->slider.y;
2583- }
2584- }
2585- else
2586- {
2587- if (priv->overlay.width > priv->slider.width)
2588- {
2589- /* Limit x and y within the overlay. */
2590- x = CLAMP (event->x_root - priv->pointer_x,
2591- priv->win_x + priv->overlay.x,
2592- priv->win_x + priv->overlay.x + priv->overlay.width - priv->slider.width);
2593- y = priv->win_y;
2594-
2595- if (gtk_adjustment_get_value (priv->adjustment) == 0)
2596- {
2597- priv->slide_initial_slider_position = 0;
2598- priv->slide_initial_coordinate = MAX (event->x_root, priv->win_x + priv->pointer_x);
2599- }
2600- else if (priv->overlay.x + priv->overlay.width >= priv->trough.width)
2601- {
2602- priv->slide_initial_slider_position = priv->trough.width - priv->overlay.width;
2603- priv->slide_initial_coordinate = MAX (event->x_root, priv->win_x + priv->pointer_x);
2604- }
2605- }
2606- else
2607- {
2608- x = priv->win_x + priv->slider.x;
2609- y = priv->win_y;
2610- }
2611- }
2612-
2613+ x > priv->thumb_win.x &&
2614+ x < priv->thumb_win.x + priv->thumb_all.width - priv->slider.width))
2615+ {
2616+ /* Stop the animation now.
2617+ * Only the reconnecting animation can be running now,
2618+ * because the paging animations were stop before. */
2619+ os_animation_stop (priv->animation, NULL);
2620+
2621+ /* Capture the movement and change adjustment's value (scroll). */
2622+ capture_movement (scrollbar, event->x_root, event->y_root);
2623+ }
2624+ else if (!os_animation_is_running (priv->animation) &&
2625+ !(priv->state & OS_STATE_DETACHED))
2626+ {
2627+ /* Animate scrolling till reaches the edge. */
2628+ if ((priv->orientation == GTK_ORIENTATION_VERTICAL && y <= priv->thumb_win.y) ||
2629+ (priv->orientation == GTK_ORIENTATION_HORIZONTAL && x <= priv->thumb_win.x))
2630+ priv->value = gtk_adjustment_get_lower (priv->adjustment);
2631+ else
2632+ priv->value = gtk_adjustment_get_upper (priv->adjustment) -
2633+ gtk_adjustment_get_page_size (priv->adjustment);
2634+
2635+ /* Proceed with the reconnection only if needed. */
2636+ if (priv->value != gtk_adjustment_get_value (priv->adjustment))
2637+ {
2638+ /* If the thumb is not detached, proceed with reconnection. */
2639+ priv->state |= OS_STATE_RECONNECTING;
2640+
2641+ os_animation_set_duration (priv->animation, MIN_DURATION_SCROLLING);
2642+
2643+ /* Start the scrolling animation. */
2644+ os_animation_start (priv->animation);
2645+ }
2646+ }
2647+ }
2648+
2649+ /* Move the thumb window. */
2650 move_thumb (scrollbar, x, y);
2651+
2652+ /* Adjust slide values in some special situations,
2653+ * update the tail if the thumb is detached and
2654+ * check if the movement changed the thumb state to connected. */
2655+ if (priv->orientation == GTK_ORIENTATION_VERTICAL)
2656+ {
2657+ if (gtk_adjustment_get_value (priv->adjustment) <= gtk_adjustment_get_lower (priv->adjustment))
2658+ {
2659+ if (priv->state & OS_STATE_DETACHED)
2660+ update_tail (scrollbar);
2661+
2662+ if (!(priv->state & OS_STATE_CONNECTED))
2663+ check_connection (scrollbar);
2664+
2665+ priv->slide_initial_slider_position = 0;
2666+ priv->slide_initial_coordinate = MAX (event->y_root, priv->thumb_win.y + priv->pointer.y);
2667+ }
2668+ else if (priv->overlay.y + priv->overlay.height >= priv->trough.height)
2669+ {
2670+ if (priv->state & OS_STATE_DETACHED)
2671+ update_tail (scrollbar);
2672+
2673+ if (!(priv->state & OS_STATE_CONNECTED))
2674+ check_connection (scrollbar);
2675+
2676+ priv->slide_initial_slider_position = priv->trough.height - MAX (priv->overlay.height, priv->slider.height);
2677+ priv->slide_initial_coordinate = MIN (event->y_root, (priv->thumb_win.y + priv->trough.height -
2678+ priv->slider.height + priv->pointer.y));
2679+ }
2680+ }
2681+ else
2682+ {
2683+ if (gtk_adjustment_get_value (priv->adjustment) <= gtk_adjustment_get_lower (priv->adjustment))
2684+ {
2685+ if (priv->state & OS_STATE_DETACHED)
2686+ update_tail (scrollbar);
2687+
2688+ if (!(priv->state & OS_STATE_CONNECTED))
2689+ check_connection (scrollbar);
2690+
2691+ priv->slide_initial_slider_position = 0;
2692+ priv->slide_initial_coordinate = MAX (event->x_root, priv->thumb_win.x + priv->pointer.x);
2693+ }
2694+ else if (priv->overlay.x + priv->overlay.width >= priv->trough.width)
2695+ {
2696+ if (priv->state & OS_STATE_DETACHED)
2697+ update_tail (scrollbar);
2698+
2699+ if (!(priv->state & OS_STATE_CONNECTED))
2700+ check_connection (scrollbar);
2701+
2702+ priv->slide_initial_slider_position = priv->trough.width - MAX (priv->overlay.width, priv->slider.width);
2703+ priv->slide_initial_coordinate = MIN (event->x_root, (priv->thumb_win.x + priv->trough.width -
2704+ priv->slider.width + priv->pointer.x));
2705+ }
2706+ }
2707 }
2708
2709 return FALSE;
2710@@ -1836,11 +2031,9 @@
2711 scrollbar = OS_SCROLLBAR (user_data);
2712 priv = scrollbar->priv;
2713
2714- /* Stop the paging animation if it's running. */
2715+ /* Stop the scrolling animation if it's running. */
2716 os_animation_stop (priv->animation, NULL);
2717
2718- priv->event |= OS_EVENT_VALUE_CHANGED;
2719-
2720 delta = get_wheel_delta (scrollbar, event->direction);
2721
2722 gtk_adjustment_set_value (priv->adjustment,
2723@@ -1849,6 +2042,25 @@
2724 (gtk_adjustment_get_upper (priv->adjustment) -
2725 gtk_adjustment_get_page_size (priv->adjustment))));
2726
2727+ /* Deal with simultaneous events. */
2728+ if (priv->event & OS_EVENT_BUTTON_PRESS)
2729+ {
2730+ priv->event &= ~(OS_EVENT_MOTION_NOTIFY);
2731+
2732+ /* we need to update the slide values
2733+ * with the current position. */
2734+ if (priv->orientation == GTK_ORIENTATION_VERTICAL)
2735+ {
2736+ priv->slide_initial_slider_position = MIN (priv->slider.y, priv->overlay.y);
2737+ priv->slide_initial_coordinate = event->y_root;
2738+ }
2739+ else
2740+ {
2741+ priv->slide_initial_slider_position = MIN (priv->slider.x, priv->overlay.x);
2742+ priv->slide_initial_coordinate = event->x_root;
2743+ }
2744+ }
2745+
2746 return FALSE;
2747 }
2748
2749@@ -1863,31 +2075,28 @@
2750 priv = scrollbar->priv;
2751
2752 priv->event = OS_EVENT_NONE;
2753-
2754- priv->detached_scroll = FALSE;
2755-
2756- os_pager_set_detached (priv->pager, FALSE);
2757+ priv->hidable_thumb = TRUE;
2758+
2759+ /* Remove running hide timeout, if there is one. */
2760+ if (priv->source_hide_thumb_id != 0)
2761+ {
2762+ g_source_remove (priv->source_hide_thumb_id);
2763+ priv->source_hide_thumb_id = 0;
2764+ }
2765+
2766+ /* This could hardly still be running,
2767+ * but it is not impossible. */
2768+ if (priv->source_show_thumb_id != 0)
2769+ {
2770+ g_source_remove (priv->source_show_thumb_id);
2771+ priv->source_show_thumb_id = 0;
2772+ }
2773+
2774+ os_bar_set_detached (priv->bar, FALSE, TRUE);
2775 }
2776
2777 /* Toplevel functions. */
2778
2779-/* Store the position of the toplevel window. */
2780-static void
2781-store_toplevel_position (OsScrollbar *scrollbar)
2782-{
2783- OsScrollbarPrivate *priv;
2784- gint x_pos, y_pos;
2785-
2786- priv = scrollbar->priv;
2787-
2788- /* In reality, I'm storing widget's window, not the toplevel.
2789- * Is that the same with gdk_window_get_origin? */
2790- gdk_window_get_origin (gtk_widget_get_window (GTK_WIDGET (scrollbar)), &x_pos, &y_pos);
2791-
2792- priv->win_x = x_pos + priv->thumb_all.x;
2793- priv->win_y = y_pos + priv->thumb_all.y;
2794-}
2795-
2796 static gboolean
2797 toplevel_configure_event_cb (GtkWidget *widget,
2798 GdkEventConfigure *event,
2799@@ -1902,7 +2111,7 @@
2800 * and the configure-event happens after
2801 * the PropertyNotify _NET_ACTIVE_WINDOW event,
2802 * see if the mouse pointer is over this window, if TRUE,
2803- * proceed with pager_set_state_from_pointer. */
2804+ * proceed with bar_set_state_from_pointer (). */
2805 if (!is_insensitive (scrollbar) &&
2806 (current_time > end_time) &&
2807 gtk_widget_get_mapped (GTK_WIDGET (scrollbar)))
2808@@ -1932,34 +2141,67 @@
2809 /* When the window is resized (maximize/restore),
2810 * check the position of the pointer
2811 * and set the state accordingly. */
2812- pager_set_state_from_pointer (scrollbar, x, y);
2813+ bar_set_state_from_pointer (scrollbar, x, y);
2814 }
2815 }
2816 else
2817 {
2818- priv->can_deactivate_pager = FALSE;
2819- os_pager_set_active (priv->pager, TRUE, TRUE);
2820+ priv->deactivable_bar = FALSE;
2821+ os_bar_set_active (priv->bar, TRUE, TRUE);
2822 }
2823 }
2824
2825 if (current_time > end_time)
2826 gtk_widget_hide (priv->thumb);
2827
2828- priv->lock_position = FALSE;
2829+ priv->state &= ~(OS_STATE_LOCKED);
2830
2831- calc_layout_pager (scrollbar, gtk_adjustment_get_value (priv->adjustment));
2832+ calc_layout_bar (scrollbar, gtk_adjustment_get_value (priv->adjustment));
2833 calc_layout_slider (scrollbar, gtk_adjustment_get_value (priv->adjustment));
2834
2835- store_toplevel_position (scrollbar);
2836+ calc_thumb_window_position (scrollbar);
2837
2838 return FALSE;
2839 }
2840
2841+/* widget's window functions. */
2842+
2843+/* Move the thumb in the proximity area. */
2844+static void
2845+adjust_thumb_position (OsScrollbar *scrollbar,
2846+ gdouble event_x,
2847+ gdouble event_y)
2848+{
2849+ OsScrollbarPrivate *priv;
2850+ gint x, y, x_pos, y_pos;
2851+
2852+ priv = scrollbar->priv;
2853+
2854+ gdk_window_get_origin (gtk_widget_get_window (GTK_WIDGET (scrollbar)), &x_pos, &y_pos);
2855+
2856+ if (priv->orientation == GTK_ORIENTATION_VERTICAL)
2857+ {
2858+ x = priv->thumb_all.x;
2859+ y = CLAMP (event_y - priv->slider.height / 2,
2860+ priv->thumb_all.y,
2861+ priv->thumb_all.y + priv->thumb_all.height - priv->slider.height);
2862+ }
2863+ else
2864+ {
2865+ x = CLAMP (event_x - priv->slider.width / 2,
2866+ priv->thumb_all.x,
2867+ priv->thumb_all.x + priv->thumb_all.width - priv->slider.width);
2868+ y = priv->thumb_all.y;
2869+ }
2870+
2871+ move_thumb (scrollbar, x_pos + x, y_pos + y);
2872+}
2873+
2874 /* Checks if the pointer is in the proximity area. */
2875 static gboolean
2876 check_proximity (OsScrollbar *scrollbar,
2877- gint x,
2878- gint y)
2879+ gint x,
2880+ gint y)
2881 {
2882 OsScrollbarPrivate *priv;
2883
2884@@ -1968,28 +2210,28 @@
2885 switch (priv->side)
2886 {
2887 case OS_SIDE_RIGHT:
2888- return (x >= priv->pager_all.x + priv->pager_all.width - PROXIMITY_SIZE &&
2889- x <= priv->pager_all.x + priv->pager_all.width) &&
2890- (y >= priv->pager_all.y + priv->overlay.y &&
2891- y <= priv->pager_all.y + priv->overlay.y + priv->overlay.height);
2892+ return (x >= priv->bar_all.x + priv->bar_all.width - PROXIMITY_SIZE &&
2893+ x <= priv->bar_all.x + priv->bar_all.width) &&
2894+ (y >= priv->bar_all.y &&
2895+ y <= priv->bar_all.y + priv->bar_all.height);
2896 break;
2897 case OS_SIDE_BOTTOM:
2898- return (y >= priv->pager_all.y + priv->pager_all.height - PROXIMITY_SIZE &&
2899- y <= priv->pager_all.y + priv->pager_all.height) &&
2900- (x >= priv->pager_all.x + priv->overlay.x &&
2901- x <= priv->pager_all.x + priv->overlay.x + priv->overlay.width);
2902+ return (y >= priv->bar_all.y + priv->bar_all.height - PROXIMITY_SIZE &&
2903+ y <= priv->bar_all.y + priv->bar_all.height) &&
2904+ (x >= priv->bar_all.x &&
2905+ x <= priv->bar_all.x + priv->bar_all.width);
2906 break;
2907 case OS_SIDE_LEFT:
2908- return (x <= priv->pager_all.x + priv->pager_all.width + PROXIMITY_SIZE &&
2909- x >= priv->pager_all.x) &&
2910- (y >= priv->pager_all.y + priv->overlay.y &&
2911- y <= priv->pager_all.y + priv->overlay.y + priv->overlay.height);
2912+ return (x <= priv->bar_all.x + priv->bar_all.width + PROXIMITY_SIZE &&
2913+ x >= priv->bar_all.x) &&
2914+ (y >= priv->bar_all.y &&
2915+ y <= priv->bar_all.y + priv->bar_all.height);
2916 break;
2917 case OS_SIDE_TOP:
2918- return (y <= priv->pager_all.y + priv->pager_all.height + PROXIMITY_SIZE &&
2919- y >= priv->pager_all.y) &&
2920- (x >= priv->pager_all.x + priv->overlay.x &&
2921- x <= priv->pager_all.x + priv->overlay.x + priv->overlay.width);
2922+ return (y <= priv->bar_all.y + priv->bar_all.height + PROXIMITY_SIZE &&
2923+ y >= priv->bar_all.y) &&
2924+ (x >= priv->bar_all.x &&
2925+ x <= priv->bar_all.x + priv->bar_all.width);
2926 break;
2927 default:
2928 break;
2929@@ -1998,6 +2240,64 @@
2930 return FALSE;
2931 }
2932
2933+/* Callback that shows the thumb if it's the case. */
2934+static gboolean
2935+show_thumb_cb (gpointer user_data)
2936+{
2937+ OsScrollbar *scrollbar;
2938+ OsScrollbarPrivate *priv;
2939+
2940+ scrollbar = OS_SCROLLBAR (user_data);
2941+ priv = scrollbar->priv;
2942+
2943+ if (!priv->hidable_thumb)
2944+ {
2945+ gtk_widget_show (priv->thumb);
2946+
2947+ update_tail (scrollbar);
2948+ }
2949+
2950+ priv->source_show_thumb_id = 0;
2951+
2952+ return FALSE;
2953+}
2954+
2955+/* Adds a timeout to reveal the thumb. */
2956+static void
2957+show_thumb (OsScrollbar *scrollbar)
2958+{
2959+ OsScrollbarPrivate *priv;
2960+
2961+ priv = scrollbar->priv;
2962+
2963+ /* Just update the tail if the thumb is already mapped. */
2964+ if (gtk_widget_get_mapped (priv->thumb))
2965+ {
2966+ update_tail (scrollbar);
2967+ return;
2968+ }
2969+
2970+ if (priv->state & OS_STATE_INTERNAL)
2971+ {
2972+ /* If the scrollbar is close to one edge of the screen,
2973+ * show it immediately, ignoring the timeout,
2974+ * to preserve Fitts' law. */
2975+ if (priv->source_show_thumb_id != 0)
2976+ {
2977+ g_source_remove (priv->source_show_thumb_id);
2978+ priv->source_show_thumb_id = 0;
2979+ }
2980+
2981+ gtk_widget_show (priv->thumb);
2982+
2983+ update_tail (scrollbar);
2984+ }
2985+ else if (priv->source_show_thumb_id == 0)
2986+ priv->source_show_thumb_id = g_timeout_add (TIMEOUT_THUMB_SHOW,
2987+ show_thumb_cb,
2988+ scrollbar);
2989+}
2990+
2991 /* Filter function applied to the toplevel window. */
2992 #ifdef USE_GTK3
2993 typedef enum
2994@@ -2025,10 +2325,10 @@
2995
2996 xev = gdkxevent;
2997
2998- g_return_val_if_fail (OS_IS_PAGER (priv->pager), GDK_FILTER_CONTINUE);
2999+ g_return_val_if_fail (OS_IS_BAR (priv->bar), GDK_FILTER_CONTINUE);
3000 g_return_val_if_fail (OS_IS_THUMB (priv->thumb), GDK_FILTER_CONTINUE);
3001
3002- if (!priv->fullsize)
3003+ if (!(priv->state & OS_STATE_FULLSIZE))
3004 {
3005 OsXEvent os_xevent;
3006 gdouble event_x, event_y;
3007@@ -2092,101 +2392,72 @@
3008
3009 if (os_xevent == OS_XEVENT_BUTTON_PRESS)
3010 {
3011- priv->toplevel_button_press = TRUE;
3012+ priv->window_button_press = TRUE;
3013+
3014+ if (priv->source_show_thumb_id != 0)
3015+ {
3016+ g_source_remove (priv->source_show_thumb_id);
3017+ priv->source_show_thumb_id = 0;
3018+ }
3019+
3020 gtk_widget_hide (priv->thumb);
3021 }
3022
3023- if (priv->toplevel_button_press && os_xevent == OS_XEVENT_BUTTON_RELEASE)
3024+ if (priv->window_button_press && os_xevent == OS_XEVENT_BUTTON_RELEASE)
3025 {
3026- priv->toplevel_button_press = FALSE;
3027+ priv->window_button_press = FALSE;
3028
3029 /* Proximity area. */
3030- if (priv->orientation == GTK_ORIENTATION_VERTICAL)
3031- {
3032- if (check_proximity (scrollbar, event_x, event_y))
3033- {
3034- priv->can_hide = FALSE;
3035-
3036- if (priv->lock_position)
3037- return GDK_FILTER_CONTINUE;
3038-
3039- if (priv->overlay.height > priv->slider.height)
3040- {
3041- gint x, y, x_pos, y_pos;
3042-
3043- gdk_window_get_origin (gtk_widget_get_window (GTK_WIDGET (scrollbar)), &x_pos, &y_pos);
3044-
3045- x = priv->thumb_all.x;
3046- y = CLAMP (event_y - priv->slider.height / 2,
3047- priv->thumb_all.y + priv->overlay.y,
3048- priv->thumb_all.y + priv->overlay.y + priv->overlay.height - priv->slider.height);
3049-
3050- move_thumb (scrollbar, x_pos + x, y_pos + y);
3051- }
3052- else
3053- {
3054- move_thumb (scrollbar, priv->win_x, priv->win_y + priv->slider.y);
3055- }
3056-
3057- gtk_widget_show (priv->thumb);
3058- }
3059- }
3060- else
3061- {
3062- if (check_proximity (scrollbar, event_x, event_y))
3063- {
3064- priv->can_hide = FALSE;
3065-
3066- if (priv->lock_position)
3067- return GDK_FILTER_CONTINUE;
3068-
3069- if (priv->overlay.width > priv->slider.width)
3070- {
3071- gint x, y, x_pos, y_pos;
3072-
3073- gdk_window_get_origin (gtk_widget_get_window (GTK_WIDGET (scrollbar)), &x_pos, &y_pos);
3074-
3075- x = CLAMP (event_x - priv->slider.width / 2,
3076- priv->thumb_all.x + priv->overlay.x,
3077- priv->thumb_all.x + priv->overlay.x + priv->overlay.width - priv->slider.width);
3078- y = priv->thumb_all.y;
3079-
3080- move_thumb (scrollbar, x_pos + x, y_pos + y);
3081- }
3082- else
3083- {
3084- move_thumb (scrollbar, priv->win_x, priv->win_y + priv->slider.y);
3085- }
3086-
3087- gtk_widget_show (priv->thumb);
3088- }
3089+ if (check_proximity (scrollbar, event_x, event_y))
3090+ {
3091+ priv->hidable_thumb = FALSE;
3092+
3093+ if (priv->state & OS_STATE_LOCKED)
3094+ return GDK_FILTER_CONTINUE;
3095+
3096+ adjust_thumb_position (scrollbar, event_x, event_y);
3097+
3098+ gtk_widget_show (priv->thumb);
3099+
3100+ update_tail (scrollbar);
3101 }
3102 }
3103
3104 if (os_xevent == OS_XEVENT_LEAVE)
3105 {
3106- /* Never deactivate the pager in an active window. */
3107+ priv->window_button_press = FALSE;
3108+
3109+ /* Never deactivate the bar in an active window. */
3110 if (!priv->active_window)
3111 {
3112- priv->can_deactivate_pager = TRUE;
3113-
3114- if (priv->source_deactivate_pager_id != 0)
3115- g_source_remove (priv->source_deactivate_pager_id);
3116-
3117- priv->source_deactivate_pager_id = g_timeout_add (TIMEOUT_TOPLEVEL_HIDE,
3118- deactivate_pager_cb,
3119- scrollbar);
3120- }
3121-
3122- priv->toplevel_button_press = FALSE;
3123- priv->can_hide = TRUE;
3124-
3125- if (priv->source_hide_thumb_id != 0)
3126- g_source_remove (priv->source_hide_thumb_id);
3127-
3128- priv->source_hide_thumb_id = g_timeout_add (TIMEOUT_TOPLEVEL_HIDE,
3129- hide_thumb_cb,
3130- scrollbar);
3131+ priv->deactivable_bar = TRUE;
3132+
3133+ if (priv->source_deactivate_bar_id != 0)
3134+ g_source_remove (priv->source_deactivate_bar_id);
3135+
3136+ priv->source_deactivate_bar_id = g_timeout_add (TIMEOUT_TOPLEVEL_HIDE,
3137+ deactivate_bar_cb,
3138+ scrollbar);
3139+ }
3140+
3141+ if (gtk_widget_get_mapped (priv->thumb) &&
3142+ !(priv->event & OS_EVENT_BUTTON_PRESS))
3143+ {
3144+ priv->hidable_thumb = TRUE;
3145+
3146+ if (priv->source_hide_thumb_id != 0)
3147+ g_source_remove (priv->source_hide_thumb_id);
3148+
3149+ priv->source_hide_thumb_id = g_timeout_add (TIMEOUT_TOPLEVEL_HIDE,
3150+ hide_thumb_cb,
3151+ scrollbar);
3152+ }
3153+
3154+ if (priv->source_show_thumb_id != 0)
3155+ {
3156+ g_source_remove (priv->source_show_thumb_id);
3157+ priv->source_show_thumb_id = 0;
3158+ }
3159
3160 if (priv->source_unlock_thumb_id != 0)
3161 g_source_remove (priv->source_unlock_thumb_id);
3162@@ -2197,107 +2468,47 @@
3163 }
3164
3165 /* Get the motion_notify_event trough XEvent. */
3166- if (!priv->toplevel_button_press && os_xevent == OS_XEVENT_MOTION)
3167+ if (!priv->window_button_press && os_xevent == OS_XEVENT_MOTION)
3168 {
3169 /* React to motion_notify_event
3170 * and set the state accordingly. */
3171 if (!is_insensitive (scrollbar) && !priv->active_window)
3172- pager_set_state_from_pointer (scrollbar, event_x, event_y);
3173+ bar_set_state_from_pointer (scrollbar, event_x, event_y);
3174
3175 /* Proximity area. */
3176- if (priv->orientation == GTK_ORIENTATION_VERTICAL)
3177+ if (check_proximity (scrollbar, event_x, event_y))
3178 {
3179- if (check_proximity (scrollbar, event_x, event_y))
3180- {
3181- priv->can_hide = FALSE;
3182-
3183- if (priv->source_hide_thumb_id != 0)
3184- {
3185- g_source_remove (priv->source_hide_thumb_id);
3186- priv->source_hide_thumb_id = 0;
3187- }
3188-
3189- if (priv->lock_position)
3190- return GDK_FILTER_CONTINUE;
3191-
3192- if (priv->overlay.height > priv->slider.height)
3193- {
3194- gint x, y, x_pos, y_pos;
3195-
3196- gdk_window_get_origin (gtk_widget_get_window (GTK_WIDGET (scrollbar)), &x_pos, &y_pos);
3197-
3198- x = priv->thumb_all.x;
3199- y = CLAMP (event_y - priv->slider.height / 2,
3200- priv->thumb_all.y + priv->overlay.y,
3201- priv->thumb_all.y + priv->overlay.y + priv->overlay.height - priv->slider.height);
3202-
3203- move_thumb (scrollbar, x_pos + x, y_pos + y);
3204- }
3205- else
3206- {
3207- move_thumb (scrollbar, priv->win_x, priv->win_y + priv->slider.y);
3208- }
3209-
3210- os_pager_set_detached (priv->pager, FALSE);
3211- os_thumb_set_detached (OS_THUMB (priv->thumb), FALSE);
3212- gtk_widget_show (priv->thumb);
3213- }
3214- else
3215- {
3216- priv->can_hide = TRUE;
3217- priv->lock_position = FALSE;
3218-
3219- if (gtk_widget_get_mapped (priv->thumb) &&
3220- priv->source_hide_thumb_id == 0)
3221- priv->source_hide_thumb_id = g_timeout_add (TIMEOUT_PROXIMITY_HIDE,
3222- hide_thumb_cb,
3223- scrollbar);
3224- }
3225+ priv->hidable_thumb = FALSE;
3226+
3227+ if (priv->source_hide_thumb_id != 0)
3228+ {
3229+ g_source_remove (priv->source_hide_thumb_id);
3230+ priv->source_hide_thumb_id = 0;
3231+ }
3232+
3233+ if (priv->state & OS_STATE_LOCKED)
3234+ return GDK_FILTER_CONTINUE;
3235+
3236+ adjust_thumb_position (scrollbar, event_x, event_y);
3237+
3238+ show_thumb (scrollbar);
3239 }
3240 else
3241 {
3242- if (check_proximity (scrollbar, event_x, event_y))
3243+ priv->state &= ~(OS_STATE_LOCKED);
3244+
3245+ if (priv->source_show_thumb_id != 0)
3246 {
3247- priv->can_hide = FALSE;
3248-
3249- if (priv->source_hide_thumb_id != 0)
3250- {
3251- g_source_remove (priv->source_hide_thumb_id);
3252- priv->source_hide_thumb_id = 0;
3253- }
3254-
3255- if (priv->lock_position)
3256- return GDK_FILTER_CONTINUE;
3257-
3258- if (priv->overlay.width > priv->slider.width)
3259- {
3260- gint x, y, x_pos, y_pos;
3261-
3262- gdk_window_get_origin (gtk_widget_get_window (GTK_WIDGET (scrollbar)), &x_pos, &y_pos);
3263-
3264- x = CLAMP (event_x - priv->slider.width / 2,
3265- priv->thumb_all.x + priv->overlay.x,
3266- priv->thumb_all.x + priv->overlay.x + priv->overlay.width - priv->slider.width);
3267- y = priv->thumb_all.y;
3268-
3269- move_thumb (scrollbar, x_pos + x, y_pos + y);
3270- }
3271- else
3272- {
3273- move_thumb (scrollbar, priv->win_x + priv->slider.x, priv->win_y);
3274- }
3275-
3276- os_pager_set_detached (priv->pager, FALSE);
3277- os_thumb_set_detached (OS_THUMB (priv->thumb), FALSE);
3278- gtk_widget_show (priv->thumb);
3279+ g_source_remove (priv->source_show_thumb_id);
3280+ priv->source_show_thumb_id = 0;
3281 }
3282- else
3283+
3284+ if (gtk_widget_get_mapped (priv->thumb) &&
3285+ !(priv->event & OS_EVENT_BUTTON_PRESS))
3286 {
3287- priv->can_hide = TRUE;
3288- priv->lock_position = FALSE;
3289+ priv->hidable_thumb = TRUE;
3290
3291- if (gtk_widget_get_mapped (priv->thumb) &&
3292- priv->source_hide_thumb_id == 0)
3293+ if (priv->source_hide_thumb_id == 0)
3294 priv->source_hide_thumb_id = g_timeout_add (TIMEOUT_PROXIMITY_HIDE,
3295 hide_thumb_cb,
3296 scrollbar);
3297@@ -2325,120 +2536,79 @@
3298
3299 xev = gdkxevent;
3300
3301- g_return_val_if_fail (OS_IS_PAGER (priv->pager), GDK_FILTER_CONTINUE);
3302+ g_return_val_if_fail (OS_IS_BAR (priv->bar), GDK_FILTER_CONTINUE);
3303 g_return_val_if_fail (OS_IS_THUMB (priv->thumb), GDK_FILTER_CONTINUE);
3304
3305- if (!priv->fullsize)
3306+ if (!(priv->state & OS_STATE_FULLSIZE))
3307 {
3308 if (xev->type == ButtonPress)
3309 {
3310- priv->toplevel_button_press = TRUE;
3311+ priv->window_button_press = TRUE;
3312+
3313+ if (priv->source_show_thumb_id != 0)
3314+ {
3315+ g_source_remove (priv->source_show_thumb_id);
3316+ priv->source_show_thumb_id = 0;
3317+ }
3318+
3319 gtk_widget_hide (priv->thumb);
3320 }
3321
3322- if (priv->toplevel_button_press && xev->type == ButtonRelease)
3323+ if (priv->window_button_press && xev->type == ButtonRelease)
3324 {
3325- priv->toplevel_button_press = FALSE;
3326+ priv->window_button_press = FALSE;
3327
3328 /* Proximity area. */
3329- if (priv->orientation == GTK_ORIENTATION_VERTICAL)
3330- {
3331- if (check_proximity (scrollbar, xev->xbutton.x, xev->xbutton.y))
3332- {
3333- priv->can_hide = FALSE;
3334-
3335- if (priv->source_hide_thumb_id != 0)
3336- {
3337- g_source_remove (priv->source_hide_thumb_id);
3338- priv->source_hide_thumb_id = 0;
3339- }
3340-
3341- if (priv->lock_position)
3342- return GDK_FILTER_CONTINUE;
3343-
3344- if (priv->overlay.height > priv->slider.height)
3345- {
3346- gint x, y, x_pos, y_pos;
3347-
3348- gdk_window_get_origin (gtk_widget_get_window (GTK_WIDGET (scrollbar)), &x_pos, &y_pos);
3349-
3350- x = priv->thumb_all.x;
3351- y = CLAMP (xev->xbutton.y - priv->slider.height / 2,
3352- priv->thumb_all.y + priv->overlay.y,
3353- priv->thumb_all.y + priv->overlay.y + priv->overlay.height - priv->slider.height);
3354-
3355- move_thumb (scrollbar, x_pos + x, y_pos + y);
3356- }
3357- else
3358- {
3359- move_thumb (scrollbar, priv->win_x, priv->win_y + priv->slider.y);
3360- }
3361-
3362- gtk_widget_show (priv->thumb);
3363- }
3364- }
3365- else
3366- {
3367- if (check_proximity (scrollbar, xev->xbutton.x, xev->xbutton.y))
3368- {
3369- priv->can_hide = FALSE;
3370-
3371- if (priv->source_hide_thumb_id != 0)
3372- {
3373- g_source_remove (priv->source_hide_thumb_id);
3374- priv->source_hide_thumb_id = 0;
3375- }
3376-
3377- if (priv->lock_position)
3378- return GDK_FILTER_CONTINUE;
3379-
3380- if (priv->overlay.width > priv->slider.width)
3381- {
3382- gint x, y, x_pos, y_pos;
3383-
3384- gdk_window_get_origin (gtk_widget_get_window (GTK_WIDGET (scrollbar)), &x_pos, &y_pos);
3385-
3386- x = CLAMP (xev->xbutton.x - priv->slider.width / 2,
3387- priv->thumb_all.x + priv->overlay.x,
3388- priv->thumb_all.x + priv->overlay.x + priv->overlay.width - priv->slider.width);
3389- y = priv->thumb_all.y;
3390-
3391- move_thumb (scrollbar, x_pos + x, y_pos + y);
3392- }
3393- else
3394- {
3395- move_thumb (scrollbar, priv->win_x, priv->win_y + priv->slider.y);
3396- }
3397-
3398- gtk_widget_show (priv->thumb);
3399- }
3400+ if (check_proximity (scrollbar, xev->xbutton.x, xev->xbutton.y))
3401+ {
3402+ priv->hidable_thumb = FALSE;
3403+
3404+ if (priv->state & OS_STATE_LOCKED)
3405+ return GDK_FILTER_CONTINUE;
3406+
3407+ adjust_thumb_position (scrollbar, xev->xbutton.x, xev->xbutton.y);
3408+
3409+ gtk_widget_show (priv->thumb);
3410+
3411+ update_tail (scrollbar);
3412 }
3413 }
3414
3415 if (xev->type == LeaveNotify)
3416 {
3417- /* Never deactivate the pager in an active window. */
3418+ priv->window_button_press = FALSE;
3419+
3420+ /* Never deactivate the bar in an active window. */
3421 if (!priv->active_window)
3422 {
3423- priv->can_deactivate_pager = TRUE;
3424-
3425- if (priv->source_deactivate_pager_id != 0)
3426- g_source_remove (priv->source_deactivate_pager_id);
3427-
3428- priv->source_deactivate_pager_id = g_timeout_add (TIMEOUT_TOPLEVEL_HIDE,
3429- deactivate_pager_cb,
3430- scrollbar);
3431- }
3432-
3433- priv->toplevel_button_press = FALSE;
3434- priv->can_hide = TRUE;
3435-
3436- if (priv->source_hide_thumb_id != 0)
3437- g_source_remove (priv->source_hide_thumb_id);
3438-
3439- priv->source_hide_thumb_id = g_timeout_add (TIMEOUT_TOPLEVEL_HIDE,
3440- hide_thumb_cb,
3441- scrollbar);
3442+ priv->deactivable_bar = TRUE;
3443+
3444+ if (priv->source_deactivate_bar_id != 0)
3445+ g_source_remove (priv->source_deactivate_bar_id);
3446+
3447+ priv->source_deactivate_bar_id = g_timeout_add (TIMEOUT_TOPLEVEL_HIDE,
3448+ deactivate_bar_cb,
3449+ scrollbar);
3450+ }
3451+
3452+ if (gtk_widget_get_mapped (priv->thumb) &&
3453+ !(priv->event & OS_EVENT_BUTTON_PRESS))
3454+ {
3455+ priv->hidable_thumb = TRUE;
3456+
3457+ if (priv->source_hide_thumb_id != 0)
3458+ g_source_remove (priv->source_hide_thumb_id);
3459+
3460+ priv->source_hide_thumb_id = g_timeout_add (TIMEOUT_TOPLEVEL_HIDE,
3461+ hide_thumb_cb,
3462+ scrollbar);
3463+ }
3464+
3465+ if (priv->source_show_thumb_id != 0)
3466+ {
3467+ g_source_remove (priv->source_show_thumb_id);
3468+ priv->source_show_thumb_id = 0;
3469+ }
3470
3471 if (priv->source_unlock_thumb_id != 0)
3472 g_source_remove (priv->source_unlock_thumb_id);
3473@@ -2449,95 +2619,47 @@
3474 }
3475
3476 /* Get the motion_notify_event trough XEvent. */
3477- if (!priv->toplevel_button_press && xev->type == MotionNotify)
3478+ if (!priv->window_button_press && xev->type == MotionNotify)
3479 {
3480 /* React to motion_notify_event
3481 * and set the state accordingly. */
3482 if (!is_insensitive (scrollbar) && !priv->active_window)
3483- pager_set_state_from_pointer (scrollbar, xev->xmotion.x, xev->xmotion.y);
3484+ bar_set_state_from_pointer (scrollbar, xev->xmotion.x, xev->xmotion.y);
3485
3486 /* Proximity area. */
3487- if (priv->orientation == GTK_ORIENTATION_VERTICAL)
3488+ if (check_proximity (scrollbar, xev->xmotion.x, xev->xmotion.y))
3489 {
3490- if (check_proximity (scrollbar, xev->xmotion.x, xev->xmotion.y))
3491- {
3492- priv->can_hide = FALSE;
3493-
3494- if (priv->lock_position)
3495- return GDK_FILTER_CONTINUE;
3496-
3497- if (priv->overlay.height > priv->slider.height)
3498- {
3499- gint x, y, x_pos, y_pos;
3500-
3501- gdk_window_get_origin (gtk_widget_get_window (GTK_WIDGET (scrollbar)), &x_pos, &y_pos);
3502-
3503- x = priv->thumb_all.x;
3504- y = CLAMP (xev->xmotion.y - priv->slider.height / 2,
3505- priv->thumb_all.y + priv->overlay.y,
3506- priv->thumb_all.y + priv->overlay.y + priv->overlay.height - priv->slider.height);
3507-
3508- move_thumb (scrollbar, x_pos + x, y_pos + y);
3509- }
3510- else
3511- {
3512- move_thumb (scrollbar, priv->win_x, priv->win_y + priv->slider.y);
3513- }
3514-
3515- os_pager_set_detached (priv->pager, FALSE);
3516- os_thumb_set_detached (OS_THUMB (priv->thumb), FALSE);
3517- gtk_widget_show (priv->thumb);
3518- }
3519- else
3520- {
3521- priv->can_hide = TRUE;
3522- priv->lock_position = FALSE;
3523-
3524- if (gtk_widget_get_mapped (priv->thumb) &&
3525- priv->source_hide_thumb_id == 0)
3526- priv->source_hide_thumb_id = g_timeout_add (TIMEOUT_PROXIMITY_HIDE,
3527- hide_thumb_cb,
3528- scrollbar);
3529- }
3530+ priv->hidable_thumb = FALSE;
3531+
3532+ if (priv->source_hide_thumb_id != 0)
3533+ {
3534+ g_source_remove (priv->source_hide_thumb_id);
3535+ priv->source_hide_thumb_id = 0;
3536+ }
3537+
3538+ if (priv->state & OS_STATE_LOCKED)
3539+ return GDK_FILTER_CONTINUE;
3540+
3541+ adjust_thumb_position (scrollbar, xev->xmotion.x, xev->xmotion.y);
3542+
3543+ show_thumb (scrollbar);
3544 }
3545 else
3546 {
3547- if (check_proximity (scrollbar, xev->xmotion.x, xev->xmotion.y))
3548+ priv->state &= ~(OS_STATE_LOCKED);
3549+
3550+ if (priv->source_show_thumb_id != 0)
3551 {
3552- priv->can_hide = FALSE;
3553-
3554- if (priv->lock_position)
3555- return GDK_FILTER_CONTINUE;
3556-
3557- if (priv->overlay.width > priv->slider.width)
3558- {
3559- gint x, y, x_pos, y_pos;
3560-
3561- gdk_window_get_origin (gtk_widget_get_window (GTK_WIDGET (scrollbar)), &x_pos, &y_pos);
3562-
3563- x = CLAMP (xev->xmotion.x - priv->slider.width / 2,
3564- priv->thumb_all.x + priv->overlay.x,
3565- priv->thumb_all.x + priv->overlay.x + priv->overlay.width - priv->slider.width);
3566- y = priv->thumb_all.y;
3567-
3568- move_thumb (scrollbar, x_pos + x, y_pos + y);
3569- }
3570- else
3571- {
3572- move_thumb (scrollbar, priv->win_x + priv->slider.x, priv->win_y);
3573- }
3574-
3575- os_pager_set_detached (priv->pager, FALSE);
3576- os_thumb_set_detached (OS_THUMB (priv->thumb), FALSE);
3577- gtk_widget_show (priv->thumb);
3578+ g_source_remove (priv->source_show_thumb_id);
3579+ priv->source_show_thumb_id = 0;
3580 }
3581- else
3582+
3583+ if (gtk_widget_get_mapped (priv->thumb) &&
3584+ !(priv->event & OS_EVENT_BUTTON_PRESS))
3585 {
3586- priv->can_hide = TRUE;
3587- priv->lock_position = FALSE;
3588+ priv->hidable_thumb = TRUE;
3589
3590- if (gtk_widget_get_mapped (priv->thumb) &&
3591- priv->source_hide_thumb_id == 0)
3592+ if (priv->source_hide_thumb_id == 0)
3593 priv->source_hide_thumb_id = g_timeout_add (TIMEOUT_PROXIMITY_HIDE,
3594 hide_thumb_cb,
3595 scrollbar);
3596@@ -2550,6 +2672,44 @@
3597 }
3598 #endif
3599
3600+/* Add the window filter function. */
3601+static void
3602+add_window_filter (OsScrollbar *scrollbar)
3603+{
3604+ OsScrollbarPrivate *priv;
3605+
3606+ priv = scrollbar->priv;
3607+
3608+ /* Don't add duplicated filters. */
3609+ if (!priv->filter.running &&
3610+ gtk_widget_get_realized (GTK_WIDGET (scrollbar)))
3611+ {
3612+ priv->filter.running = TRUE;
3613+ gdk_window_add_filter (gtk_widget_get_window (GTK_WIDGET (scrollbar)),
3614+ window_filter_func,
3615+ scrollbar);
3616+ }
3617+}
3618+
3619+/* Remove the window filter function. */
3620+static void
3621+remove_window_filter (OsScrollbar *scrollbar)
3622+{
3623+ OsScrollbarPrivate *priv;
3624+
3625+ priv = scrollbar->priv;
3626+
3627+ /* Remove only if the filter is running. */
3628+ if (priv->filter.running &&
3629+ gtk_widget_get_realized (GTK_WIDGET (scrollbar)))
3630+ {
3631+ priv->filter.running = FALSE;
3632+ gdk_window_remove_filter (gtk_widget_get_window (GTK_WIDGET (scrollbar)),
3633+ window_filter_func,
3634+ scrollbar);
3635+ }
3636+}
3637+
3638 G_DEFINE_TYPE (OsScrollbar, os_scrollbar, GTK_TYPE_SCROLLBAR);
3639
3640 static void
3641@@ -2634,27 +2794,34 @@
3642
3643 priv->event = OS_EVENT_NONE;
3644
3645+ priv->state = OS_STATE_NONE;
3646+
3647+ priv->side = OS_SIDE_RIGHT;
3648+
3649+ priv->filter.proximity = FALSE;
3650+ priv->filter.running = FALSE;
3651+
3652 priv->active_window = FALSE;
3653- priv->can_deactivate_pager = TRUE;
3654- priv->can_hide = TRUE;
3655- priv->detached_scroll = FALSE;
3656- priv->filter = FALSE;
3657- priv->fullsize = FALSE;
3658- priv->internal = FALSE;
3659- priv->lock_position = FALSE;
3660- priv->proximity = FALSE;
3661- priv->toplevel_button_press = FALSE;
3662- priv->side = OS_SIDE_RIGHT;
3663- priv->source_deactivate_pager_id = 0;
3664+ priv->deactivable_bar = TRUE;
3665+ priv->hidable_thumb = TRUE;
3666+ priv->window_button_press = FALSE;
3667+
3668+ priv->pointer.x = 0;
3669+ priv->pointer.y = 0;
3670+ priv->thumb_win.x = 0;
3671+ priv->thumb_win.y = 0;
3672+
3673+ priv->source_deactivate_bar_id = 0;
3674 priv->source_hide_thumb_id = 0;
3675+ priv->source_show_thumb_id = 0;
3676 priv->source_unlock_thumb_id = 0;
3677
3678- priv->pager = os_pager_new ();
3679+ priv->bar = os_bar_new ();
3680
3681 priv->window_group = gtk_window_group_new ();
3682
3683- priv->animation = os_animation_new (RATE_PAGING, MAX_DURATION_PAGING,
3684- paging_cb, NULL, scrollbar);
3685+ priv->animation = os_animation_new (RATE_ANIMATION, MAX_DURATION_SCROLLING,
3686+ scrolling_cb, scrolling_end_cb, scrollbar);
3687 priv->value = 0;
3688
3689 g_signal_connect (G_OBJECT (scrollbar), "notify::adjustment",
3690@@ -2673,10 +2840,10 @@
3691 scrollbar = OS_SCROLLBAR (object);
3692 priv = scrollbar->priv;
3693
3694- if (priv->source_deactivate_pager_id != 0)
3695+ if (priv->source_deactivate_bar_id != 0)
3696 {
3697- g_source_remove (priv->source_deactivate_pager_id);
3698- priv->source_deactivate_pager_id = 0;
3699+ g_source_remove (priv->source_deactivate_bar_id);
3700+ priv->source_deactivate_bar_id = 0;
3701 }
3702
3703 if (priv->source_hide_thumb_id != 0)
3704@@ -2711,10 +2878,10 @@
3705 priv->animation = NULL;
3706 }
3707
3708- if (priv->pager != NULL)
3709+ if (priv->bar != NULL)
3710 {
3711- g_object_unref (priv->pager);
3712- priv->pager = NULL;
3713+ g_object_unref (priv->bar);
3714+ priv->bar = NULL;
3715 }
3716
3717 if (priv->window_group != NULL)
3718@@ -2767,8 +2934,7 @@
3719 *minimal_width = *natural_width = 0;
3720 else
3721 {
3722- /* Smaller than 35 pixels the thumb looks weird. */
3723- *minimal_width = 35;
3724+ *minimal_width = MIN_THUMB_HEIGHT;
3725 *natural_width = THUMB_HEIGHT;
3726 }
3727 }
3728@@ -2788,8 +2954,7 @@
3729 *minimal_height = *natural_height = 0;
3730 else
3731 {
3732- /* Smaller than 35 pixels the thumb looks weird. */
3733- *minimal_height = 35;
3734+ *minimal_height = MIN_THUMB_HEIGHT;
3735 *natural_height = THUMB_HEIGHT;
3736 }
3737 }
3738@@ -2823,10 +2988,10 @@
3739 gdk_screen_get_active_window (gtk_widget_get_screen (widget)))
3740 {
3741 /* Stops potential running timeout. */
3742- if (priv->source_deactivate_pager_id != 0)
3743+ if (priv->source_deactivate_bar_id != 0)
3744 {
3745- g_source_remove (priv->source_deactivate_pager_id);
3746- priv->source_deactivate_pager_id = 0;
3747+ g_source_remove (priv->source_deactivate_bar_id);
3748+ priv->source_deactivate_bar_id = 0;
3749 }
3750
3751 priv->active_window = TRUE;
3752@@ -2846,29 +3011,24 @@
3753 * for example when switching notebook page,
3754 * check the position of the pointer
3755 * and set the state accordingly. */
3756- pager_set_state_from_pointer (scrollbar, x, y);
3757+ bar_set_state_from_pointer (scrollbar, x, y);
3758 }
3759 else
3760 {
3761 /* On map-event of an active window,
3762- * the pager should be active. */
3763- priv->can_deactivate_pager = FALSE;
3764- os_pager_set_active (priv->pager, TRUE, FALSE);
3765+ * the bar should be active. */
3766+ priv->deactivable_bar = FALSE;
3767+ os_bar_set_active (priv->bar, TRUE, FALSE);
3768 }
3769 }
3770
3771- if (priv->fullsize == FALSE)
3772- os_pager_show (priv->pager);
3773+ if (!(priv->state & OS_STATE_FULLSIZE))
3774+ os_bar_show (priv->bar);
3775
3776 if (!is_insensitive (scrollbar))
3777 {
3778- priv->proximity = TRUE;
3779-
3780- if (gtk_widget_get_realized (widget) && priv->filter == FALSE)
3781- {
3782- priv->filter = TRUE;
3783- gdk_window_add_filter (gtk_widget_get_window (widget), window_filter_func, scrollbar);
3784- }
3785+ priv->filter.proximity = TRUE;
3786+ add_window_filter (scrollbar);
3787 }
3788 }
3789
3790@@ -2889,20 +3049,17 @@
3791 gdk_window_get_events (gtk_widget_get_window (widget)) |
3792 GDK_POINTER_MOTION_MASK);
3793
3794- if (priv->filter == FALSE && priv->proximity == TRUE)
3795- {
3796- priv->filter = TRUE;
3797- gdk_window_add_filter (gtk_widget_get_window (widget), window_filter_func, scrollbar);
3798- }
3799+ if (priv->filter.proximity)
3800+ add_window_filter (scrollbar);
3801
3802 g_signal_connect (G_OBJECT (gtk_widget_get_toplevel (widget)), "configure-event",
3803 G_CALLBACK (toplevel_configure_event_cb), scrollbar);
3804
3805- calc_layout_pager (scrollbar, gtk_adjustment_get_value (priv->adjustment));
3806-
3807- os_pager_set_parent (priv->pager, widget);
3808-
3809- store_toplevel_position (scrollbar);
3810+ calc_layout_bar (scrollbar, gtk_adjustment_get_value (priv->adjustment));
3811+
3812+ os_bar_set_parent (priv->bar, widget);
3813+
3814+ calc_thumb_window_position (scrollbar);
3815 }
3816
3817 static void
3818@@ -2965,7 +3122,7 @@
3819 scrollbar = OS_SCROLLBAR (widget);
3820 priv = scrollbar->priv;
3821
3822- /* Get the side, then move thumb and pager accordingly. */
3823+ /* Get the side, then move thumb and bar accordingly. */
3824 retrieve_side (scrollbar);
3825
3826 priv->trough.x = allocation->x;
3827@@ -2973,7 +3130,7 @@
3828 priv->trough.width = allocation->width;
3829 priv->trough.height = allocation->height;
3830
3831- priv->pager_all = *allocation;
3832+ priv->bar_all = *allocation;
3833 priv->thumb_all = *allocation;
3834
3835 if (priv->orientation == GTK_ORIENTATION_VERTICAL)
3836@@ -2986,16 +3143,16 @@
3837 }
3838
3839 if (priv->side == OS_SIDE_RIGHT)
3840- priv->pager_all.x = allocation->x - PAGER_SIZE;
3841+ priv->bar_all.x = allocation->x - BAR_SIZE;
3842
3843- priv->pager_all.width = PAGER_SIZE;
3844+ priv->bar_all.width = BAR_SIZE;
3845
3846 priv->thumb_all.width = THUMB_WIDTH;
3847
3848 if (priv->side == OS_SIDE_RIGHT)
3849- priv->thumb_all.x = allocation->x - priv->pager_all.width;
3850+ priv->thumb_all.x = allocation->x - priv->bar_all.width;
3851 else
3852- priv->thumb_all.x = allocation->x + priv->pager_all.width - priv->thumb_all.width;
3853+ priv->thumb_all.x = allocation->x + priv->bar_all.width - priv->thumb_all.width;
3854
3855 allocation->width = 0;
3856 }
3857@@ -3009,32 +3166,32 @@
3858 }
3859
3860 if (priv->side == OS_SIDE_BOTTOM)
3861- priv->pager_all.y = allocation->y - PAGER_SIZE;
3862+ priv->bar_all.y = allocation->y - BAR_SIZE;
3863
3864- priv->pager_all.height = PAGER_SIZE;
3865+ priv->bar_all.height = BAR_SIZE;
3866
3867 priv->thumb_all.height = THUMB_WIDTH;
3868
3869 if (priv->side == OS_SIDE_BOTTOM)
3870- priv->thumb_all.y = allocation->y - priv->pager_all.height;
3871+ priv->thumb_all.y = allocation->y - priv->bar_all.height;
3872 else
3873- priv->thumb_all.y = allocation->y + priv->pager_all.height - priv->thumb_all.height;
3874+ priv->thumb_all.y = allocation->y + priv->bar_all.height - priv->thumb_all.height;
3875
3876 allocation->height = 0;
3877 }
3878
3879 if (priv->adjustment != NULL)
3880 {
3881- calc_layout_pager (scrollbar, gtk_adjustment_get_value (priv->adjustment));
3882+ calc_layout_bar (scrollbar, gtk_adjustment_get_value (priv->adjustment));
3883 calc_layout_slider (scrollbar, gtk_adjustment_get_value (priv->adjustment));
3884 }
3885
3886- os_pager_size_allocate (priv->pager, priv->pager_all);
3887+ os_bar_size_allocate (priv->bar, priv->bar_all);
3888
3889- move_pager (scrollbar);
3890+ move_bar (scrollbar);
3891
3892 if (gtk_widget_get_realized (widget))
3893- store_toplevel_position (scrollbar);
3894+ calc_thumb_window_position (scrollbar);
3895
3896 gtk_widget_set_allocation (widget, allocation);
3897 }
3898@@ -3047,15 +3204,10 @@
3899
3900 priv = scrollbar->priv;
3901
3902- priv->proximity = FALSE;
3903-
3904- if (gtk_widget_get_realized (GTK_WIDGET (scrollbar)) && priv->filter == TRUE)
3905- {
3906- priv->filter = FALSE;
3907- gdk_window_remove_filter (gtk_widget_get_window (GTK_WIDGET (scrollbar)), window_filter_func, scrollbar);
3908- }
3909-
3910- os_pager_set_active (priv->pager, FALSE, FALSE);
3911+ priv->filter.proximity = FALSE;
3912+ remove_window_filter (scrollbar);
3913+
3914+ os_bar_set_active (priv->bar, FALSE, FALSE);
3915
3916 gtk_widget_hide (priv->thumb);
3917 }
3918@@ -3068,16 +3220,11 @@
3919
3920 priv = scrollbar->priv;
3921
3922- priv->proximity = TRUE;
3923-
3924- if (gtk_widget_get_realized (GTK_WIDGET (scrollbar)) && priv->filter == FALSE)
3925- {
3926- priv->filter = TRUE;
3927- gdk_window_add_filter (gtk_widget_get_window (GTK_WIDGET (scrollbar)), window_filter_func, scrollbar);
3928- }
3929+ priv->filter.proximity = TRUE;
3930+ add_window_filter (scrollbar);
3931
3932 if (priv->active_window)
3933- os_pager_set_active (priv->pager, TRUE, FALSE);
3934+ os_bar_set_active (priv->bar, TRUE, FALSE);
3935 else
3936 {
3937 gint x, y;
3938@@ -3087,7 +3234,7 @@
3939 /* When the window is unfocused,
3940 * check the position of the pointer
3941 * and set the state accordingly. */
3942- pager_set_state_from_pointer (scrollbar, x, y);
3943+ bar_set_state_from_pointer (scrollbar, x, y);
3944 }
3945 }
3946
3947@@ -3150,17 +3297,12 @@
3948
3949 GTK_WIDGET_CLASS (g_type_class_peek (GTK_TYPE_WIDGET))->unmap (widget);
3950
3951- priv->proximity = FALSE;
3952-
3953- os_pager_hide (priv->pager);
3954+ os_bar_hide (priv->bar);
3955
3956 gtk_widget_hide (priv->thumb);
3957
3958- if (gtk_widget_get_realized (widget) && priv->filter == TRUE)
3959- {
3960- priv->filter = FALSE;
3961- gdk_window_remove_filter (gtk_widget_get_window (widget), window_filter_func, scrollbar);
3962- }
3963+ priv->filter.proximity = FALSE;
3964+ remove_window_filter (scrollbar);
3965 }
3966
3967 static void
3968@@ -3172,17 +3314,17 @@
3969 scrollbar = OS_SCROLLBAR (widget);
3970 priv = scrollbar->priv;
3971
3972- os_pager_hide (priv->pager);
3973+ os_bar_hide (priv->bar);
3974
3975 gtk_widget_hide (priv->thumb);
3976
3977- priv->filter = FALSE;
3978+ priv->filter.running = FALSE;
3979 gdk_window_remove_filter (gtk_widget_get_window (widget), window_filter_func, scrollbar);
3980
3981 g_signal_handlers_disconnect_by_func (G_OBJECT (gtk_widget_get_toplevel (widget)),
3982 G_CALLBACK (toplevel_configure_event_cb), scrollbar);
3983
3984- os_pager_set_parent (priv->pager, NULL);
3985+ os_bar_set_parent (priv->bar, NULL);
3986
3987 GTK_WIDGET_CLASS (g_type_class_peek (GTK_TYPE_WIDGET))->unrealize (widget);
3988 }
3989
3990=== modified file 'os/os-thumb.c'
3991--- os/os-thumb.c 2011-10-05 12:24:21 +0000
3992+++ os/os-thumb.c 2011-10-12 17:16:23 +0000
3993@@ -29,9 +29,6 @@
3994 #include <math.h>
3995 #include <stdlib.h>
3996
3997-/* Rate of the fade-out. */
3998-#define RATE_FADE_OUT 30
3999-
4000 /* Duration of the fade-out. */
4001 #define DURATION_FADE_OUT 2000
4002
4003@@ -57,14 +54,12 @@
4004 GtkOrientation orientation;
4005 GtkWidget *grabbed_widget;
4006 OsAnimation *animation;
4007- OsEvent event;
4008- gboolean can_rgba;
4009+ OsCoordinate pointer;
4010+ OsCoordinate pointer_root;
4011+ OsEventFlags event;
4012+ gboolean rgba;
4013 gboolean detached;
4014- gboolean use_tolerance;
4015- gint pointer_x;
4016- gint pointer_y;
4017- gint pointer_x_root;
4018- gint pointer_y_root;
4019+ gboolean tolerance;
4020 guint32 source_id;
4021 };
4022
4023@@ -192,12 +187,17 @@
4024
4025 priv->event = OS_EVENT_NONE;
4026
4027- priv->can_rgba = FALSE;
4028+ priv->pointer.x = 0;
4029+ priv->pointer.y = 0;
4030+ priv->pointer_root.x = 0;
4031+ priv->pointer_root.y = 0;
4032+
4033+ priv->rgba = FALSE;
4034 priv->detached = FALSE;
4035- priv->use_tolerance = FALSE;
4036+ priv->tolerance = FALSE;
4037
4038 priv->source_id = 0;
4039- priv->animation = os_animation_new (RATE_FADE_OUT, DURATION_FADE_OUT,
4040+ priv->animation = os_animation_new (RATE_ANIMATION, DURATION_FADE_OUT,
4041 fade_out_cb, NULL, thumb);
4042
4043 gtk_window_set_skip_pager_hint (GTK_WINDOW (thumb), TRUE);
4044@@ -237,19 +237,20 @@
4045
4046 if (event->type == GDK_BUTTON_PRESS)
4047 {
4048- if (event->button == 1)
4049+ if (event->button == 1 ||
4050+ event->button == 2)
4051 {
4052 gtk_grab_add (widget);
4053
4054- priv->pointer_x = event->x;
4055- priv->pointer_y = event->y;
4056- priv->pointer_x_root = event->x_root;
4057- priv->pointer_y_root = event->y_root;
4058+ priv->pointer.x = event->x;
4059+ priv->pointer.y = event->y;
4060+ priv->pointer_root.x = event->x_root;
4061+ priv->pointer_root.y = event->y_root;
4062
4063 priv->event |= OS_EVENT_BUTTON_PRESS;
4064 priv->event &= ~(OS_EVENT_MOTION_NOTIFY);
4065
4066- priv->use_tolerance = TRUE;
4067+ priv->tolerance = TRUE;
4068
4069 gtk_widget_queue_draw (widget);
4070 }
4071@@ -273,7 +274,8 @@
4072
4073 if (event->type == GDK_BUTTON_RELEASE)
4074 {
4075- if (event->button == 1)
4076+ if (event->button == 1 ||
4077+ event->button == 2)
4078 {
4079 gtk_grab_remove (widget);
4080
4081@@ -295,7 +297,7 @@
4082 thumb = OS_THUMB (widget);
4083 priv = thumb->priv;
4084
4085- priv->can_rgba = FALSE;
4086+ priv->rgba = FALSE;
4087
4088 if (gdk_screen_is_composited (gtk_widget_get_screen (widget)))
4089 {
4090@@ -313,7 +315,7 @@
4091 if (gdk_visual_get_depth (visual) == 32 && (red_mask == 0xff0000 &&
4092 green_mask == 0x00ff00 &&
4093 blue_mask == 0x0000ff))
4094- priv->can_rgba = TRUE;
4095+ priv->rgba = TRUE;
4096 }
4097
4098 gtk_widget_queue_draw (widget);
4099@@ -631,7 +633,7 @@
4100 thumb = OS_THUMB (widget);
4101 priv = thumb->priv;
4102
4103- radius = priv->can_rgba ? THUMB_RADIUS : 0;
4104+ radius = priv->rgba ? THUMB_RADIUS : 0;
4105
4106 #ifdef USE_GTK3
4107 width = gtk_widget_get_allocated_width (widget);
4108@@ -690,8 +692,8 @@
4109 if ((priv->event & OS_EVENT_BUTTON_PRESS) &&
4110 !(priv->event & OS_EVENT_MOTION_NOTIFY))
4111 {
4112- if ((priv->orientation == GTK_ORIENTATION_VERTICAL && (priv->pointer_y < height / 2)) ||
4113- (priv->orientation == GTK_ORIENTATION_HORIZONTAL && (priv->pointer_x < width / 2)))
4114+ if ((priv->orientation == GTK_ORIENTATION_VERTICAL && (priv->pointer.y < height / 2)) ||
4115+ (priv->orientation == GTK_ORIENTATION_HORIZONTAL && (priv->pointer.x < width / 2)))
4116 {
4117 pattern_add_gdk_rgba_stop (pat, 0.0, &bg_arrow_down, 0.6);
4118 pattern_add_gdk_rgba_stop (pat, 0.49, &bg_arrow_down, 0.1);
4119@@ -850,7 +852,7 @@
4120 os_animation_stop (priv->animation, NULL);
4121 }
4122
4123- priv->use_tolerance = FALSE;
4124+ priv->tolerance = FALSE;
4125
4126 return FALSE;
4127 }
4128@@ -906,11 +908,11 @@
4129 * see code few lines below. */
4130 if (!(priv->event & OS_EVENT_MOTION_NOTIFY))
4131 {
4132- if (!priv->use_tolerance ||
4133- (abs (priv->pointer_x - event->x) > TOLERANCE_FADE ||
4134- abs (priv->pointer_y - event->y) > TOLERANCE_FADE))
4135+ if (!priv->tolerance ||
4136+ (abs (priv->pointer.x - event->x) > TOLERANCE_FADE ||
4137+ abs (priv->pointer.y - event->y) > TOLERANCE_FADE))
4138 {
4139- priv->use_tolerance = FALSE;
4140+ priv->tolerance = FALSE;
4141 priv->source_id = g_timeout_add (TIMEOUT_FADE_OUT,
4142 timeout_fade_out_cb,
4143 thumb);
4144@@ -920,8 +922,8 @@
4145 if (priv->event & OS_EVENT_BUTTON_PRESS &&
4146 !(priv->event & OS_EVENT_MOTION_NOTIFY))
4147 {
4148- if (abs (priv->pointer_x_root - event->x_root) <= TOLERANCE_MOTION &&
4149- abs (priv->pointer_y_root - event->y_root) <= TOLERANCE_MOTION)
4150+ if (abs (priv->pointer_root.x - event->x_root) <= TOLERANCE_MOTION &&
4151+ abs (priv->pointer_root.y - event->y_root) <= TOLERANCE_MOTION)
4152 return FALSE;
4153
4154 priv->event |= OS_EVENT_MOTION_NOTIFY;
4155@@ -977,6 +979,13 @@
4156 /* If started, stop the fade-out. */
4157 os_animation_stop (priv->animation, fade_out_stop_cb);
4158
4159+ if (priv->event & OS_EVENT_MOTION_NOTIFY)
4160+ {
4161+ priv->event &= ~(OS_EVENT_MOTION_NOTIFY);
4162+
4163+ gtk_widget_queue_draw (widget);
4164+ }
4165+
4166 return FALSE;
4167 }
4168
4169@@ -991,7 +1000,7 @@
4170
4171 priv->event = OS_EVENT_NONE;
4172
4173- priv->use_tolerance = FALSE;
4174+ priv->tolerance = FALSE;
4175
4176 if (priv->grabbed_widget != NULL && gtk_widget_get_mapped (priv->grabbed_widget))
4177 gtk_grab_add (priv->grabbed_widget);

Subscribers

People subscribed via source and target branches