From 846b01c278ea82514b09b029fb7c6b3aa8345f90 Mon Sep 17 00:00:00 2001 Message-Id: <846b01c278ea82514b09b029fb7c6b3aa8345f90.1714182748.git.mdw@distorted.org.uk> From: Mark Wooding Date: Sun, 15 Nov 2009 12:28:34 +0000 Subject: [PATCH] Move drag-begin handling to multidrag.c Organization: Straylight/Edgeware From: Richard Kettlewell --- disobedience/multidrag.c | 101 +++++++++++++++++++++++++++++++++-- disobedience/queue-generic.c | 84 ----------------------------- 2 files changed, 96 insertions(+), 89 deletions(-) diff --git a/disobedience/multidrag.c b/disobedience/multidrag.c index cc33038..6014e07 100644 --- a/disobedience/multidrag.c +++ b/disobedience/multidrag.c @@ -22,20 +22,27 @@ * you dragged from (because it can't cope with dragging more than one row at a * time). * - * Disobedience needs more. To implement this it intercepts button-press-event - * and button-release event and for clicks that might be the start of drags, - * suppresses changes to the selection. A consequence of this is that it needs - * to intercept button-release-event too, to restore the effect of the click, - * if it turns out not to be drag after all. + * Disobedience needs more. + * + * Firstly it intercepts button-press-event and button-release event and for + * clicks that might be the start of drags, suppresses changes to the + * selection. A consequence of this is that it needs to intercept + * button-release-event too, to restore the effect of the click, if it turns + * out not to be drag after all. * * The location of the initial click is stored in object data called @c * multidrag-where. * + * Secondly it intercepts drag-begin and constructs an icon from the rows to be + * dragged. + * * Inspired by similar code in Quodlibet (another software * jukebox, albeit as far as I can see a single-user one). */ #include + +#include #include #include @@ -128,6 +135,88 @@ static gboolean multidrag_button_release_event(GtkWidget *w, return FALSE; /* propagate */ } +/** @brief State for multidrag_begin() and its callbacks */ +struct multidrag_begin_state { + GtkTreeView *view; + int rows; + int index; + GdkPixmap **pixmaps; +}; + +/** @brief Callback to construct a row pixmap */ +static void multidrag_make_row_pixmaps(GtkTreeModel attribute((unused)) *model, + GtkTreePath *path, + GtkTreeIter attribute((unused)) *iter, + gpointer data) { + struct multidrag_begin_state *qdbs = data; + + qdbs->pixmaps[qdbs->index++] + = gtk_tree_view_create_row_drag_icon(qdbs->view, path); +} + +/** @brief Called when a drag operation starts + * @param w Source widget (the tree view) + * @param dc Drag context + * @param user_data Not used + */ +static void multidrag_drag_begin(GtkWidget *w, + GdkDragContext attribute((unused)) *dc, + gpointer attribute((unused)) user_data) { + struct multidrag_begin_state qdbs[1]; + GdkPixmap *icon; + GtkTreeSelection *sel; + + //fprintf(stderr, "drag-begin\n"); + memset(qdbs, 0, sizeof *qdbs); + qdbs->view = GTK_TREE_VIEW(w); + sel = gtk_tree_view_get_selection(qdbs->view); + /* Find out how many rows there are */ + if(!(qdbs->rows = gtk_tree_selection_count_selected_rows(sel))) + return; /* doesn't make sense */ + /* Generate a pixmap for each row */ + qdbs->pixmaps = g_new(GdkPixmap *, qdbs->rows); + gtk_tree_selection_selected_foreach(sel, + multidrag_make_row_pixmaps, + qdbs); + /* Determine the size of the final icon */ + int height = 0, width = 0; + for(int n = 0; n < qdbs->rows; ++n) { + int pxw, pxh; + gdk_drawable_get_size(qdbs->pixmaps[n], &pxw, &pxh); + if(pxw > width) + width = pxw; + height += pxh; + } + if(!width || !height) + return; /* doesn't make sense */ + /* Construct the icon */ + icon = gdk_pixmap_new(qdbs->pixmaps[0], width, height, -1); + GdkGC *gc = gdk_gc_new(icon); + gdk_gc_set_colormap(gc, gtk_widget_get_colormap(w)); + int y = 0; + for(int n = 0; n < qdbs->rows; ++n) { + int pxw, pxh; + gdk_drawable_get_size(qdbs->pixmaps[n], &pxw, &pxh); + gdk_draw_drawable(icon, + gc, + qdbs->pixmaps[n], + 0, 0, /* source coords */ + 0, y, /* dest coords */ + pxw, pxh); /* size */ + y += pxh; + gdk_drawable_unref(qdbs->pixmaps[n]); + qdbs->pixmaps[n] = NULL; + } + g_free(qdbs->pixmaps); + qdbs->pixmaps = NULL; + // TODO scale down a bit, the resulting icons are currently a bit on the + // large side. + gtk_drag_source_set_icon(w, + gtk_widget_get_colormap(w), + icon, + NULL); +} + /** @brief Allow multi-row drag for @p w * @param w A GtkTreeView widget * @@ -138,6 +227,8 @@ void make_treeview_multidrag(GtkWidget *w) { G_CALLBACK(multidrag_button_press_event), NULL); g_signal_connect(w, "button-release-event", G_CALLBACK(multidrag_button_release_event), NULL); + g_signal_connect(w, "drag-begin", + G_CALLBACK(multidrag_drag_begin), NULL); } /* diff --git a/disobedience/queue-generic.c b/disobedience/queue-generic.c index 54b11c5..179998a 100644 --- a/disobedience/queue-generic.c +++ b/disobedience/queue-generic.c @@ -424,86 +424,6 @@ void ql_new_queue(struct queuelike *ql, --suppress_actions; } -/** @brief State for ql_drag_begin() and its callbacks */ -struct ql_drag_begin_state { - struct queuelike *ql; - int rows; - int index; - GdkPixmap **pixmaps; -}; - -/** @brief Callback to construct a row pixmap */ -static void ql_drag_make_row_pixmaps(GtkTreeModel attribute((unused)) *model, - GtkTreePath *path, - GtkTreeIter attribute((unused)) *iter, - gpointer data) { - struct ql_drag_begin_state *qdbs = data; - - qdbs->pixmaps[qdbs->index++] - = gtk_tree_view_create_row_drag_icon(GTK_TREE_VIEW(qdbs->ql->view), - path); -} - -/** @brief Called when a drag operation from this queuelike begins - * @param w Source widget (the tree view) - * @param dc Drag context - * @param user_data The queuelike - */ -static void ql_drag_begin(GtkWidget attribute((unused)) *w, - GdkDragContext attribute((unused)) *dc, - gpointer user_data) { - struct queuelike *const ql = user_data; - struct ql_drag_begin_state qdbs[1]; - GdkPixmap *icon; - - //fprintf(stderr, "drag-begin\n"); - memset(qdbs, 0, sizeof *qdbs); - qdbs->ql = ql; - /* Find out how many rows there are */ - if(!(qdbs->rows = gtk_tree_selection_count_selected_rows(ql->selection))) - return; /* doesn't make sense */ - /* Generate a pixmap for each row */ - qdbs->pixmaps = xcalloc(qdbs->rows, sizeof *qdbs->pixmaps); - gtk_tree_selection_selected_foreach(ql->selection, - ql_drag_make_row_pixmaps, - qdbs); - /* Determine the size of the final icon */ - int height = 0, width = 0; - for(int n = 0; n < qdbs->rows; ++n) { - int pxw, pxh; - gdk_drawable_get_size(qdbs->pixmaps[n], &pxw, &pxh); - if(pxw > width) - width = pxw; - height += pxh; - } - if(!width || !height) - return; /* doesn't make sense */ - /* Construct the icon */ - icon = gdk_pixmap_new(qdbs->pixmaps[0], width, height, -1); - GdkGC *gc = gdk_gc_new(icon); - gdk_gc_set_colormap(gc, gtk_widget_get_colormap(ql->view)); - int y = 0; - for(int n = 0; n < qdbs->rows; ++n) { - int pxw, pxh; - gdk_drawable_get_size(qdbs->pixmaps[n], &pxw, &pxh); - gdk_draw_drawable(icon, - gc, - qdbs->pixmaps[n], - 0, 0, /* source coords */ - 0, y, /* dest coords */ - pxw, pxh); /* size */ - y += pxh; - gdk_drawable_unref(qdbs->pixmaps[n]); - qdbs->pixmaps[n] = NULL; - } - // TODO scale down a bit, the resulting icons are currently a bit on the - // large side. - gtk_drag_source_set_icon(ql->view, - gtk_widget_get_colormap(ql->view), - icon, - NULL); -} - /** @brief Called when a drag moves within a candidate destination * @param w Destination widget * @param dc Drag context @@ -819,8 +739,6 @@ GtkWidget *init_queuelike(struct queuelike *ql) { queuelike_targets, sizeof queuelike_targets / sizeof *queuelike_targets, GDK_ACTION_MOVE|GDK_ACTION_COPY); - g_signal_connect(ql->view, "drag-begin", - G_CALLBACK(ql_drag_begin), ql); g_signal_connect(ql->view, "drag-motion", G_CALLBACK(ql_drag_motion), ql); g_signal_connect(ql->view, "drag-leave", @@ -837,8 +755,6 @@ GtkWidget *init_queuelike(struct queuelike *ql) { queuelike_targets, sizeof queuelike_targets / sizeof *queuelike_targets, GDK_ACTION_COPY); - g_signal_connect(ql->view, "drag-begin", - G_CALLBACK(ql_drag_begin), ql); g_signal_connect(ql->view, "drag-data-get", G_CALLBACK(ql_drag_data_get), ql); make_treeview_multidrag(ql->view); -- [mdw]