--- /dev/null
+/* Derived from gtktreeview.c
+ * Copyright (C) 2000 Red Hat, Inc., Jonathan Blandford <jrb@redhat.com>
+ * Portions copyright (C) 2009 Richard Kettlewell
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/** @file disobedience/autoscroll.c
+ * @brief Automatic scrolling of a GtkTreeView
+ *
+ * GTK+ doesn't expose the automatic scrolling support if you don't use its
+ * high-level treeview drag+drop features.
+ *
+ * Adapted from GTK+ upstream as of commit
+ * 7fda8e6378d90bc8cf670ffe9dea682911e5e241.
+ */
+
+#include <config.h>
+
+#include <glib.h>
+#include <gtk/gtk.h>
+
+#include "autoscroll.h"
+
+/** @brief Object data key used to track the autoscroll timeout */
+#define AUTOSCROLL_KEY "autoscroll.greenend.org.uk"
+
+/** @brief Controls size of edge region that provokes scrolling
+ *
+ * Actually this is half the size of the scroll region. In isolation this may
+ * seem bizarre, but GTK+ uses the value internally for other purposes.
+ */
+#define SCROLL_EDGE_SIZE 15
+
+/** @brief Called from time to time to check whether auto-scrolling is needed
+ * @param data The GtkTreeView
+ * @return TRUE, to keep on truckin'
+ */
+static gboolean autoscroll_timeout(gpointer data) {
+ GtkTreeView *tree_view = data;
+ GdkRectangle visible_rect;
+ gint wx, wy, tx, ty;
+ gint offset;
+ gfloat value;
+
+ /* First we must find the pointer Y position in tree coordinates. GTK+
+ * natively knows what the bin window is and can get the pointer in bin
+ * coords and convert to tree coords. But there is no published way for us
+ * to find the bin window, so we must start in widget coords. */
+ gtk_widget_get_pointer(GTK_WIDGET(tree_view), &wx, &wy);
+ //fprintf(stderr, "widget coords: %d, %d\n", wx, wy);
+ gtk_tree_view_convert_widget_to_tree_coords(tree_view, wx, wy, &tx, &ty);
+ //fprintf(stderr, "tree coords: %d, %d\n", tx, ty);
+
+ gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
+
+ /* see if we are near the edge. */
+ offset = ty - (visible_rect.y + 2 * SCROLL_EDGE_SIZE);
+ if (offset > 0)
+ {
+ offset = ty - (visible_rect.y + visible_rect.height - 2 * SCROLL_EDGE_SIZE);
+ if (offset < 0)
+ return TRUE;
+ }
+
+ GtkAdjustment *vadjustment = gtk_tree_view_get_vadjustment(tree_view);
+
+ value = CLAMP (vadjustment->value + offset, 0.0,
+ vadjustment->upper - vadjustment->page_size);
+ gtk_adjustment_set_value (vadjustment, value);
+
+ return TRUE;
+}
+
+/** @brief Enable autoscrolling
+ * @param tree_view Tree view to enable autoscrolling
+ *
+ * It's harmless to call this if autoscrolling is already enabled.
+ *
+ * It's up to you to cancel the callback when no longer required (including
+ * object destruction).
+ */
+void autoscroll_add(GtkTreeView *tree_view) {
+ guint *scrolldata = g_object_get_data(G_OBJECT(tree_view), AUTOSCROLL_KEY);
+ if(!scrolldata) {
+ /* Set up the callback */
+ scrolldata = g_new(guint, 1);
+ *scrolldata = gdk_threads_add_timeout(150, autoscroll_timeout, tree_view);
+ g_object_set_data(G_OBJECT(tree_view), AUTOSCROLL_KEY, scrolldata);
+ //fprintf(stderr, "autoscroll enabled\n");
+ }
+}
+
+/** @brief Disable autoscrolling
+ * @param tree_view Tree view to enable autoscrolling
+ *
+ * It's harmless to call this if autoscrolling is not enabled.
+ */
+void autoscroll_remove(GtkTreeView *tree_view) {
+ guint *scrolldata = g_object_get_data(G_OBJECT(tree_view), AUTOSCROLL_KEY);
+ if(scrolldata) {
+ g_object_set_data(G_OBJECT(tree_view), AUTOSCROLL_KEY, NULL);
+ g_source_remove(*scrolldata);
+ g_free(scrolldata);
+ //fprintf(stderr, "autoscroll disabled\n");
+ }
+}
+
+/*
+Local Variables:
+c-basic-offset:2
+comment-column:40
+fill-column:79
+indent-tabs-mode:nil
+End:
+*/
--- /dev/null
+/* Derived from gtktreeview.c
+ * Copyright (C) 2000 Red Hat, Inc., Jonathan Blandford <jrb@redhat.com>
+ * Portions copyright (C) 2009 Richard Kettlewell
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/** @file disobedience/autoscroll.h
+ * @brief Automatic scrolling of a GtkTreeView
+ */
+#ifndef AUTOSCROLL_H
+#define AUTOSCROLL_H
+
+void autoscroll_add(GtkTreeView *tree_view);
+void autoscroll_remove(GtkTreeView *tree_view);
+
+#endif /* AUTOSCROLL_H */
+
+/*
+Local Variables:
+c-basic-offset:2
+comment-column:40
+fill-column:79
+indent-tabs-mode:nil
+End:
+*/
#include "popup.h"
#include "queue-generic.h"
#include "multidrag.h"
+#include "autoscroll.h"
static const GtkTargetEntry queuelike_targets[] = {
{
* @param time_ Current time
* @param user_data Pointer to queuelike
* @return TRUE in a dropzone, otherwise FALSE
+ *
+ * This is the handler for the "drag-motion" signal.
*/
static gboolean ql_drag_motion(GtkWidget *w,
GdkDragContext *dc,
* As the code stands the drop works but the visual feedback is not quite
* right.
*/
+ autoscroll_add(GTK_TREE_VIEW(w));
return TRUE; /* We are (always) in a drop zone */
}
* @param dc Drag context
* @param time_ Current time
* @param user_data Pointer to queuelike
+ *
+ * This is the handler for the "drag-leave" signal.
+ *
+ * It turns out that we get a drag-leave event when the data is dropped, too
+ * (See _gtk_drag_dest_handle_event). This seems logically consistent and is
+ * convenient too - for instance it's why autoscroll_remove() gets called at
+ * the end of a drag+drop sequence.
*/
static void ql_drag_leave(GtkWidget *w,
GdkDragContext attribute((unused)) *dc,
//struct queuelike *const ql = user_data;
gtk_tree_view_set_drag_dest_row(GTK_TREE_VIEW(w), NULL, 0);
+ autoscroll_remove(GTK_TREE_VIEW(w));
}
/** @brief Callback to add selected tracks to the selection data
* convenient.
*
* If there are no IDs for rows in this widget then the ID half is undefined.
+ *
+ * This is the handler for the "drag-data-get" signal.
*/
static void ql_drag_data_get(GtkWidget attribute((unused)) *w,
GdkDragContext attribute((unused)) *dc,
* @param info_ The target type that was chosen
* @param time_ Time data received (for some reason not a @c time_t)
* @param user_data The queuelike
+ *
+ * This is the handler for the "drag-data-received" signal.
*/
static void ql_drag_data_received(GtkWidget attribute((unused)) *w,
GdkDragContext attribute((unused)) *dc,