]> Pileus Git - ~andy/gtk/blob - gtk/gtktreednd.c
Boilerplate reduction
[~andy/gtk] / gtk / gtktreednd.c
1 /* gtktreednd.c
2  * Copyright (C) 2001  Red Hat, Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include <config.h>
21 #include <string.h>
22 #include "gtktreednd.h"
23 #include "gtkintl.h"
24 #include "gtkalias.h"
25
26 GType
27 gtk_tree_drag_source_get_type (void)
28 {
29   static GType our_type = 0;
30
31   if (!our_type)
32     {
33       static const GTypeInfo our_info =
34       {
35         sizeof (GtkTreeDragSourceIface), /* class_size */
36         NULL,           /* base_init */
37         NULL,           /* base_finalize */
38         NULL,
39         NULL,           /* class_finalize */
40         NULL,           /* class_data */
41         0,
42         0,              /* n_preallocs */
43         NULL
44       };
45
46       our_type = g_type_register_static (G_TYPE_INTERFACE, 
47                                          I_("GtkTreeDragSource"),
48                                          &our_info, 0);
49     }
50   
51   return our_type;
52 }
53
54
55 GType
56 gtk_tree_drag_dest_get_type (void)
57 {
58   static GType our_type = 0;
59
60   if (!our_type)
61     {
62       static const GTypeInfo our_info =
63       {
64         sizeof (GtkTreeDragDestIface), /* class_size */
65         NULL,           /* base_init */
66         NULL,           /* base_finalize */
67         NULL,
68         NULL,           /* class_finalize */
69         NULL,           /* class_data */
70         0,
71         0,              /* n_preallocs */
72         NULL
73       };
74
75       our_type = g_type_register_static (G_TYPE_INTERFACE, I_("GtkTreeDragDest"), &our_info, 0);
76     }
77   
78   return our_type;
79 }
80
81 /**
82  * gtk_tree_drag_source_row_draggable:
83  * @drag_source: a #GtkTreeDragSource
84  * @path: row on which user is initiating a drag
85  * 
86  * Asks the #GtkTreeDragSource whether a particular row can be used as
87  * the source of a DND operation. If the source doesn't implement
88  * this interface, the row is assumed draggable.
89  *
90  * Return value: %TRUE if the row can be dragged
91  **/
92 gboolean
93 gtk_tree_drag_source_row_draggable (GtkTreeDragSource *drag_source,
94                                     GtkTreePath       *path)
95 {
96   GtkTreeDragSourceIface *iface = GTK_TREE_DRAG_SOURCE_GET_IFACE (drag_source);
97
98   g_return_val_if_fail (path != NULL, FALSE);
99
100   if (iface->row_draggable)
101     return (* iface->row_draggable) (drag_source, path);
102   else
103     return TRUE;
104     /* Returning TRUE if row_draggable is not implemented is a fallback.
105        Interface implementations such as GtkTreeStore and GtkListStore really should
106        implement row_draggable. */
107 }
108
109
110 /**
111  * gtk_tree_drag_source_drag_data_delete:
112  * @drag_source: a #GtkTreeDragSource
113  * @path: row that was being dragged
114  * 
115  * Asks the #GtkTreeDragSource to delete the row at @path, because
116  * it was moved somewhere else via drag-and-drop. Returns %FALSE
117  * if the deletion fails because @path no longer exists, or for
118  * some model-specific reason. Should robustly handle a @path no
119  * longer found in the model!
120  * 
121  * Return value: %TRUE if the row was successfully deleted
122  **/
123 gboolean
124 gtk_tree_drag_source_drag_data_delete (GtkTreeDragSource *drag_source,
125                                        GtkTreePath       *path)
126 {
127   GtkTreeDragSourceIface *iface = GTK_TREE_DRAG_SOURCE_GET_IFACE (drag_source);
128
129   g_return_val_if_fail (iface->drag_data_delete != NULL, FALSE);
130   g_return_val_if_fail (path != NULL, FALSE);
131
132   return (* iface->drag_data_delete) (drag_source, path);
133 }
134
135 /**
136  * gtk_tree_drag_source_drag_data_get:
137  * @drag_source: a #GtkTreeDragSource
138  * @path: row that was dragged
139  * @selection_data: a #GtkSelectionData to fill with data from the dragged row
140  * 
141  * Asks the #GtkTreeDragSource to fill in @selection_data with a
142  * representation of the row at @path. @selection_data->target gives
143  * the required type of the data.  Should robustly handle a @path no
144  * longer found in the model!
145  * 
146  * Return value: %TRUE if data of the required type was provided 
147  **/
148 gboolean
149 gtk_tree_drag_source_drag_data_get    (GtkTreeDragSource *drag_source,
150                                        GtkTreePath       *path,
151                                        GtkSelectionData  *selection_data)
152 {
153   GtkTreeDragSourceIface *iface = GTK_TREE_DRAG_SOURCE_GET_IFACE (drag_source);
154
155   g_return_val_if_fail (iface->drag_data_get != NULL, FALSE);
156   g_return_val_if_fail (path != NULL, FALSE);
157   g_return_val_if_fail (selection_data != NULL, FALSE);
158
159   return (* iface->drag_data_get) (drag_source, path, selection_data);
160 }
161
162 /**
163  * gtk_tree_drag_dest_drag_data_received:
164  * @drag_dest: a #GtkTreeDragDest
165  * @dest: row to drop in front of
166  * @selection_data: data to drop
167  * 
168  * Asks the #GtkTreeDragDest to insert a row before the path @dest,
169  * deriving the contents of the row from @selection_data. If @dest is
170  * outside the tree so that inserting before it is impossible, %FALSE
171  * will be returned. Also, %FALSE may be returned if the new row is
172  * not created for some model-specific reason.  Should robustly handle
173  * a @dest no longer found in the model!
174  * 
175  * Return value: whether a new row was created before position @dest
176  **/
177 gboolean
178 gtk_tree_drag_dest_drag_data_received (GtkTreeDragDest  *drag_dest,
179                                        GtkTreePath      *dest,
180                                        GtkSelectionData *selection_data)
181 {
182   GtkTreeDragDestIface *iface = GTK_TREE_DRAG_DEST_GET_IFACE (drag_dest);
183
184   g_return_val_if_fail (iface->drag_data_received != NULL, FALSE);
185   g_return_val_if_fail (dest != NULL, FALSE);
186   g_return_val_if_fail (selection_data != NULL, FALSE);
187
188   return (* iface->drag_data_received) (drag_dest, dest, selection_data);
189 }
190
191
192 /**
193  * gtk_tree_drag_dest_row_drop_possible:
194  * @drag_dest: a #GtkTreeDragDest
195  * @dest_path: destination row
196  * @selection_data: the data being dragged
197  * 
198  * Determines whether a drop is possible before the given @dest_path,
199  * at the same depth as @dest_path. i.e., can we drop the data in
200  * @selection_data at that location. @dest_path does not have to
201  * exist; the return value will almost certainly be %FALSE if the
202  * parent of @dest_path doesn't exist, though.
203  * 
204  * Return value: %TRUE if a drop is possible before @dest_path
205  **/
206 gboolean
207 gtk_tree_drag_dest_row_drop_possible (GtkTreeDragDest   *drag_dest,
208                                       GtkTreePath       *dest_path,
209                                       GtkSelectionData  *selection_data)
210 {
211   GtkTreeDragDestIface *iface = GTK_TREE_DRAG_DEST_GET_IFACE (drag_dest);
212
213   g_return_val_if_fail (iface->row_drop_possible != NULL, FALSE);
214   g_return_val_if_fail (selection_data != NULL, FALSE);
215   g_return_val_if_fail (dest_path != NULL, FALSE);
216
217   return (* iface->row_drop_possible) (drag_dest, dest_path, selection_data);
218 }
219
220 typedef struct _TreeRowData TreeRowData;
221
222 struct _TreeRowData
223 {
224   GtkTreeModel *model;
225   gchar path[4];
226 };
227
228 /**
229  * gtk_tree_set_row_drag_data:
230  * @selection_data: some #GtkSelectionData
231  * @tree_model: a #GtkTreeModel
232  * @path: a row in @tree_model
233  * 
234  * Sets selection data of target type %GTK_TREE_MODEL_ROW. Normally used
235  * in a drag_data_get handler.
236  * 
237  * Return value: %TRUE if the #GtkSelectionData had the proper target type to allow us to set a tree row
238  **/
239 gboolean
240 gtk_tree_set_row_drag_data (GtkSelectionData *selection_data,
241                             GtkTreeModel     *tree_model,
242                             GtkTreePath      *path)
243 {
244   TreeRowData *trd;
245   gchar *path_str;
246   gint len;
247   gint struct_size;
248   
249   g_return_val_if_fail (selection_data != NULL, FALSE);
250   g_return_val_if_fail (GTK_IS_TREE_MODEL (tree_model), FALSE);
251   g_return_val_if_fail (path != NULL, FALSE);
252
253   if (selection_data->target != gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
254     return FALSE;
255   
256   path_str = gtk_tree_path_to_string (path);
257
258   len = strlen (path_str);
259
260   /* the old allocate-end-of-struct-to-hold-string trick */
261   struct_size = sizeof (TreeRowData) + len + 1 -
262     (sizeof (TreeRowData) - G_STRUCT_OFFSET (TreeRowData, path));
263
264   trd = g_malloc (struct_size); 
265
266   strcpy (trd->path, path_str);
267
268   g_free (path_str);
269   
270   trd->model = tree_model;
271   
272   gtk_selection_data_set (selection_data,
273                           gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"),
274                           8, /* bytes */
275                           (void*)trd,
276                           struct_size);
277
278   g_free (trd);
279   
280   return TRUE;
281 }
282
283 /**
284  * gtk_tree_get_row_drag_data:
285  * @selection_data: a #GtkSelectionData
286  * @tree_model: a #GtkTreeModel
287  * @path: row in @tree_model
288  * 
289  * Obtains a @tree_model and @path from selection data of target type
290  * %GTK_TREE_MODEL_ROW. Normally called from a drag_data_received handler.
291  * This function can only be used if @selection_data originates from the same
292  * process that's calling this function, because a pointer to the tree model
293  * is being passed around. If you aren't in the same process, then you'll
294  * get memory corruption. In the #GtkTreeDragDest drag_data_received handler,
295  * you can assume that selection data of type %GTK_TREE_MODEL_ROW is
296  * in from the current process. The returned path must be freed with
297  * gtk_tree_path_free().
298  * 
299  * Return value: %TRUE if @selection_data had target type %GTK_TREE_MODEL_ROW and
300  *  is otherwise valid
301  **/
302 gboolean
303 gtk_tree_get_row_drag_data (GtkSelectionData  *selection_data,
304                             GtkTreeModel     **tree_model,
305                             GtkTreePath      **path)
306 {
307   TreeRowData *trd;
308   
309   g_return_val_if_fail (selection_data != NULL, FALSE);  
310
311   if (tree_model)
312     *tree_model = NULL;
313
314   if (path)
315     *path = NULL;
316   
317   if (selection_data->target != gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
318     return FALSE;
319
320   if (selection_data->length < 0)
321     return FALSE;
322
323   trd = (void*) selection_data->data;
324
325   if (tree_model)
326     *tree_model = trd->model;
327
328   if (path)
329     *path = gtk_tree_path_new_from_string (trd->path);
330   
331   return TRUE;
332 }
333
334 #define __GTK_TREE_DND_C__
335 #include "gtkaliasdef.c"