]> Pileus Git - ~andy/gtk/blob - gdk/directfb/gdkdnd-directfb.c
Include "config.h" instead of <config.h> Command used: find -name
[~andy/gtk] / gdk / directfb / gdkdnd-directfb.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1999 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
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.
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  * Lesser General Public License for more details.
13  *
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.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.
23  */
24
25 /*
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>
31  */
32
33 #include "config.h"
34 #include "gdk.h"
35 #include "gdkdirectfb.h"
36 #include "gdkprivate-directfb.h"
37
38 #include "gdkdnd.h"
39 #include "gdkproperty.h"
40 #include "gdkalias.h"
41
42 typedef struct _GdkDragContextPrivate GdkDragContextPrivate;
43
44 typedef enum
45 {
46   GDK_DRAG_STATUS_DRAG,
47   GDK_DRAG_STATUS_MOTION_WAIT,
48   GDK_DRAG_STATUS_ACTION_WAIT,
49   GDK_DRAG_STATUS_DROP
50 } GtkDragStatus;
51
52 /* Structure that holds information about a drag in progress.
53  * this is used on both source and destination sides.
54  */
55 struct _GdkDragContextPrivate
56 {
57   GdkAtom local_selection;
58
59   guint16 last_x;               /* Coordinates from last event */
60   guint16 last_y;
61   guint   drag_status : 4;      /* current status of drag      */
62 };
63
64 /* Drag Contexts */
65
66 static GList          *contexts          = NULL;
67 static GdkDragContext *current_dest_drag = NULL;
68
69 #define GDK_DRAG_CONTEXT_PRIVATE_DATA(ctx) ((GdkDragContextPrivate *) GDK_DRAG_CONTEXT (ctx)->windowing_data)
70
71
72 static gpointer  parent_class = NULL;
73
74
75 static void
76 gdk_drag_context_init (GdkDragContext *dragcontext)
77 {
78   dragcontext->windowing_data = g_new (GdkDragContextPrivate, 1);
79
80   contexts = g_list_prepend (contexts, dragcontext);
81 }
82
83 static void
84 gdk_drag_context_finalize (GObject *object)
85 {
86   GdkDragContext        *context = GDK_DRAG_CONTEXT (object);
87   GdkDragContextPrivate *private = GDK_DRAG_CONTEXT_PRIVATE_DATA (object);
88
89   g_list_free (context->targets);
90
91   if (context->source_window)
92     g_object_unref (context->source_window);
93
94   if (context->dest_window)
95     g_object_unref (context->dest_window);
96
97
98   if (private)
99     {
100       g_free (private);
101       context->windowing_data = NULL;
102     }
103
104   contexts = g_list_remove (contexts, context);
105
106   G_OBJECT_CLASS (parent_class)->finalize (object);
107 }
108
109 static void
110 gdk_drag_context_class_init (GdkDragContextClass *klass)
111 {
112   GObjectClass *object_class = G_OBJECT_CLASS (klass);
113
114   parent_class = g_type_class_peek_parent (klass);
115
116   object_class->finalize = gdk_drag_context_finalize;
117 }
118
119 GType
120 gdk_drag_context_get_type (void)
121 {
122   static GType object_type = 0;
123
124   if (!object_type)
125     {
126       static const GTypeInfo object_info =
127       {
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),
135         0,              /* n_preallocs */
136         (GInstanceInitFunc) gdk_drag_context_init,
137       };
138
139       object_type = g_type_register_static (G_TYPE_OBJECT,
140                                             "GdkDragContext",
141                                             &object_info, 0);
142     }
143
144   return object_type;
145 }
146
147 GdkDragContext *
148 gdk_drag_context_new (void)
149 {
150   return (GdkDragContext *) g_object_new (gdk_drag_context_get_type (), NULL);
151 }
152
153 void
154 gdk_drag_context_ref (GdkDragContext *context)
155 {
156   g_object_ref (context);
157 }
158
159 void
160 gdk_drag_context_unref (GdkDragContext *context)
161 {
162   g_object_unref (context);
163 }
164
165 static GdkDragContext *
166 gdk_drag_context_find (gboolean     is_source,
167                        GdkWindow   *source,
168                        GdkWindow   *dest)
169 {
170   GdkDragContext        *context;
171   GdkDragContextPrivate *private;
172   GList                 *list;
173
174   for (list = contexts; list; list = list->next)
175     {
176       context = (GdkDragContext *) list->data;
177       private = GDK_DRAG_CONTEXT_PRIVATE_DATA (context);
178
179       if ((!context->is_source == !is_source) &&
180           ((source == NULL) ||
181            (context->source_window && (context->source_window == source))) &&
182           ((dest == NULL) ||
183            (context->dest_window && (context->dest_window == dest))))
184           return context;
185     }
186
187   return NULL;
188 }
189
190
191 /************************** Public API ***********************/
192
193 void
194 _gdk_dnd_init (void)
195 {
196 }
197
198 /* Source side */
199
200 static void
201 local_send_leave (GdkDragContext  *context,
202                   guint32          time)
203 {
204   GdkEvent event;
205
206   if ((current_dest_drag != NULL) &&
207       (current_dest_drag->protocol == GDK_DRAG_PROTO_LOCAL) &&
208       (current_dest_drag->source_window == context->source_window))
209     {
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;
216
217       current_dest_drag = NULL;
218
219       gdk_event_put (&event);
220     }
221 }
222
223 static void
224 local_send_enter (GdkDragContext *context,
225                   guint32         time)
226 {
227   GdkDragContextPrivate *private;
228   GdkDragContext        *new_context;
229   GdkEvent event;
230
231   private = GDK_DRAG_CONTEXT_PRIVATE_DATA (context);
232
233   if (!private->local_selection)
234     private->local_selection = gdk_atom_intern ("LocalDndSelection", FALSE);
235
236   if (current_dest_drag != NULL)
237     {
238       gdk_drag_context_unref (current_dest_drag);
239       current_dest_drag = NULL;
240     }
241
242   new_context = gdk_drag_context_new ();
243   new_context->protocol  = GDK_DRAG_PROTO_LOCAL;
244   new_context->is_source = FALSE;
245
246   new_context->source_window = context->source_window;
247   g_object_ref (new_context->source_window);
248
249   new_context->dest_window   = context->dest_window;
250   g_object_ref (new_context->dest_window);
251
252   new_context->targets = g_list_copy (context->targets);
253
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;
258
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;
264
265   current_dest_drag = new_context;
266
267   (GDK_DRAG_CONTEXT_PRIVATE_DATA (new_context))->local_selection =
268     private->local_selection;
269
270   gdk_event_put (&event);
271 }
272
273 static void
274 local_send_motion (GdkDragContext  *context,
275                     gint            x_root,
276                     gint            y_root,
277                     GdkDragAction   action,
278                     guint32         time)
279 {
280   GdkEvent event;
281
282   if ((current_dest_drag != NULL) &&
283       (current_dest_drag->protocol == GDK_DRAG_PROTO_LOCAL) &&
284       (current_dest_drag->source_window == context->source_window))
285     {
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;
293
294       current_dest_drag->suggested_action = action;
295       current_dest_drag->actions          = action;
296
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;
299
300       GDK_DRAG_CONTEXT_PRIVATE_DATA (context)->drag_status = GDK_DRAG_STATUS_MOTION_WAIT;
301
302       gdk_event_put (&event);
303     }
304 }
305
306 static void
307 local_send_drop (GdkDragContext *context,
308                  guint32         time)
309 {
310   GdkEvent event;
311
312   if ((current_dest_drag != NULL) &&
313       (current_dest_drag->protocol == GDK_DRAG_PROTO_LOCAL) &&
314       (current_dest_drag->source_window == context->source_window))
315     {
316       GdkDragContextPrivate *private;
317       private = GDK_DRAG_CONTEXT_PRIVATE_DATA (current_dest_drag);
318
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;
326
327       gdk_event_put (&event);
328     }
329 }
330
331 static void
332 gdk_drag_do_leave (GdkDragContext *context,
333                    guint32         time)
334 {
335   if (context->dest_window)
336     {
337       switch (context->protocol)
338         {
339         case GDK_DRAG_PROTO_LOCAL:
340           local_send_leave (context, time);
341           break;
342
343         default:
344           break;
345         }
346
347       g_object_unref (context->dest_window);
348       context->dest_window = NULL;
349     }
350 }
351
352 GdkDragContext *
353 gdk_drag_begin (GdkWindow *window,
354                 GList     *targets)
355 {
356   GList          *list;
357   GdkDragContext *new_context;
358
359   g_return_val_if_fail (window != NULL, NULL);
360
361   g_object_ref (window);
362
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;
368
369   for (list = targets; list; list = list->next)
370     new_context->targets = g_list_append (new_context->targets, list->data);
371
372   return new_context;
373 }
374
375 guint32
376 gdk_drag_get_protocol_for_display(GdkDisplay *display, guint32          xid,
377                                    GdkDragProtocol *protocol)
378 {
379   GdkWindow *window;
380
381   window = gdk_window_lookup ((GdkNativeWindow) xid);
382
383   if (window &&
384       GPOINTER_TO_INT (gdk_drawable_get_data (window, "gdk-dnd-registered")))
385     {
386       *protocol = GDK_DRAG_PROTO_LOCAL;
387       return xid;
388     }
389
390   *protocol = GDK_DRAG_PROTO_NONE;
391   return 0;
392 }
393
394 void
395 gdk_drag_find_window_for_screen (GdkDragContext   *context,
396                                  GdkWindow        *drag_window,
397                                  GdkScreen        *screen,
398                                  gint              x_root,
399                                  gint              y_root,
400                                  GdkWindow       **dest_window,
401                                  GdkDragProtocol  *protocol)
402 {
403   GdkWindow *dest;
404
405   g_return_if_fail (context != NULL);
406
407   dest = gdk_window_get_pointer (NULL, &x_root, &y_root, NULL);
408
409   if (context->dest_window != dest)
410     {
411       guint32 recipient;
412
413       /* Check if new destination accepts drags, and which protocol */
414       if ((recipient = gdk_drag_get_protocol (GDK_WINDOW_DFB_ID (dest),
415                                               protocol)))
416         {
417           *dest_window = gdk_window_lookup ((GdkNativeWindow) recipient);
418           if (dest_window)
419             g_object_ref (*dest_window);
420         }
421       else
422         *dest_window = NULL;
423     }
424   else
425     {
426       *dest_window = context->dest_window;
427       if (*dest_window)
428         g_object_ref (*dest_window);
429
430       *protocol = context->protocol;
431     }
432
433 }
434
435 gboolean
436 gdk_drag_motion (GdkDragContext  *context,
437                  GdkWindow       *dest_window,
438                  GdkDragProtocol  protocol,
439                  gint             x_root,
440                  gint             y_root,
441                  GdkDragAction    suggested_action,
442                  GdkDragAction    possible_actions,
443                  guint32          time)
444 {
445   GdkDragContextPrivate *private;
446
447   g_return_val_if_fail (context != NULL, FALSE);
448
449   private = GDK_DRAG_CONTEXT_PRIVATE_DATA (context);
450
451   if (context->dest_window != dest_window)
452     {
453       GdkEvent  event;
454
455       /* Send a leave to the last destination */
456       gdk_drag_do_leave (context, time);
457       private->drag_status = GDK_DRAG_STATUS_DRAG;
458
459       /* Check if new destination accepts drags, and which protocol */
460       if (dest_window)
461         {
462           context->dest_window = dest_window;
463           g_object_ref (context->dest_window);
464           context->protocol = protocol;
465
466           switch (protocol)
467             {
468             case GDK_DRAG_PROTO_LOCAL:
469               local_send_enter (context, time);
470               break;
471
472             default:
473               break;
474             }
475           context->suggested_action = suggested_action;
476         }
477       else
478         {
479           context->dest_window = NULL;
480           context->action = 0;
481         }
482
483       /* Push a status event, to let the client know that
484        * the drag changed
485        */
486
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...
491        */
492       event.dnd.send_event = TRUE;
493       event.dnd.context    = context;
494       event.dnd.time       = time;
495
496       gdk_event_put (&event);
497     }
498   else
499     {
500       context->suggested_action = suggested_action;
501     }
502
503   /* Send a drag-motion event */
504
505   private->last_x = x_root;
506   private->last_y = y_root;
507
508   if (context->dest_window)
509     {
510       if (private->drag_status == GDK_DRAG_STATUS_DRAG)
511         {
512           switch (context->protocol)
513             {
514             case GDK_DRAG_PROTO_LOCAL:
515               local_send_motion (context,
516                                  x_root, y_root, suggested_action, time);
517               break;
518
519             case GDK_DRAG_PROTO_NONE:
520               g_warning ("GDK_DRAG_PROTO_NONE is not valid in gdk_drag_motion()");
521               break;
522             default:
523               break;
524             }
525         }
526       else
527         return TRUE;
528     }
529
530   return FALSE;
531 }
532
533 void
534 gdk_drag_drop (GdkDragContext *context,
535                guint32         time)
536 {
537   g_return_if_fail (context != NULL);
538
539   if (context->dest_window)
540     {
541       switch (context->protocol)
542         {
543         case GDK_DRAG_PROTO_LOCAL:
544           local_send_drop (context, time);
545           break;
546         case GDK_DRAG_PROTO_NONE:
547           g_warning ("GDK_DRAG_PROTO_NONE is not valid in gdk_drag_drop()");
548           break;
549         default:
550           break;
551         }
552     }
553 }
554
555 void
556 gdk_drag_abort (GdkDragContext *context,
557                 guint32         time)
558 {
559   g_return_if_fail (context != NULL);
560
561   gdk_drag_do_leave (context, time);
562 }
563
564 /* Destination side */
565
566 void
567 gdk_drag_status (GdkDragContext   *context,
568                  GdkDragAction     action,
569                  guint32           time)
570 {
571   GdkDragContextPrivate *private;
572   GdkDragContext        *src_context;
573   GdkEvent event;
574
575   g_return_if_fail (context != NULL);
576
577   private = GDK_DRAG_CONTEXT_PRIVATE_DATA (context);
578
579   src_context = gdk_drag_context_find (TRUE,
580                                        context->source_window,
581                                        context->dest_window);
582
583   if (src_context)
584     {
585       GdkDragContextPrivate *private;
586
587       private = GDK_DRAG_CONTEXT_PRIVATE_DATA (src_context);
588
589       if (private->drag_status == GDK_DRAG_STATUS_MOTION_WAIT)
590         private->drag_status = GDK_DRAG_STATUS_DRAG;
591
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;
597
598       src_context->action = action;
599
600       gdk_event_put (&event);
601     }
602 }
603
604 void
605 gdk_drop_reply (GdkDragContext   *context,
606                 gboolean          ok,
607                 guint32           time)
608 {
609   g_return_if_fail (context != NULL);
610 }
611
612 void
613 gdk_drop_finish (GdkDragContext   *context,
614                  gboolean          success,
615                  guint32           time)
616 {
617   GdkDragContextPrivate *private;
618   GdkDragContext        *src_context;
619   GdkEvent event;
620
621   g_return_if_fail (context != NULL);
622
623   private = GDK_DRAG_CONTEXT_PRIVATE_DATA (context);
624
625   src_context = gdk_drag_context_find (TRUE,
626                                        context->source_window,
627                                        context->dest_window);
628   if (src_context)
629     {
630       gdk_drag_context_ref (src_context);
631
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;
636
637       gdk_event_put (&event);
638     }
639 }
640
641 gboolean
642 gdk_drag_drop_succeeded (GdkDragContext *context)
643 {
644         g_warning("gdk_drag_drop_succeeded unimplemented \n");
645         return TRUE;
646 }
647
648 void
649 gdk_window_register_dnd (GdkWindow      *window)
650 {
651   g_return_if_fail (window != NULL);
652
653   if (GPOINTER_TO_INT (gdk_drawable_get_data (window, "gdk-dnd-registered")))
654     return;
655
656   gdk_drawable_set_data (window, "gdk-dnd-registered",
657                          GINT_TO_POINTER (TRUE), NULL);
658 }
659
660 /*************************************************************
661  * gdk_drag_get_selection:
662  *     Returns the selection atom for the current source window
663  *   arguments:
664  *
665  *   results:
666  *************************************************************/
667
668 GdkAtom
669 gdk_drag_get_selection (GdkDragContext *context)
670 {
671   g_return_val_if_fail (context != NULL, GDK_NONE);
672
673   if (context->protocol == GDK_DRAG_PROTO_LOCAL)
674     return (GDK_DRAG_CONTEXT_PRIVATE_DATA (context))->local_selection;
675   else
676     return GDK_NONE;
677 }
678
679 #define __GDK_DND_X11_C__
680 #include "gdkaliasdef.c"