Drag works.
[wxWidgets.git] / src / gtk / dnd.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: dnd.cpp
3 // Purpose: wxDropTarget class
4 // Author: Robert Roebling
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 ///////////////////////////////////////////////////////////////////////////////
9
10 #ifdef __GNUG__
11 #pragma implementation "dnd.h"
12 #endif
13
14 #include "wx/dnd.h"
15
16 #if wxUSE_DRAG_AND_DROP
17
18 #include "wx/window.h"
19 #include "wx/app.h"
20 #include "wx/gdicmn.h"
21 #include "wx/intl.h"
22 #include "wx/utils.h"
23
24 #include "gdk/gdk.h"
25 #include "gtk/gtk.h"
26 #include "gdk/gdkprivate.h"
27
28 #include <X11/Xlib.h>
29
30 //----------------------------------------------------------------------------
31 // global data
32 //----------------------------------------------------------------------------
33
34 extern bool g_blockEventsOnDrag;
35
36 //----------------------------------------------------------------------------
37 // standard icons
38 //----------------------------------------------------------------------------
39
40 /* XPM */
41 static char * gv_xpm[] = {
42 "40 34 3 1",
43 " s None c None",
44 ". c black",
45 "X c white",
46 " ",
47 " ",
48 " ...... ",
49 " ..XXXXXX.. ",
50 " .XXXXXXXXXX. ",
51 " .XXXXXXXXXXXX. ",
52 " .XXXXXXXXXXXX. ",
53 " .XXXXXXXXXXXXXX. ",
54 " .XXX..XXXX..XXX. ",
55 " ....XX....XX....XX. ",
56 " .XXX.XXX..XXXX..XXX.... ",
57 " .XXXXXXXXXXXXXXXXXXX.XXX. ",
58 " .XXXXXXXXXXXXXXXXXXXXXXXX. ",
59 " .XXXXXXXXXXXXXXXXXXXXXXXX. ",
60 " ..XXXXXXXXXXXXXXXXXXXXXX. ",
61 " .XXXXXXXXXXXXXXXXXX... ",
62 " ..XXXXXXXXXXXXXXXX. ",
63 " .XXXXXXXXXXXXXXXX. ",
64 " .XXXXXXXXXXXXXXXX. ",
65 " .XXXXXXXXXXXXXXXXX. ",
66 " .XXXXXXXXXXXXXXXXX. ",
67 " .XXXXXXXXXXXXXXXXXX. ",
68 " .XXXXXXXXXXXXXXXXXXX. ",
69 " .XXXXXXXXXXXXXXXXXXXXX. ",
70 " .XXXXXXXXXXXXXX.XXXXXXX. ",
71 " .XXXXXXX.XXXXXXX.XXXXXXX. ",
72 " .XXXXXXXX.XXXXXXX.XXXXXXX. ",
73 " .XXXXXXX...XXXXX...XXXXX. ",
74 " .XXXXXXX. ..... ..... ",
75 " ..XXXX.. ",
76 " .... ",
77 " ",
78 " ",
79 " "};
80
81 /* XPM */
82 static char * page_xpm[] = {
83 /* width height ncolors chars_per_pixel */
84 "32 32 5 1",
85 /* colors */
86 " s None c None",
87 ". c black",
88 "X c wheat",
89 "o c tan",
90 "O c #6699FF",
91 /* pixels */
92 " ................... ",
93 " .XXXXXXXXXXXXXXXXX.. ",
94 " .XXXXXXXXXXXXXXXXX.o. ",
95 " .XXXXXXXXXXXXXXXXX.oo. ",
96 " .XXXXXXXXXXXXXXXXX.ooo. ",
97 " .XXXXXXXXXXXXXXXXX.oooo. ",
98 " .XXXXXXXXXXXXXXXXX....... ",
99 " .XXXXXOOOOOOOOOOXXXooooo. ",
100 " .XXXXXXXXXXXXXXXXXXooooo. ",
101 " .XXXXXOOOOOOOOOOXXXXXXXX. ",
102 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
103 " .XXXXXXXOOOOOOOOOXXXXXXX. ",
104 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
105 " .XXXXXXOOOOOOOOOOXXXXXXX. ",
106 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
107 " .XXXXXOOOOOOOOOOXXXXXXXX. ",
108 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
109 " .XXXXXXXOOOOOOOOOXXXXXXX. ",
110 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
111 " .XXXXXXOOOOOOOOOOXXXXXXX. ",
112 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
113 " .XXXXXOOOOOOOOOOXXXXXXXX. ",
114 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
115 " .XXXXXXOOOOOOOOOOXXXXXXX. ",
116 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
117 " .XXXXXOOOOOOOXXXXXXXXXXX. ",
118 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
119 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
120 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
121 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
122 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
123 " ......................... "};
124
125
126 #if (GTK_MINOR_VERSION > 0)
127
128 #include "gtk/gtkdnd.h"
129 #include "gtk/gtkselection.h"
130
131
132 // ----------------------------------------------------------------------------
133 // "drag_leave"
134 // ----------------------------------------------------------------------------
135
136 static void target_drag_leave( GtkWidget *WXUNUSED(widget),
137 GdkDragContext *context,
138 guint WXUNUSED(time),
139 wxDropTarget *drop_target )
140 {
141 /* inform the wxDropTarget about the current GdkDragContext.
142 this is only valid for the duration of this call */
143 drop_target->SetDragContext( context );
144
145 /* we don't need return values. this event is just for
146 information */
147 drop_target->OnLeave();
148
149 /* this has to be done because GDK has no "drag_enter" event */
150 drop_target->m_firstMotion = TRUE;
151
152 /* after this, invalidate the drop_target's GdkDragContext */
153 drop_target->SetDragContext( (GdkDragContext*) NULL );
154 }
155
156 // ----------------------------------------------------------------------------
157 // "drag_motion"
158 // ----------------------------------------------------------------------------
159
160 static gboolean target_drag_motion( GtkWidget *WXUNUSED(widget),
161 GdkDragContext *context,
162 gint x,
163 gint y,
164 guint time,
165 wxDropTarget *drop_target )
166 {
167 /* Owen Taylor: "if the coordinates not in a drop zone,
168 return FALSE, otherwise call gtk_drag_status() and
169 return TRUE" */
170
171 /* inform the wxDropTarget about the current GdkDragContext.
172 this is only valid for the duration of this call */
173 drop_target->SetDragContext( context );
174
175 if (drop_target->m_firstMotion)
176 {
177 /* the first "drag_motion" event substitutes a "drag_enter" event */
178 drop_target->OnEnter();
179 }
180
181 /* give program a chance to react (i.e. to say no by returning FALSE) */
182 bool ret = drop_target->OnMove( x, y );
183
184 /* we don't yet handle which "actions" (i.e. copy or move)
185 the target accepts. so far we simply accept the
186 suggested action. TODO. */
187 if (ret)
188 gdk_drag_status( context, context->suggested_action, time );
189
190 /* after this, invalidate the drop_target's GdkDragContext */
191 drop_target->SetDragContext( (GdkDragContext*) NULL );
192
193 /* this has to be done because GDK has no "drag_enter" event */
194 drop_target->m_firstMotion = FALSE;
195
196 return ret;
197 }
198
199 // ----------------------------------------------------------------------------
200 // "drag_drop"
201 // ----------------------------------------------------------------------------
202
203 static gboolean target_drag_drop( GtkWidget *widget,
204 GdkDragContext *context,
205 gint x,
206 gint y,
207 guint time,
208 wxDropTarget *drop_target )
209 {
210 /* Owen Taylor: "if the drop is not in a drop zone,
211 return FALSE, otherwise, if you aren't accepting
212 the drop, call gtk_drag_finish() with success == FALSE
213 otherwise call gtk_drag_data_get()" */
214
215 // printf( "drop.\n" );
216
217 /* this seems to make a difference between not accepting
218 due to wrong target area and due to wrong format. let
219 us hope that this is not required.. */
220
221 /* inform the wxDropTarget about the current GdkDragContext.
222 this is only valid for the duration of this call */
223 drop_target->SetDragContext( context );
224
225 /* inform the wxDropTarget about the current drag widget.
226 this is only valid for the duration of this call */
227 drop_target->SetDragWidget( widget );
228
229 /* inform the wxDropTarget about the current drag time.
230 this is only valid for the duration of this call */
231 drop_target->SetDragTime( time );
232
233 bool ret = drop_target->OnDrop( x, y );
234
235 if (ret)
236 {
237 /* this should trigger an "drag_data_received" event */
238 gtk_drag_get_data( widget,
239 context,
240 GPOINTER_TO_INT (context->targets->data),
241 time );
242 }
243 else
244 {
245 /* cancel the whole thing */
246 gtk_drag_finish( context,
247 FALSE, /* no success */
248 FALSE, /* don't delete data on dropping side */
249 time );
250 }
251
252 /* after this, invalidate the drop_target's GdkDragContext */
253 drop_target->SetDragContext( (GdkDragContext*) NULL );
254
255 /* after this, invalidate the drop_target's drag widget */
256 drop_target->SetDragWidget( (GtkWidget*) NULL );
257
258 /* this has to be done because GDK has no "drag_enter" event */
259 drop_target->m_firstMotion = TRUE;
260
261 return ret;
262 }
263
264 // ----------------------------------------------------------------------------
265 // "drag_data_received"
266 // ----------------------------------------------------------------------------
267
268 static void target_drag_data_received( GtkWidget *WXUNUSED(widget),
269 GdkDragContext *context,
270 gint x,
271 gint y,
272 GtkSelectionData *data,
273 guint WXUNUSED(info),
274 guint time,
275 wxDropTarget *drop_target )
276 {
277 /* Owen Taylor: "call gtk_drag_finish() with
278 success == TRUE" */
279
280 // printf( "data received.\n" );
281
282 /* strangely, we get a "drag_data_received" event even when
283 we don't request them. this checks this. */
284 if (!drop_target->m_currentDataObject) return;
285
286 wxDataObject *data_object = drop_target->m_currentDataObject;
287
288 if ((data->length <= 0) || (data->format != 8))
289 {
290 /* negative data length and non 8-bit data format
291 qualifies for junk */
292 gtk_drag_finish (context, FALSE, FALSE, time);
293 }
294 else
295 {
296 wxASSERT_MSG( data->target == data_object->GetFormat().GetAtom(), "DnD GetData target mismatch." );
297
298 if (data_object->GetFormat().GetType() == wxDF_TEXT)
299 {
300 wxTextDataObject *text_object = (wxTextDataObject*)data_object;
301 text_object->SetText( (const char*)data->data );
302 } else
303
304 if (data_object->GetFormat().GetType() == wxDF_FILENAME)
305 {
306 } else
307
308 if (data_object->GetFormat().GetType() == wxDF_PRIVATE)
309 {
310 wxPrivateDataObject *priv_object = (wxPrivateDataObject*)data_object;
311 priv_object->SetData( (const char*)data->data, (size_t)data->length );
312 }
313
314 /* tell wxDropTarget that data transfer was successfull */
315 drop_target->m_dataRetrieveSuccess = TRUE;
316
317 /* tell GTK that data transfer was successfull */
318 gtk_drag_finish( context, TRUE, FALSE, time );
319 }
320
321 /* tell wxDropTarget that data has arrived (or not) */
322 drop_target->m_waiting = FALSE;
323 }
324
325 //----------------------------------------------------------------------------
326 // wxDropTarget
327 //----------------------------------------------------------------------------
328
329 wxDropTarget::wxDropTarget()
330 {
331 m_firstMotion = TRUE;
332 m_dragContext = (GdkDragContext*) NULL;
333 m_dragWidget = (GtkWidget*) NULL;
334 m_dragTime = 0;
335 m_currentDataObject = (wxDataObject*) NULL;
336 m_dataRetrieveSuccess = FALSE;
337 }
338
339 wxDropTarget::~wxDropTarget()
340 {
341 }
342
343 void wxDropTarget::OnEnter()
344 {
345 }
346
347 void wxDropTarget::OnLeave()
348 {
349 }
350
351 bool wxDropTarget::OnMove( int WXUNUSED(x), int WXUNUSED(y) )
352 {
353 return TRUE;
354 }
355
356 bool wxDropTarget::OnDrop( int WXUNUSED(x), int WXUNUSED(y) )
357 {
358 return FALSE;
359 }
360
361 bool wxDropTarget::IsSupported( wxDataFormat format )
362 {
363 if (!m_dragContext) return FALSE;
364
365 GList *child = m_dragContext->targets;
366 while (child)
367 {
368 GdkAtom formatAtom = (GdkAtom) GPOINTER_TO_INT(child->data);
369
370 // char *name = gdk_atom_name( formatAtom );
371 // if (name) printf( "Format available: %s.\n", name );
372
373 if (formatAtom == format.GetAtom()) return TRUE;
374 child = child->next;
375 }
376
377 return FALSE;
378 }
379
380 bool wxDropTarget::GetData( wxDataObject *data )
381 {
382 if (!m_dragContext) return FALSE;
383 if (!m_dragWidget) return FALSE;
384
385 m_currentDataObject = data;
386 m_dataRetrieveSuccess = FALSE;
387
388 /* this should trigger an "drag_data_received" event */
389 gtk_drag_get_data( m_dragWidget,
390 m_dragContext,
391 data->GetFormat().GetAtom(),
392 m_dragTime );
393
394 /* wait for the "drag_data_received" event */
395
396 // printf( "pre wait.\n" );
397
398 m_waiting = TRUE;
399 while (m_waiting) wxYield();
400
401 // printf( "post wait.\n" );
402
403 m_currentDataObject = (wxDataObject*) NULL;
404
405 return m_dataRetrieveSuccess;
406 }
407
408 void wxDropTarget::UnregisterWidget( GtkWidget *widget )
409 {
410 wxCHECK_RET( widget != NULL, "unregister widget is NULL" );
411
412 gtk_drag_dest_unset( widget );
413
414 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
415 GTK_SIGNAL_FUNC(target_drag_leave), (gpointer) this );
416
417 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
418 GTK_SIGNAL_FUNC(target_drag_motion), (gpointer) this );
419
420 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
421 GTK_SIGNAL_FUNC(target_drag_drop), (gpointer) this );
422
423 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
424 GTK_SIGNAL_FUNC(target_drag_data_received), (gpointer) this );
425 }
426
427 void wxDropTarget::RegisterWidget( GtkWidget *widget )
428 {
429 wxCHECK_RET( widget != NULL, "register widget is NULL" );
430
431 /* gtk_drag_dest_set() determines what default behaviour we'd like
432 GTK to supply. we don't want to specify out targets (=formats)
433 or actions in advance (i.e. not GTK_DEST_DEFAULT_MOTION and
434 not GTK_DEST_DEFAULT_DROP). instead we react individually to
435 "drag_motion" and "drag_drop" events. this makes it possible
436 to allow dropping on only a small area. we should set
437 GTK_DEST_DEFAULT_HIGHLIGHT as this will switch on the nice
438 highlighting if dragging over standard controls, but this
439 seems to be broken without the other two. */
440
441 gtk_drag_dest_set( widget,
442 (GtkDestDefaults) 0, /* no default behaviour */
443 (GtkTargetEntry*) NULL, /* we don't supply any formats here */
444 0, /* number of targets = 0 */
445 (GdkDragAction) 0 ); /* we don't supply any actions here */
446
447 gtk_signal_connect( GTK_OBJECT(widget), "drag_leave",
448 GTK_SIGNAL_FUNC(target_drag_leave), (gpointer) this );
449
450 gtk_signal_connect( GTK_OBJECT(widget), "drag_motion",
451 GTK_SIGNAL_FUNC(target_drag_motion), (gpointer) this );
452
453 gtk_signal_connect( GTK_OBJECT(widget), "drag_drop",
454 GTK_SIGNAL_FUNC(target_drag_drop), (gpointer) this );
455
456 gtk_signal_connect( GTK_OBJECT(widget), "drag_data_received",
457 GTK_SIGNAL_FUNC(target_drag_data_received), (gpointer) this );
458 }
459
460 //-------------------------------------------------------------------------
461 // wxTextDropTarget
462 //-------------------------------------------------------------------------
463
464 bool wxTextDropTarget::OnMove( int WXUNUSED(x), int WXUNUSED(y) )
465 {
466 return IsSupported( wxDF_TEXT ); // same as "STRING"
467 }
468
469 bool wxTextDropTarget::OnDrop( int x, int y )
470 {
471 if (!IsSupported( wxDF_TEXT )) return FALSE;
472
473 wxTextDataObject data;
474 if (!GetData( &data )) return FALSE;
475
476 OnDropText( x, y, data.GetText() );
477 return TRUE;
478 }
479
480 //-------------------------------------------------------------------------
481 // wxPrivateDropTarget
482 //-------------------------------------------------------------------------
483
484 wxPrivateDropTarget::wxPrivateDropTarget()
485 {
486 m_id = wxTheApp->GetAppName();
487 }
488
489 wxPrivateDropTarget::wxPrivateDropTarget( const wxString &id )
490 {
491 m_id = id;
492 }
493
494 bool wxPrivateDropTarget::OnMove( int WXUNUSED(x), int WXUNUSED(y) )
495 {
496 return IsSupported( m_id );
497 }
498
499 bool wxPrivateDropTarget::OnDrop( int x, int y )
500 {
501 if (!IsSupported( m_id )) return FALSE;
502
503 wxPrivateDataObject data;
504 if (!GetData( &data )) return FALSE;
505
506 OnDropData( x, y, data.GetData(), data.GetSize() );
507
508 return TRUE;
509 }
510
511 //----------------------------------------------------------------------------
512 // A drop target which accepts files (dragged from File Manager or Explorer)
513 //----------------------------------------------------------------------------
514
515 bool wxFileDropTarget::OnMove( int WXUNUSED(x), int WXUNUSED(y) )
516 {
517 return IsSupported( wxDF_FILENAME ); // same as "file:ALL"
518 }
519
520 bool wxFileDropTarget::OnDrop( int x, int y )
521 {
522 return IsSupported( wxDF_FILENAME ); // same as "file:ALL"
523 }
524
525 void wxFileDropTarget::OnData( int x, int y )
526 {
527 wxFileDataObject data;
528 if (!GetData( &data )) return;
529
530 /* get number of substrings /root/mytext.txt/0/root/myothertext.txt/0/0 */
531 size_t number = 0;
532 size_t i;
533 size_t size = data.GetFiles().Length();
534 char *text = WXSTRINGCAST data.GetFiles();
535 for ( i = 0; i < size; i++)
536 if (text[i] == 0) number++;
537
538 if (number == 0) return;
539
540 char **files = new char*[number];
541
542 text = WXSTRINGCAST data.GetFiles();
543 for (i = 0; i < number; i++)
544 {
545 files[i] = text;
546 int len = strlen( text );
547 text += len+1;
548 }
549
550 OnDropFiles( x, y, number, files );
551
552 free( files );
553 }
554
555 //----------------------------------------------------------------------------
556 // "drag_data_get"
557 //----------------------------------------------------------------------------
558
559 static void
560 source_drag_data_get (GtkWidget *WXUNUSED(widget),
561 GdkDragContext *context,
562 GtkSelectionData *selection_data,
563 guint WXUNUSED(info),
564 guint WXUNUSED(time),
565 wxDropSource *drop_source )
566 {
567 char *name = gdk_atom_name( selection_data->target );
568 if (name) printf( "Format requested: %s.\n", name );
569
570 wxNode *node = drop_source->m_data->m_dataObjects.First();
571 while (node)
572 {
573 wxDataObject *data_object = (wxDataObject*) node->Data();
574 if (data_object->GetFormat().GetAtom() == selection_data->target)
575 {
576 size_t data_size = data_object->GetSize();
577 if (data_size > 0)
578 {
579 guchar *buffer = new guchar[data_size];
580 data_object->WriteData( buffer );
581
582 gtk_selection_data_set( selection_data,
583 selection_data->target,
584 8, /* 8-bit */
585 buffer,
586 data_size );
587
588 free( buffer );
589
590 /* so far only copy, no moves. TODO. */
591 drop_source->m_retValue = wxDragCopy;
592
593 return;
594 }
595 }
596
597 node = node->Next();
598 }
599
600 drop_source->m_retValue = wxDragCancel;
601 }
602
603 //----------------------------------------------------------------------------
604 // "drag_data_delete"
605 //----------------------------------------------------------------------------
606
607 static void source_drag_data_delete( GtkWidget *WXUNUSED(widget),
608 GdkDragContext *WXUNUSED(context),
609 wxDropSource *drop_source )
610 {
611 // printf( "Delete the data!\n" );
612
613 drop_source->m_retValue = wxDragMove;
614 }
615
616 //----------------------------------------------------------------------------
617 // "drag_begin"
618 //----------------------------------------------------------------------------
619
620 static void source_drag_begin( GtkWidget *WXUNUSED(widget),
621 GdkDragContext *WXUNUSED(context),
622 wxDropSource *WXUNUSED(drop_source) )
623 {
624 // printf( "drag_begin.\n" );
625 }
626
627 //----------------------------------------------------------------------------
628 // "drag_end"
629 //----------------------------------------------------------------------------
630
631 static void source_drag_end( GtkWidget *WXUNUSED(widget),
632 GdkDragContext *WXUNUSED(context),
633 wxDropSource *drop_source )
634 {
635 // printf( "drag_end.\n" );
636
637 drop_source->m_waiting = FALSE;
638 }
639
640 //---------------------------------------------------------------------------
641 // wxDropSource
642 //---------------------------------------------------------------------------
643
644 wxDropSource::wxDropSource( wxWindow *win, const wxIcon &go, const wxIcon &stop )
645 {
646 g_blockEventsOnDrag = TRUE;
647 m_waiting = TRUE;
648
649 m_window = win;
650 m_widget = win->m_widget;
651 if (win->m_wxwindow) m_widget = win->m_wxwindow;
652
653 m_data = (wxDataBroker*) NULL;
654 m_retValue = wxDragCancel;
655
656 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
657 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
658
659 m_goIcon = go;
660 if (wxNullIcon == go) m_goIcon = wxIcon( page_xpm );
661 m_stopIcon = stop;
662 if (wxNullIcon == stop) m_stopIcon = wxIcon( gv_xpm );
663 }
664
665 wxDropSource::wxDropSource( wxDataObject *data, wxWindow *win, const wxIcon &go, const wxIcon &stop )
666 {
667 m_waiting = TRUE;
668
669 m_window = win;
670 m_widget = win->m_widget;
671 if (win->m_wxwindow) m_widget = win->m_wxwindow;
672 m_retValue = wxDragCancel;
673
674 if (data)
675 {
676 m_data = new wxDataBroker();
677 m_data->Add( data );
678 }
679 else
680 {
681 m_data = (wxDataBroker*) NULL;
682 }
683
684 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
685 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
686
687 m_goIcon = go;
688 if (wxNullIcon == go) m_goIcon = wxIcon( page_xpm );
689 m_stopIcon = stop;
690 if (wxNullIcon == stop) m_stopIcon = wxIcon( gv_xpm );
691 }
692
693 wxDropSource::wxDropSource( wxDataBroker *data, wxWindow *win )
694 {
695 m_window = win;
696 m_widget = win->m_widget;
697 if (win->m_wxwindow) m_widget = win->m_wxwindow;
698 m_retValue = wxDragCancel;
699
700 m_data = data;
701
702 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
703 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
704 }
705
706 void wxDropSource::SetData( wxDataObject *data )
707 {
708 if (m_data) delete m_data;
709
710 if (data)
711 {
712 m_data = new wxDataBroker();
713 m_data->Add( data );
714 }
715 else
716 {
717 m_data = (wxDataBroker*) NULL;
718 }
719 }
720
721 void wxDropSource::SetData( wxDataBroker *data )
722 {
723 if (m_data) delete m_data;
724
725 m_data = data;
726 }
727
728 wxDropSource::~wxDropSource(void)
729 {
730 if (m_data) delete m_data;
731
732 g_blockEventsOnDrag = FALSE;
733 }
734
735 wxDragResult wxDropSource::DoDragDrop( bool WXUNUSED(bAllowMove) )
736 {
737 wxASSERT_MSG( m_data, "wxDragSource: no data" );
738
739 if (!m_data) return (wxDragResult) wxDragNone;
740
741 g_blockEventsOnDrag = TRUE;
742
743 RegisterWindow();
744
745 m_waiting = TRUE;
746
747 GtkTargetList *target_list = gtk_target_list_new( (GtkTargetEntry*) NULL, 0 );
748 gtk_target_list_add( target_list, gdk_atom_intern( "STRING", FALSE ), 0, 0 );
749
750 GdkEventMotion event;
751 event.window = m_widget->window;
752 int x = 0;
753 int y = 0;
754 GdkModifierType state;
755 gdk_window_get_pointer( event.window, &x, &y, &state );
756 event.x = x;
757 event.y = y;
758 event.state = state;
759
760 /* GTK wants to know which button was pressed which caused the dragging */
761 int button_number = 0;
762 if (event.state & GDK_BUTTON1_MASK) button_number = 1;
763 else if (event.state & GDK_BUTTON2_MASK) button_number = 2;
764 else if (event.state & GDK_BUTTON3_MASK) button_number = 3;
765
766 /* don't start dragging if no button is down */
767 if (button_number)
768 {
769 GdkDragContext *context = gtk_drag_begin( m_widget,
770 target_list,
771 GDK_ACTION_COPY,
772 button_number, /* number of mouse button which started drag */
773 (GdkEvent*) &event );
774
775 wxMask *mask = m_goIcon.GetMask();
776 GdkBitmap *bm = (GdkBitmap *) NULL;
777 if (mask) bm = mask->GetBitmap();
778 GdkPixmap *pm = m_goIcon.GetPixmap();
779
780 gtk_drag_set_icon_pixmap( context,
781 gtk_widget_get_colormap( m_widget ),
782 pm,
783 bm,
784 0,
785 0 );
786
787 while (m_waiting) wxYield();
788 }
789
790 g_blockEventsOnDrag = FALSE;
791
792 UnregisterWindow();
793
794 return m_retValue;
795 }
796
797 void wxDropSource::RegisterWindow()
798 {
799 if (!m_widget) return;
800
801 gtk_signal_connect( GTK_OBJECT(m_widget), "drag_data_get",
802 GTK_SIGNAL_FUNC (source_drag_data_get), (gpointer) this);
803 gtk_signal_connect (GTK_OBJECT(m_widget), "drag_data_delete",
804 GTK_SIGNAL_FUNC (source_drag_data_delete), (gpointer) this );
805 gtk_signal_connect (GTK_OBJECT(m_widget), "drag_begin",
806 GTK_SIGNAL_FUNC (source_drag_begin), (gpointer) this );
807 gtk_signal_connect (GTK_OBJECT(m_widget), "drag_end",
808 GTK_SIGNAL_FUNC (source_drag_end), (gpointer) this );
809
810 }
811
812 void wxDropSource::UnregisterWindow()
813 {
814 if (!m_widget) return;
815
816 gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget),
817 GTK_SIGNAL_FUNC(source_drag_data_get), (gpointer) this );
818 gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget),
819 GTK_SIGNAL_FUNC(source_drag_data_delete), (gpointer) this );
820 gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget),
821 GTK_SIGNAL_FUNC(source_drag_begin), (gpointer) this );
822 gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget),
823 GTK_SIGNAL_FUNC(source_drag_end), (gpointer) this );
824 }
825
826
827 #else // NEW_CODE
828
829 //----------------------------------------------------------------------------
830 // forward
831 //----------------------------------------------------------------------------
832
833 GtkWidget *shape_create_icon ( const wxIcon &shape,
834 gint x,
835 gint y,
836 gint px,
837 gint py,
838 gint window_type);
839
840 //-----------------------------------------------------------------------------
841 // globals
842 //-----------------------------------------------------------------------------
843
844 wxDropSource *gs_currentDropSource = (wxDropSource*) NULL;
845
846 //-----------------------------------------------------------------------------
847 // "drop_enter_event"
848 //-----------------------------------------------------------------------------
849
850 static void gtk_target_enter_callback( GtkWidget *WXUNUSED(widget),
851 GdkEventDropEnter *WXUNUSED(event),
852 wxDropTarget *target )
853 {
854 if (target)
855 target->OnEnter();
856 }
857
858 //-----------------------------------------------------------------------------
859 // "drop_leave_event"
860 //-----------------------------------------------------------------------------
861
862 static void gtk_target_leave_callback( GtkWidget *WXUNUSED(widget),
863 GdkEventDropLeave *WXUNUSED(event),
864 wxDropTarget *target )
865 {
866 if (target)
867 target->OnLeave();
868 }
869
870 //-----------------------------------------------------------------------------
871 // "drop_data_available_event"
872 //-----------------------------------------------------------------------------
873
874 static void gtk_target_callback( GtkWidget *widget,
875 GdkEventDropDataAvailable *event,
876 wxDropTarget *target )
877 {
878 if (target)
879 {
880 int x = 0;
881 int y = 0;
882 gdk_window_get_pointer( widget->window, &x, &y, (GdkModifierType *) NULL );
883 /*
884 printf( "Drop data is of type %s.\n", event->data_type );
885 */
886 target->OnDrop( x, y, (const void*)event->data, (size_t)event->data_numbytes );
887 }
888
889 /*
890 g_free (event->data);
891 g_free (event->data_type);
892 */
893 }
894
895 // ----------------------------------------------------------------------------
896 // wxDropTarget
897 // ----------------------------------------------------------------------------
898
899 wxDropTarget::wxDropTarget()
900 {
901 m_format = (wxDataFormat*) NULL;
902 }
903
904 wxDropTarget::~wxDropTarget()
905 {
906 if (m_format) delete m_format;
907 }
908
909 wxDataFormat &wxDropTarget::GetFormat(size_t n) const
910 {
911 return (*m_format);
912 }
913
914 void wxDropTarget::UnregisterWidget( GtkWidget *widget )
915 {
916 if (!widget) return;
917
918 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
919 GTK_SIGNAL_FUNC(gtk_target_callback), (gpointer) this );
920
921 gtk_widget_dnd_drop_set( widget, FALSE, (gchar **) NULL, 0, FALSE );
922 }
923
924 void wxDropTarget::RegisterWidget( GtkWidget *widget )
925 {
926 wxString formats;
927 int valid = 0;
928
929 for ( size_t i = 0; i < GetFormatCount(); i++ )
930 {
931 switch (GetFormat(i).GetType())
932 {
933 case wxDF_TEXT:
934 {
935 if (i > 0) formats += ";";
936 formats += "text/plain";
937 valid++;
938 break;
939 }
940 case wxDF_FILENAME:
941 {
942 if (i > 0) formats += ";";
943 formats += "file:ALL";
944 valid++;
945 break;
946 }
947 case wxDF_PRIVATE:
948 {
949 if (i > 0) formats += ";";
950 wxPrivateDropTarget *pdt = (wxPrivateDropTarget *)this;
951 formats += pdt->GetId();
952 valid++;
953 break;
954 }
955 default:
956 break;
957 }
958 }
959
960 char *str = WXSTRINGCAST formats;
961
962 gtk_widget_dnd_drop_set( widget, TRUE, &str, valid, FALSE );
963
964 gtk_signal_connect( GTK_OBJECT(widget), "drop_data_available_event",
965 GTK_SIGNAL_FUNC(gtk_target_callback), (gpointer) this );
966
967 gtk_signal_connect( GTK_OBJECT(widget), "drop_enter_event",
968 GTK_SIGNAL_FUNC(gtk_target_enter_callback), (gpointer) this );
969
970 gtk_signal_connect( GTK_OBJECT(widget), "drop_leave_event",
971 GTK_SIGNAL_FUNC(gtk_target_leave_callback), (gpointer) this );
972 }
973
974 // ----------------------------------------------------------------------------
975 // wxTextDropTarget
976 // ----------------------------------------------------------------------------
977
978 wxTextDropTarget::wxTextDropTarget()
979 {
980 m_format = new wxDataFormat( wxDF_TEXT );
981 }
982
983 bool wxTextDropTarget::OnDrop( long x, long y, const void *data, size_t WXUNUSED(size) )
984 {
985 OnDropText( x, y, (const char*)data );
986 return TRUE;
987 }
988
989 bool wxTextDropTarget::OnDropText( long x, long y, const char *psz )
990 {
991 /*
992 printf( "Got dropped text: %s.\n", psz );
993 printf( "At x: %d, y: %d.\n", (int)x, (int)y );
994 */
995 return TRUE;
996 }
997
998 size_t wxTextDropTarget::GetFormatCount() const
999 {
1000 return 1;
1001 }
1002
1003 // ----------------------------------------------------------------------------
1004 // wxPrivateDropTarget
1005 // ----------------------------------------------------------------------------
1006
1007 wxPrivateDropTarget::wxPrivateDropTarget()
1008 {
1009 m_id = wxTheApp->GetAppName();
1010 m_format = new wxDataFormat( m_id );
1011 }
1012
1013 void wxPrivateDropTarget::SetId( const wxString& id )
1014 {
1015 m_id = id;
1016 m_format->SetId( id );
1017 }
1018
1019 size_t wxPrivateDropTarget::GetFormatCount() const
1020 {
1021 return 1;
1022 }
1023
1024 // ----------------------------------------------------------------------------
1025 // wxFileDropTarget
1026 // ----------------------------------------------------------------------------
1027
1028 wxFileDropTarget::wxFileDropTarget()
1029 {
1030 m_format = new wxDataFormat( wxDF_FILENAME );
1031 }
1032
1033 bool wxFileDropTarget::OnDropFiles( long x, long y, size_t nFiles, const char * const aszFiles[] )
1034 {
1035 printf( "Got %d dropped files.\n", (int)nFiles );
1036 printf( "At x: %d, y: %d.\n", (int)x, (int)y );
1037
1038 for (size_t i = 0; i < nFiles; i++)
1039 {
1040 printf( aszFiles[i] );
1041 printf( "\n" );
1042 }
1043
1044 return TRUE;
1045 }
1046
1047 bool wxFileDropTarget::OnDrop(long x, long y, const void *data, size_t size )
1048 {
1049 size_t number = 0;
1050 size_t i;
1051 char *text = (char*) data;
1052 for ( i = 0; i < size; i++)
1053 if (text[i] == 0) number++;
1054
1055 if (number == 0) return TRUE;
1056
1057 char **files = new char*[number];
1058
1059 text = (char*) data;
1060 for (i = 0; i < number; i++)
1061 {
1062 files[i] = text;
1063 int len = strlen( text );
1064 text += len+1;
1065 }
1066
1067 bool ret = OnDropFiles( x, y, 1, files );
1068
1069 free( files );
1070
1071 return ret;
1072 }
1073
1074 size_t wxFileDropTarget::GetFormatCount() const
1075 {
1076 return 1;
1077 }
1078
1079 //-------------------------------------------------------------------------
1080 // wxDropSource
1081 //-------------------------------------------------------------------------
1082
1083 static void
1084 shape_motion (GtkWidget *widget,
1085 GdkEventMotion * /*event*/);
1086
1087 //-----------------------------------------------------------------------------
1088 // "drag_request_event"
1089 //-----------------------------------------------------------------------------
1090
1091 void gtk_drag_callback( GtkWidget *widget, GdkEventDragRequest *event, wxDropSource *source )
1092 {
1093 wxDataBroker *data = source->m_data;
1094
1095 if (!data) return;
1096
1097 wxNode *node = data->m_dataObjects.First();
1098 {
1099 wxDataObject *dobj = (wxDataObject*) node->Data();
1100
1101 if ((strcmp(event->data_type,"file:ALL") == 0) &&
1102 (dobj->GetFormat().GetType() == wxDF_FILENAME))
1103 {
1104 wxFileDataObject *file_object = (wxFileDataObject*) dobj;
1105
1106 wxString text = file_object->GetFiles();
1107
1108 char *s = WXSTRINGCAST text;
1109
1110 gtk_widget_dnd_data_set( widget,
1111 (GdkEvent*)event,
1112 (unsigned char*) s,
1113 (int) text.Length()+1 );
1114
1115 source->m_retValue = wxDragCopy;
1116
1117 return;
1118 }
1119
1120 if ((strcmp(event->data_type,"text/plain") == 0) &&
1121 (dobj->GetFormat().GetType() == wxDF_TEXT))
1122 {
1123 wxTextDataObject *text_object = (wxTextDataObject*) dobj;
1124
1125 wxString text = text_object->GetText();
1126
1127 char *s = WXSTRINGCAST text;
1128
1129 gtk_widget_dnd_data_set( widget,
1130 (GdkEvent*)event,
1131 (unsigned char*) s,
1132 (int) text.Length()+1 );
1133
1134 source->m_retValue = wxDragCopy;
1135
1136 return;
1137 }
1138
1139 if (dobj->GetFormat().GetType() == wxDF_PRIVATE)
1140 {
1141 wxPrivateDataObject *pdo = (wxPrivateDataObject*) dobj;
1142
1143 if (pdo->GetId() == event->data_type)
1144 {
1145 gtk_widget_dnd_data_set( widget,
1146 (GdkEvent*)event,
1147 (unsigned char*) pdo->GetData(),
1148 (int) pdo->GetSize() );
1149
1150 source->m_retValue = wxDragCopy;
1151
1152 return;
1153 }
1154 }
1155
1156 node = node->Next();
1157 }
1158 }
1159
1160 wxDropSource::wxDropSource( wxWindow *win, const wxIcon &go, const wxIcon &stop )
1161 {
1162 g_blockEventsOnDrag = TRUE;
1163
1164 m_window = win;
1165 m_widget = win->m_widget;
1166 if (win->m_wxwindow) m_widget = win->m_wxwindow;
1167
1168 m_data = (wxDataBroker*) NULL;
1169 m_retValue = wxDragCancel;
1170
1171 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
1172 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
1173
1174 m_goIcon = go;
1175 if (wxNullIcon == go) m_goIcon = wxIcon( page_xpm );
1176 m_stopIcon = stop;
1177 if (wxNullIcon == stop) m_stopIcon = wxIcon( gv_xpm );
1178 }
1179
1180 wxDropSource::wxDropSource( wxDataObject *data, wxWindow *win, const wxIcon &go, const wxIcon &stop )
1181 {
1182 g_blockEventsOnDrag = TRUE;
1183
1184 m_window = win;
1185 m_widget = win->m_widget;
1186 if (win->m_wxwindow) m_widget = win->m_wxwindow;
1187 m_retValue = wxDragCancel;
1188
1189 if (data)
1190 {
1191 m_data = new wxDataBroker();
1192 m_data->Add( data );
1193 }
1194 else
1195 {
1196 m_data = (wxDataBroker*) NULL;
1197 }
1198
1199 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
1200 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
1201
1202 m_goIcon = go;
1203 if (wxNullIcon == go) m_goIcon = wxIcon( page_xpm );
1204 m_stopIcon = stop;
1205 if (wxNullIcon == stop) m_stopIcon = wxIcon( gv_xpm );
1206 }
1207
1208 wxDropSource::wxDropSource( wxDataBroker *data, wxWindow *win )
1209 {
1210 g_blockEventsOnDrag = TRUE;
1211
1212 m_window = win;
1213 m_widget = win->m_widget;
1214 if (win->m_wxwindow) m_widget = win->m_wxwindow;
1215 m_retValue = wxDragCancel;
1216
1217 m_data = data;
1218
1219 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
1220 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
1221 }
1222
1223 void wxDropSource::SetData( wxDataObject *data )
1224 {
1225 if (m_data) delete m_data;
1226
1227 if (data)
1228 {
1229 m_data = new wxDataBroker();
1230 m_data->Add( data );
1231 }
1232 else
1233 {
1234 m_data = (wxDataBroker*) NULL;
1235 }
1236 }
1237
1238 void wxDropSource::SetData( wxDataBroker *data )
1239 {
1240 if (m_data) delete m_data;
1241
1242 m_data = data;
1243 }
1244
1245 wxDropSource::~wxDropSource(void)
1246 {
1247 if (m_data) delete m_data;
1248
1249 g_blockEventsOnDrag = FALSE;
1250 }
1251
1252 wxDragResult wxDropSource::DoDragDrop( bool WXUNUSED(bAllowMove) )
1253 {
1254 if (gdk_dnd.dnd_grabbed) return (wxDragResult) wxDragNone;
1255 if (gdk_dnd.drag_really) return (wxDragResult) wxDragNone;
1256
1257 wxASSERT_MSG( m_data, "wxDragSource: no data" );
1258
1259 if (!m_data) return (wxDragResult) wxDragNone;
1260
1261 static GtkWidget *drag_icon = (GtkWidget*) NULL;
1262 static GtkWidget *drop_icon = (GtkWidget*) NULL;
1263
1264 GdkPoint hotspot_1 = {0,-5 };
1265
1266 if (!drag_icon)
1267 {
1268 drag_icon = shape_create_icon ( m_stopIcon,
1269 440, 140, 0,0, GTK_WINDOW_POPUP);
1270
1271 gtk_signal_connect (GTK_OBJECT (drag_icon), "destroy",
1272 GTK_SIGNAL_FUNC(gtk_widget_destroyed),
1273 &drag_icon);
1274
1275 gtk_widget_hide (drag_icon);
1276 }
1277
1278 GdkPoint hotspot_2 = {-5,-5};
1279
1280 if (!drop_icon)
1281 {
1282 drop_icon = shape_create_icon ( m_goIcon,
1283 440, 140, 0,0, GTK_WINDOW_POPUP);
1284
1285 gtk_signal_connect (GTK_OBJECT (drop_icon), "destroy",
1286 GTK_SIGNAL_FUNC(gtk_widget_destroyed),
1287 &drop_icon);
1288
1289 gtk_widget_hide (drop_icon);
1290 }
1291
1292
1293 gdk_dnd_set_drag_shape( drag_icon->window,
1294 &hotspot_1,
1295 drop_icon->window,
1296 &hotspot_2);
1297
1298
1299 GdkWindowPrivate *wp = (GdkWindowPrivate*) m_widget->window;
1300
1301 RegisterWindow();
1302
1303 gdk_dnd.drag_perhaps = TRUE;
1304
1305 gdk_dnd.dnd_drag_start.x = 5;
1306 gdk_dnd.dnd_drag_start.y = 5;
1307 gdk_dnd.real_sw = wp;
1308
1309 if (gdk_dnd.drag_startwindows)
1310 {
1311 g_free( gdk_dnd.drag_startwindows );
1312 gdk_dnd.drag_startwindows = (GdkWindow **) NULL;
1313 }
1314 gdk_dnd.drag_numwindows = gdk_dnd.drag_really = 0;
1315
1316 XWindowAttributes dnd_winattr;
1317 XGetWindowAttributes( gdk_display, wp->xwindow, &dnd_winattr );
1318 wp->dnd_drag_savedeventmask = dnd_winattr.your_event_mask;
1319
1320 gdk_dnd_drag_addwindow( m_widget->window );
1321
1322 GdkEventDragBegin ev;
1323 ev.type = GDK_DRAG_BEGIN;
1324 ev.window = m_widget->window;
1325 ev.u.allflags = 0;
1326 ev.u.flags.protocol_version = DND_PROTOCOL_VERSION;
1327
1328 gdk_event_put( (GdkEvent*)&ev );
1329
1330 XGrabPointer( gdk_display, wp->xwindow, False,
1331 ButtonMotionMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
1332 GrabModeAsync, GrabModeAsync, gdk_root_window, None, CurrentTime );
1333
1334 gdk_dnd_set_drag_cursors( m_defaultCursor.GetCursor(), m_goaheadCursor.GetCursor() );
1335
1336 gdk_dnd.dnd_grabbed = TRUE;
1337 gdk_dnd.drag_really = 1;
1338
1339 int x = 0;
1340 int y = 0;
1341 wxGetMousePosition( &x, &y );
1342
1343 gdk_dnd_display_drag_cursor( x, y, FALSE, TRUE );
1344
1345 gs_currentDropSource = this;
1346
1347 while (gdk_dnd.drag_really || gdk_dnd.drag_perhaps) wxYield();
1348
1349 gs_currentDropSource = (wxDropSource*) NULL;
1350
1351 UnregisterWindow();
1352
1353 g_blockEventsOnDrag = FALSE;
1354
1355 return m_retValue;
1356 }
1357
1358 void wxDropSource::RegisterWindow(void)
1359 {
1360 if (!m_data) return;
1361
1362 wxString formats;
1363
1364 wxNode *node = m_data->m_dataObjects.First();
1365 while (node)
1366 {
1367 wxDataObject* dobj = (wxDataObject*) node->Data();
1368
1369 switch (dobj->GetFormat().GetType())
1370 {
1371 case wxDF_TEXT:
1372 {
1373 formats += "text/plain";
1374 break;
1375 }
1376 case wxDF_FILENAME:
1377 {
1378 formats += "file:ALL";
1379 break;
1380 }
1381 case wxDF_PRIVATE:
1382 {
1383 wxPrivateDataObject* pdo = (wxPrivateDataObject*) m_data;
1384 formats += pdo->GetId();
1385 break;
1386 }
1387 default:
1388 break;
1389 }
1390 node = node->Next();
1391 }
1392
1393 char *str = WXSTRINGCAST formats;
1394
1395 gtk_widget_dnd_drag_set( m_widget, TRUE, &str, 1 );
1396
1397 gtk_signal_connect( GTK_OBJECT(m_widget), "drag_request_event",
1398 GTK_SIGNAL_FUNC(gtk_drag_callback), (gpointer)this );
1399 }
1400
1401 void wxDropSource::UnregisterWindow(void)
1402 {
1403 if (!m_widget) return;
1404
1405 gtk_widget_dnd_drag_set( m_widget, FALSE, (gchar **) NULL, 0 );
1406
1407 gtk_signal_disconnect_by_data( GTK_OBJECT(m_widget), (gpointer)this );
1408 }
1409
1410
1411 /*
1412 * Shaped Windows
1413 */
1414 static GdkWindow *root_win = (GdkWindow*) NULL;
1415
1416 typedef struct _cursoroffset {gint x,y;} CursorOffset;
1417
1418 static void
1419 shape_pressed (GtkWidget *widget, GdkEventButton *event)
1420 {
1421 CursorOffset *p;
1422
1423 /* ignore double and triple click */
1424 if (event->type != GDK_BUTTON_PRESS)
1425 return;
1426
1427 p = (CursorOffset *)gtk_object_get_user_data (GTK_OBJECT(widget));
1428 p->x = (int) event->x;
1429 p->y = (int) event->y;
1430
1431 gtk_grab_add (widget);
1432 gdk_pointer_grab (widget->window, TRUE,
1433 (GdkEventMask)
1434 (GDK_BUTTON_RELEASE_MASK |
1435 GDK_BUTTON_MOTION_MASK |
1436 GDK_POINTER_MOTION_HINT_MASK),
1437 (GdkWindow*)NULL,
1438 (GdkCursor*) NULL, 0);
1439 }
1440
1441
1442 static void
1443 shape_released (GtkWidget *widget)
1444 {
1445 gtk_grab_remove (widget);
1446 gdk_pointer_ungrab (0);
1447 }
1448
1449 static void
1450 shape_motion (GtkWidget *widget,
1451 GdkEventMotion * /*event*/ )
1452 {
1453 gint xp, yp;
1454 CursorOffset * p;
1455 GdkModifierType mask;
1456
1457 p = (CursorOffset *)gtk_object_get_user_data (GTK_OBJECT (widget));
1458
1459 /*
1460 * Can't use event->x / event->y here
1461 * because I need absolute coordinates.
1462 */
1463
1464 gdk_window_get_pointer (root_win, &xp, &yp, &mask);
1465 gtk_widget_set_uposition (widget, xp - p->x, yp - p->y);
1466
1467 if (gs_currentDropSource) gs_currentDropSource->GiveFeedback( wxDragCopy, FALSE );
1468 }
1469
1470 GtkWidget *
1471 shape_create_icon (const wxIcon &shape,
1472 gint x,
1473 gint y,
1474 gint px,
1475 gint py,
1476 gint window_type)
1477 {
1478 /*
1479 * GDK_WINDOW_TOPLEVEL works also, giving you a title border
1480 */
1481 GtkWidget *window = gtk_window_new ((GtkWindowType)window_type);
1482
1483 GtkWidget *fixed = gtk_fixed_new ();
1484 gtk_widget_set_usize (fixed, 100,100);
1485 gtk_container_add (GTK_CONTAINER (window), fixed);
1486 gtk_widget_show (fixed);
1487
1488 gtk_widget_set_events (window,
1489 gtk_widget_get_events (window) |
1490 GDK_BUTTON_MOTION_MASK |
1491 GDK_POINTER_MOTION_HINT_MASK |
1492 GDK_BUTTON_PRESS_MASK);
1493
1494 gtk_widget_realize (window);
1495
1496 GdkBitmap *mask = (GdkBitmap*) NULL;
1497 if (shape.GetMask()) mask = shape.GetMask()->GetBitmap();
1498
1499 GtkWidget *pixmap = gtk_pixmap_new (shape.GetPixmap(), mask);
1500 gtk_fixed_put (GTK_FIXED (fixed), pixmap, px,py);
1501 gtk_widget_show (pixmap);
1502
1503 gtk_widget_shape_combine_mask (window, mask, px,py);
1504
1505
1506 gtk_signal_connect (GTK_OBJECT (window), "button_press_event",
1507 GTK_SIGNAL_FUNC (shape_pressed),NULL);
1508 gtk_signal_connect (GTK_OBJECT (window), "button_release_event",
1509 GTK_SIGNAL_FUNC (shape_released),NULL);
1510 gtk_signal_connect (GTK_OBJECT (window), "motion_notify_event",
1511 GTK_SIGNAL_FUNC (shape_motion),NULL);
1512
1513 CursorOffset*icon_pos = g_new (CursorOffset, 1);
1514 gtk_object_set_user_data(GTK_OBJECT(window), icon_pos);
1515
1516 gtk_widget_set_uposition (window, x, y);
1517 gtk_widget_show (window);
1518
1519 return window;
1520 }
1521
1522 #endif
1523 // NEW_GTK_DND_CODE
1524
1525 #endif
1526
1527 // wxUSE_DRAG_AND_DROP