1 /*
2 * glade-dnd.c
3 *
4 * Copyright (C) 2013 Juan Pablo Ugarte
5 *
6 * Authors:
7 * Juan Pablo Ugarte <juanpablougarte@gmail.com>
8 *
9 * This library is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as
11 * published by the Free Software Foundation; either version 2.1 of
12 * the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 *
23 */
24
25 #include "glade.h"
26 #include "glade-dnd.h"
27
28 GtkTargetEntry *
_glade_dnd_get_target(void)29 _glade_dnd_get_target (void)
30 {
31 static GtkTargetEntry target = {GLADE_DND_TARGET_DATA, GTK_TARGET_SAME_APP, GLADE_DND_INFO_DATA};
32 return ⌖
33 }
34
35 void
_glade_dnd_dest_set(GtkWidget * target)36 _glade_dnd_dest_set (GtkWidget *target)
37 {
38 gtk_drag_dest_set (target, 0, _glade_dnd_get_target (), 1, GDK_ACTION_COPY);
39 }
40
41 GObject *
_glade_dnd_get_data(GdkDragContext * context,GtkSelectionData * selection,guint info)42 _glade_dnd_get_data (GdkDragContext *context,
43 GtkSelectionData *selection,
44 guint info)
45 {
46 GdkAtom target = gtk_selection_data_get_target (selection);
47
48 if (info == GLADE_DND_INFO_DATA &&
49 g_strcmp0 (gdk_atom_name (target), GLADE_DND_TARGET_DATA) == 0)
50 {
51 const guchar *data = gtk_selection_data_get_data (selection);
52 if (data)
53 return *((GObject **)data);
54 }
55 return NULL;
56 }
57
58
59 void
_glade_dnd_set_data(GtkSelectionData * selection,GObject * data)60 _glade_dnd_set_data (GtkSelectionData *selection, GObject *data)
61 {
62 static GdkAtom type = 0;
63
64 if (!type)
65 type = gdk_atom_intern_static_string (GLADE_DND_TARGET_DATA);
66
67 gtk_selection_data_set (selection, type, sizeof (gpointer),
68 (const guchar *)&data,
69 sizeof (gpointer));
70 }
71
72 static gboolean
on_drag_icon_draw(GtkWidget * widget,cairo_t * cr)73 on_drag_icon_draw (GtkWidget *widget, cairo_t *cr)
74 {
75 GtkStyleContext *context = gtk_widget_get_style_context (widget);
76 cairo_pattern_t *gradient;
77 GtkAllocation alloc;
78 gint x, y, w, h;
79 gdouble h2;
80 GdkRGBA bg;
81
82 /* Not needed acording to GtkWidget:draw documentation
83 * But seems like there is a bug when used as a drag_icon that makes the
84 * cairo translation used here persist when drawing children.
85 */
86 cairo_save (cr);
87
88 /* Clear BG */
89 cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
90 cairo_paint (cr);
91 cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
92
93 gtk_widget_get_allocation (widget, &alloc);
94 x = alloc.x;
95 y = alloc.y;
96 w = alloc.width;
97 h = alloc.height;
98 h2 = h/2.0;
99
100 gtk_style_context_get_background_color (context, gtk_style_context_get_state (context), &bg);
101
102 gradient = cairo_pattern_create_linear (x, y, x, y+h);
103 cairo_pattern_add_color_stop_rgba (gradient, 0, bg.red, bg.green, bg.blue, 0);
104 cairo_pattern_add_color_stop_rgba (gradient, .5, bg.red, bg.green, bg.blue, .8);
105 cairo_pattern_add_color_stop_rgba (gradient, 1, bg.red, bg.green, bg.blue, 0);
106
107 cairo_set_source (cr, gradient);
108 cairo_rectangle (cr, x+h2, y, w-h, h);
109 cairo_fill (cr);
110 cairo_pattern_destroy (gradient);
111
112 gradient = cairo_pattern_create_radial (x+h2, y+h2, 0, x+h2, y+h2, h2);
113 cairo_pattern_add_color_stop_rgba (gradient, 0, bg.red, bg.green, bg.blue, .8);
114 cairo_pattern_add_color_stop_rgba (gradient, 1, bg.red, bg.green, bg.blue, 0);
115
116 cairo_set_source (cr, gradient);
117 cairo_rectangle (cr, x, y, h2, h);
118 cairo_fill (cr);
119
120 cairo_translate (cr, w-h, 0);
121 cairo_set_source (cr, gradient);
122 cairo_rectangle (cr, x+h2, y, h2, h);
123 cairo_fill (cr);
124
125 cairo_pattern_destroy (gradient);
126 cairo_restore (cr);
127
128 return FALSE;
129 }
130
131 void
_glade_dnd_set_icon_widget(GdkDragContext * context,const gchar * icon_name,const gchar * description)132 _glade_dnd_set_icon_widget (GdkDragContext *context,
133 const gchar *icon_name,
134 const gchar *description)
135 {
136 GtkWidget *window, *box, *label, *icon;
137 GdkScreen *screen;
138 GdkVisual *visual;
139
140 screen = gdk_window_get_screen (gdk_drag_context_get_source_window (context));
141 window = gtk_window_new (GTK_WINDOW_POPUP);
142
143 gtk_window_set_type_hint (GTK_WINDOW (window), GDK_WINDOW_TYPE_HINT_DND);
144 gtk_window_set_screen (GTK_WINDOW (window), screen);
145
146 box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
147 gtk_container_set_border_width (GTK_CONTAINER (box), 12);
148
149 icon = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_BUTTON);
150 gtk_widget_set_opacity (icon, .8);
151
152 label = gtk_label_new (description);
153
154 gtk_box_pack_start (GTK_BOX (box), icon, FALSE, TRUE, 0);
155 gtk_box_pack_start (GTK_BOX (box), label, FALSE, TRUE, 0);
156
157 gtk_widget_show_all (box);
158 gtk_container_add (GTK_CONTAINER (window), box);
159
160 if ((visual = gdk_screen_get_rgba_visual (screen)))
161 {
162 gtk_widget_set_visual (window, visual);
163 gtk_widget_set_app_paintable (window, TRUE);
164 g_signal_connect (window, "draw", G_CALLBACK (on_drag_icon_draw), NULL);
165 }
166
167 g_object_ref_sink (window);
168 gtk_drag_set_icon_widget (context, window, 0, 0);
169 g_object_unref (window);
170 }
171