Commit | Line | Data |
---|---|---|
df73cc67 RK |
1 | /* Derived from gtktreeview.c |
2 | * Copyright (C) 2000 Red Hat, Inc., Jonathan Blandford <jrb@redhat.com> | |
3 | * Portions copyright (C) 2009 Richard Kettlewell | |
4 | * | |
5 | * This library is free software; you can redistribute it and/or | |
6 | * modify it under the terms of the GNU Library General Public | |
7 | * License as published by the Free Software Foundation; either | |
8 | * version 2 of the License, or (at your option) any later version. | |
9 | * | |
10 | * This library is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | * Library General Public License for more details. | |
14 | * | |
15 | * You should have received a copy of the GNU Library General Public | |
16 | * License along with this library; if not, write to the | |
17 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
18 | * Boston, MA 02111-1307, USA. | |
19 | */ | |
20 | /** @file disobedience/autoscroll.c | |
21 | * @brief Automatic scrolling of a GtkTreeView | |
22 | * | |
23 | * GTK+ doesn't expose the automatic scrolling support if you don't use its | |
24 | * high-level treeview drag+drop features. | |
25 | * | |
26 | * Adapted from GTK+ upstream as of commit | |
27 | * 7fda8e6378d90bc8cf670ffe9dea682911e5e241. | |
28 | */ | |
29 | ||
30 | #include <config.h> | |
31 | ||
32 | #include <glib.h> | |
33 | #include <gtk/gtk.h> | |
34 | ||
35 | #include "autoscroll.h" | |
36 | ||
37 | /** @brief Object data key used to track the autoscroll timeout */ | |
38 | #define AUTOSCROLL_KEY "autoscroll.greenend.org.uk" | |
39 | ||
40 | /** @brief Controls size of edge region that provokes scrolling | |
41 | * | |
42 | * Actually this is half the size of the scroll region. In isolation this may | |
43 | * seem bizarre, but GTK+ uses the value internally for other purposes. | |
44 | */ | |
45 | #define SCROLL_EDGE_SIZE 15 | |
46 | ||
47 | /** @brief Called from time to time to check whether auto-scrolling is needed | |
48 | * @param data The GtkTreeView | |
49 | * @return TRUE, to keep on truckin' | |
50 | */ | |
51 | static gboolean autoscroll_timeout(gpointer data) { | |
52 | GtkTreeView *tree_view = data; | |
53 | GdkRectangle visible_rect; | |
54 | gint wx, wy, tx, ty; | |
55 | gint offset; | |
56 | gfloat value; | |
57 | ||
58 | /* First we must find the pointer Y position in tree coordinates. GTK+ | |
59 | * natively knows what the bin window is and can get the pointer in bin | |
60 | * coords and convert to tree coords. But there is no published way for us | |
61 | * to find the bin window, so we must start in widget coords. */ | |
62 | gtk_widget_get_pointer(GTK_WIDGET(tree_view), &wx, &wy); | |
63 | //fprintf(stderr, "widget coords: %d, %d\n", wx, wy); | |
64 | gtk_tree_view_convert_widget_to_tree_coords(tree_view, wx, wy, &tx, &ty); | |
65 | //fprintf(stderr, "tree coords: %d, %d\n", tx, ty); | |
66 | ||
67 | gtk_tree_view_get_visible_rect (tree_view, &visible_rect); | |
68 | ||
69 | /* see if we are near the edge. */ | |
70 | offset = ty - (visible_rect.y + 2 * SCROLL_EDGE_SIZE); | |
e07418c4 RK |
71 | if (offset > 0) { |
72 | offset = ty - (visible_rect.y + visible_rect.height - 2 * SCROLL_EDGE_SIZE); | |
73 | if (offset < 0) | |
74 | return TRUE; | |
75 | } | |
df73cc67 RK |
76 | |
77 | GtkAdjustment *vadjustment = gtk_tree_view_get_vadjustment(tree_view); | |
78 | ||
79 | value = CLAMP (vadjustment->value + offset, 0.0, | |
80 | vadjustment->upper - vadjustment->page_size); | |
81 | gtk_adjustment_set_value (vadjustment, value); | |
82 | ||
83 | return TRUE; | |
84 | } | |
85 | ||
86 | /** @brief Enable autoscrolling | |
87 | * @param tree_view Tree view to enable autoscrolling | |
88 | * | |
89 | * It's harmless to call this if autoscrolling is already enabled. | |
90 | * | |
91 | * It's up to you to cancel the callback when no longer required (including | |
92 | * object destruction). | |
93 | */ | |
94 | void autoscroll_add(GtkTreeView *tree_view) { | |
95 | guint *scrolldata = g_object_get_data(G_OBJECT(tree_view), AUTOSCROLL_KEY); | |
96 | if(!scrolldata) { | |
97 | /* Set up the callback */ | |
98 | scrolldata = g_new(guint, 1); | |
99 | *scrolldata = gdk_threads_add_timeout(150, autoscroll_timeout, tree_view); | |
100 | g_object_set_data(G_OBJECT(tree_view), AUTOSCROLL_KEY, scrolldata); | |
101 | //fprintf(stderr, "autoscroll enabled\n"); | |
102 | } | |
103 | } | |
104 | ||
105 | /** @brief Disable autoscrolling | |
106 | * @param tree_view Tree view to enable autoscrolling | |
107 | * | |
108 | * It's harmless to call this if autoscrolling is not enabled. | |
109 | */ | |
110 | void autoscroll_remove(GtkTreeView *tree_view) { | |
111 | guint *scrolldata = g_object_get_data(G_OBJECT(tree_view), AUTOSCROLL_KEY); | |
112 | if(scrolldata) { | |
113 | g_object_set_data(G_OBJECT(tree_view), AUTOSCROLL_KEY, NULL); | |
114 | g_source_remove(*scrolldata); | |
115 | g_free(scrolldata); | |
116 | //fprintf(stderr, "autoscroll disabled\n"); | |
117 | } | |
118 | } | |
119 | ||
120 | /* | |
121 | Local Variables: | |
122 | c-basic-offset:2 | |
123 | comment-column:40 | |
124 | fill-column:79 | |
125 | indent-tabs-mode:nil | |
126 | End: | |
127 | */ |