1 /* GDK - The GIMP Drawing Kit
2 * Copyright (C) 1995-1999 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser 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.
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 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser 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.
21 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
22 * file for a list of people on the GTK+ Team.
26 * GTK+ DirectFB backend
27 * Copyright (C) 2001-2002 convergence integrated media GmbH
28 * Copyright (C) 2002-2004 convergence GmbH
29 * Written by Denis Oliver Kropp <dok@convergence.de> and
30 * Sven Neumann <sven@convergence.de>
35 #include "gdkdirectfb.h"
36 #include "gdkprivate-directfb.h"
39 #include "gdkproperty.h"
42 typedef struct _GdkDragContextPrivate GdkDragContextPrivate;
47 GDK_DRAG_STATUS_MOTION_WAIT,
48 GDK_DRAG_STATUS_ACTION_WAIT,
52 /* Structure that holds information about a drag in progress.
53 * this is used on both source and destination sides.
55 struct _GdkDragContextPrivate
57 GdkAtom local_selection;
59 guint16 last_x; /* Coordinates from last event */
61 guint drag_status : 4; /* current status of drag */
66 static GList *contexts = NULL;
67 static GdkDragContext *current_dest_drag = NULL;
69 #define GDK_DRAG_CONTEXT_PRIVATE_DATA(ctx) ((GdkDragContextPrivate *) GDK_DRAG_CONTEXT (ctx)->windowing_data)
72 static gpointer parent_class = NULL;
76 gdk_drag_context_init (GdkDragContext *dragcontext)
78 dragcontext->windowing_data = g_new (GdkDragContextPrivate, 1);
80 contexts = g_list_prepend (contexts, dragcontext);
84 gdk_drag_context_finalize (GObject *object)
86 GdkDragContext *context = GDK_DRAG_CONTEXT (object);
87 GdkDragContextPrivate *private = GDK_DRAG_CONTEXT_PRIVATE_DATA (object);
89 g_list_free (context->targets);
91 if (context->source_window)
92 g_object_unref (context->source_window);
94 if (context->dest_window)
95 g_object_unref (context->dest_window);
101 context->windowing_data = NULL;
104 contexts = g_list_remove (contexts, context);
106 G_OBJECT_CLASS (parent_class)->finalize (object);
110 gdk_drag_context_class_init (GdkDragContextClass *klass)
112 GObjectClass *object_class = G_OBJECT_CLASS (klass);
114 parent_class = g_type_class_peek_parent (klass);
116 object_class->finalize = gdk_drag_context_finalize;
120 gdk_drag_context_get_type (void)
122 static GType object_type = 0;
126 static const GTypeInfo object_info =
128 sizeof (GdkDragContextClass),
129 (GBaseInitFunc) NULL,
130 (GBaseFinalizeFunc) NULL,
131 (GClassInitFunc) gdk_drag_context_class_init,
132 NULL, /* class_finalize */
133 NULL, /* class_data */
134 sizeof (GdkDragContext),
136 (GInstanceInitFunc) gdk_drag_context_init,
139 object_type = g_type_register_static (G_TYPE_OBJECT,
148 gdk_drag_context_new (void)
150 return (GdkDragContext *) g_object_new (gdk_drag_context_get_type (), NULL);
154 gdk_drag_context_ref (GdkDragContext *context)
156 g_object_ref (context);
160 gdk_drag_context_unref (GdkDragContext *context)
162 g_object_unref (context);
165 static GdkDragContext *
166 gdk_drag_context_find (gboolean is_source,
170 GdkDragContext *context;
171 GdkDragContextPrivate *private;
174 for (list = contexts; list; list = list->next)
176 context = (GdkDragContext *) list->data;
177 private = GDK_DRAG_CONTEXT_PRIVATE_DATA (context);
179 if ((!context->is_source == !is_source) &&
181 (context->source_window && (context->source_window == source))) &&
183 (context->dest_window && (context->dest_window == dest))))
191 /************************** Public API ***********************/
201 local_send_leave (GdkDragContext *context,
206 if ((current_dest_drag != NULL) &&
207 (current_dest_drag->protocol == GDK_DRAG_PROTO_LOCAL) &&
208 (current_dest_drag->source_window == context->source_window))
210 event.dnd.type = GDK_DRAG_LEAVE;
211 event.dnd.window = context->dest_window;
212 /* Pass ownership of context to the event */
213 event.dnd.context = current_dest_drag;
214 event.dnd.send_event = FALSE;
215 event.dnd.time = time;
217 current_dest_drag = NULL;
219 gdk_event_put (&event);
224 local_send_enter (GdkDragContext *context,
227 GdkDragContextPrivate *private;
228 GdkDragContext *new_context;
231 private = GDK_DRAG_CONTEXT_PRIVATE_DATA (context);
233 if (!private->local_selection)
234 private->local_selection = gdk_atom_intern ("LocalDndSelection", FALSE);
236 if (current_dest_drag != NULL)
238 gdk_drag_context_unref (current_dest_drag);
239 current_dest_drag = NULL;
242 new_context = gdk_drag_context_new ();
243 new_context->protocol = GDK_DRAG_PROTO_LOCAL;
244 new_context->is_source = FALSE;
246 new_context->source_window = context->source_window;
247 g_object_ref (new_context->source_window);
249 new_context->dest_window = context->dest_window;
250 g_object_ref (new_context->dest_window);
252 new_context->targets = g_list_copy (context->targets);
254 gdk_window_set_events (new_context->source_window,
255 gdk_window_get_events (new_context->source_window) |
256 GDK_PROPERTY_CHANGE_MASK);
257 new_context->actions = context->actions;
259 event.dnd.type = GDK_DRAG_ENTER;
260 event.dnd.window = context->dest_window;
261 event.dnd.send_event = FALSE;
262 event.dnd.context = new_context;
263 event.dnd.time = time;
265 current_dest_drag = new_context;
267 (GDK_DRAG_CONTEXT_PRIVATE_DATA (new_context))->local_selection =
268 private->local_selection;
270 gdk_event_put (&event);
274 local_send_motion (GdkDragContext *context,
277 GdkDragAction action,
282 if ((current_dest_drag != NULL) &&
283 (current_dest_drag->protocol == GDK_DRAG_PROTO_LOCAL) &&
284 (current_dest_drag->source_window == context->source_window))
286 event.dnd.type = GDK_DRAG_MOTION;
287 event.dnd.window = current_dest_drag->dest_window;
288 event.dnd.send_event = FALSE;
289 event.dnd.context = current_dest_drag;
290 event.dnd.time = time;
291 event.dnd.x_root = x_root;
292 event.dnd.y_root = y_root;
294 current_dest_drag->suggested_action = action;
295 current_dest_drag->actions = action;
297 (GDK_DRAG_CONTEXT_PRIVATE_DATA (current_dest_drag))->last_x = x_root;
298 (GDK_DRAG_CONTEXT_PRIVATE_DATA (current_dest_drag))->last_y = y_root;
300 GDK_DRAG_CONTEXT_PRIVATE_DATA (context)->drag_status = GDK_DRAG_STATUS_MOTION_WAIT;
302 gdk_event_put (&event);
307 local_send_drop (GdkDragContext *context,
312 if ((current_dest_drag != NULL) &&
313 (current_dest_drag->protocol == GDK_DRAG_PROTO_LOCAL) &&
314 (current_dest_drag->source_window == context->source_window))
316 GdkDragContextPrivate *private;
317 private = GDK_DRAG_CONTEXT_PRIVATE_DATA (current_dest_drag);
319 event.dnd.type = GDK_DROP_START;
320 event.dnd.window = current_dest_drag->dest_window;
321 event.dnd.send_event = FALSE;
322 event.dnd.context = current_dest_drag;
323 event.dnd.time = time;
324 event.dnd.x_root = private->last_x;
325 event.dnd.y_root = private->last_y;
327 gdk_event_put (&event);
332 gdk_drag_do_leave (GdkDragContext *context,
335 if (context->dest_window)
337 switch (context->protocol)
339 case GDK_DRAG_PROTO_LOCAL:
340 local_send_leave (context, time);
347 g_object_unref (context->dest_window);
348 context->dest_window = NULL;
353 gdk_drag_begin (GdkWindow *window,
357 GdkDragContext *new_context;
359 g_return_val_if_fail (window != NULL, NULL);
361 g_object_ref (window);
363 new_context = gdk_drag_context_new ();
364 new_context->is_source = TRUE;
365 new_context->source_window = window;
366 new_context->targets = NULL;
367 new_context->actions = 0;
369 for (list = targets; list; list = list->next)
370 new_context->targets = g_list_append (new_context->targets, list->data);
376 gdk_drag_get_protocol_for_display(GdkDisplay *display, guint32 xid,
377 GdkDragProtocol *protocol)
381 window = gdk_window_lookup ((GdkNativeWindow) xid);
384 GPOINTER_TO_INT (gdk_drawable_get_data (window, "gdk-dnd-registered")))
386 *protocol = GDK_DRAG_PROTO_LOCAL;
390 *protocol = GDK_DRAG_PROTO_NONE;
395 gdk_drag_find_window_for_screen (GdkDragContext *context,
396 GdkWindow *drag_window,
400 GdkWindow **dest_window,
401 GdkDragProtocol *protocol)
405 g_return_if_fail (context != NULL);
407 dest = gdk_window_get_pointer (NULL, &x_root, &y_root, NULL);
409 if (context->dest_window != dest)
413 /* Check if new destination accepts drags, and which protocol */
414 if ((recipient = gdk_drag_get_protocol (GDK_WINDOW_DFB_ID (dest),
417 *dest_window = gdk_window_lookup ((GdkNativeWindow) recipient);
419 g_object_ref (*dest_window);
426 *dest_window = context->dest_window;
428 g_object_ref (*dest_window);
430 *protocol = context->protocol;
436 gdk_drag_motion (GdkDragContext *context,
437 GdkWindow *dest_window,
438 GdkDragProtocol protocol,
441 GdkDragAction suggested_action,
442 GdkDragAction possible_actions,
445 GdkDragContextPrivate *private;
447 g_return_val_if_fail (context != NULL, FALSE);
449 private = GDK_DRAG_CONTEXT_PRIVATE_DATA (context);
451 if (context->dest_window != dest_window)
455 /* Send a leave to the last destination */
456 gdk_drag_do_leave (context, time);
457 private->drag_status = GDK_DRAG_STATUS_DRAG;
459 /* Check if new destination accepts drags, and which protocol */
462 context->dest_window = dest_window;
463 g_object_ref (context->dest_window);
464 context->protocol = protocol;
468 case GDK_DRAG_PROTO_LOCAL:
469 local_send_enter (context, time);
475 context->suggested_action = suggested_action;
479 context->dest_window = NULL;
483 /* Push a status event, to let the client know that
487 event.dnd.type = GDK_DRAG_STATUS;
488 event.dnd.window = context->source_window;
489 /* We use this to signal a synthetic status. Perhaps
490 * we should use an extra field...
492 event.dnd.send_event = TRUE;
493 event.dnd.context = context;
494 event.dnd.time = time;
496 gdk_event_put (&event);
500 context->suggested_action = suggested_action;
503 /* Send a drag-motion event */
505 private->last_x = x_root;
506 private->last_y = y_root;
508 if (context->dest_window)
510 if (private->drag_status == GDK_DRAG_STATUS_DRAG)
512 switch (context->protocol)
514 case GDK_DRAG_PROTO_LOCAL:
515 local_send_motion (context,
516 x_root, y_root, suggested_action, time);
519 case GDK_DRAG_PROTO_NONE:
520 g_warning ("GDK_DRAG_PROTO_NONE is not valid in gdk_drag_motion()");
534 gdk_drag_drop (GdkDragContext *context,
537 g_return_if_fail (context != NULL);
539 if (context->dest_window)
541 switch (context->protocol)
543 case GDK_DRAG_PROTO_LOCAL:
544 local_send_drop (context, time);
546 case GDK_DRAG_PROTO_NONE:
547 g_warning ("GDK_DRAG_PROTO_NONE is not valid in gdk_drag_drop()");
556 gdk_drag_abort (GdkDragContext *context,
559 g_return_if_fail (context != NULL);
561 gdk_drag_do_leave (context, time);
564 /* Destination side */
567 gdk_drag_status (GdkDragContext *context,
568 GdkDragAction action,
571 GdkDragContextPrivate *private;
572 GdkDragContext *src_context;
575 g_return_if_fail (context != NULL);
577 private = GDK_DRAG_CONTEXT_PRIVATE_DATA (context);
579 src_context = gdk_drag_context_find (TRUE,
580 context->source_window,
581 context->dest_window);
585 GdkDragContextPrivate *private;
587 private = GDK_DRAG_CONTEXT_PRIVATE_DATA (src_context);
589 if (private->drag_status == GDK_DRAG_STATUS_MOTION_WAIT)
590 private->drag_status = GDK_DRAG_STATUS_DRAG;
592 event.dnd.type = GDK_DRAG_STATUS;
593 event.dnd.window = src_context->source_window;
594 event.dnd.send_event = FALSE;
595 event.dnd.context = src_context;
596 event.dnd.time = time;
598 src_context->action = action;
600 gdk_event_put (&event);
605 gdk_drop_reply (GdkDragContext *context,
609 g_return_if_fail (context != NULL);
613 gdk_drop_finish (GdkDragContext *context,
617 GdkDragContextPrivate *private;
618 GdkDragContext *src_context;
621 g_return_if_fail (context != NULL);
623 private = GDK_DRAG_CONTEXT_PRIVATE_DATA (context);
625 src_context = gdk_drag_context_find (TRUE,
626 context->source_window,
627 context->dest_window);
630 gdk_drag_context_ref (src_context);
632 event.dnd.type = GDK_DROP_FINISHED;
633 event.dnd.window = src_context->source_window;
634 event.dnd.send_event = FALSE;
635 event.dnd.context = src_context;
637 gdk_event_put (&event);
642 gdk_drag_drop_succeeded (GdkDragContext *context)
644 g_warning("gdk_drag_drop_succeeded unimplemented \n");
649 gdk_window_register_dnd (GdkWindow *window)
651 g_return_if_fail (window != NULL);
653 if (GPOINTER_TO_INT (gdk_drawable_get_data (window, "gdk-dnd-registered")))
656 gdk_drawable_set_data (window, "gdk-dnd-registered",
657 GINT_TO_POINTER (TRUE), NULL);
660 /*************************************************************
661 * gdk_drag_get_selection:
662 * Returns the selection atom for the current source window
666 *************************************************************/
669 gdk_drag_get_selection (GdkDragContext *context)
671 g_return_val_if_fail (context != NULL, GDK_NONE);
673 if (context->protocol == GDK_DRAG_PROTO_LOCAL)
674 return (GDK_DRAG_CONTEXT_PRIVATE_DATA (context))->local_selection;
679 #define __GDK_DND_X11_C__
680 #include "gdkaliasdef.c"