Chnaged text id for clipboard to "text/plain"
[wxWidgets.git] / src / gtk1 / 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 // "drag_leave"
133 // ----------------------------------------------------------------------------
134
135 static void target_drag_leave( GtkWidget *WXUNUSED(widget),
136 GdkDragContext *context,
137 guint WXUNUSED(time),
138 wxDropTarget *dt )
139 {
140 dt->SetDragContext( context );
141 dt->OnLeave();
142 dt->SetDragContext( (GdkDragContext*) NULL );
143 }
144
145 // ----------------------------------------------------------------------------
146 // "drag_motion"
147 // ----------------------------------------------------------------------------
148
149 static gboolean target_drag_motion( GtkWidget *WXUNUSED(widget),
150 GdkDragContext *context,
151 gint x,
152 gint y,
153 guint time,
154 wxDropTarget *dt )
155 {
156 dt->SetDragContext( context );
157
158 if (dt->OnMove( x, y ))
159 {
160 gdk_drag_status( context, context->suggested_action, time );
161 }
162 else
163 {
164 gdk_drag_status( context, (GdkDragAction)0, time );
165 }
166
167 dt->SetDragContext( (GdkDragContext*) NULL );
168 return TRUE;
169 }
170
171 // ----------------------------------------------------------------------------
172 // "drag_drop"
173 // ----------------------------------------------------------------------------
174
175 static gboolean target_drag_drop( GtkWidget *widget,
176 GdkDragContext *context,
177 gint x,
178 gint y,
179 guint time )
180 {
181 printf( "drop at: %d,%d.\n", x, y );
182
183 if (context->targets)
184 {
185 gtk_drag_get_data( widget,
186 context,
187 GPOINTER_TO_INT (context->targets->data),
188 time );
189 }
190 return FALSE;
191 }
192
193 // ----------------------------------------------------------------------------
194 // "drag_data_received"
195 // ----------------------------------------------------------------------------
196
197 static void target_drag_data_received( GtkWidget *WXUNUSED(widget),
198 GdkDragContext *context,
199 gint x,
200 gint y,
201 GtkSelectionData *data,
202 guint WXUNUSED(info),
203 guint time )
204 {
205 printf( "data receive at: %d,%d.\n", x, y );
206
207 if ((data->length >= 0) && (data->format == 8))
208 {
209 wxString str = (const char*)data->data;
210 printf( "Received %s\n.", WXSTRINGCAST str );
211 gtk_drag_finish( context, TRUE, FALSE, time );
212 return;
213 }
214
215 gtk_drag_finish (context, FALSE, FALSE, time);
216 }
217
218 // ----------------------------------------------------------------------------
219 // wxDropTarget
220 // ----------------------------------------------------------------------------
221
222 wxDropTarget::wxDropTarget()
223 {
224 }
225
226 wxDropTarget::~wxDropTarget()
227 {
228 }
229
230 void wxDropTarget::OnEnter()
231 {
232 }
233
234 void wxDropTarget::OnLeave()
235 {
236 }
237
238 bool wxDropTarget::OnMove( int x, int y )
239 {
240 printf( "generic move %d %d.\n", x, y );
241
242 return TRUE;
243 }
244
245 bool wxDropTarget::OnDrop( int x, int y )
246 {
247 printf( "generic drop %d %d.\n", x, y );
248
249 return TRUE;
250 }
251
252 bool wxDropTarget::IsSupported( wxDataFormat format )
253 {
254 printf( "generic is supported.\n" );
255
256 if (!m_dragContext) return FALSE;
257
258 GList *child = m_dragContext->targets;
259 while (child)
260 {
261 GdkAtom formatAtom = (GdkAtom) GPOINTER_TO_INT(child->data);
262 char *name = gdk_atom_name( formatAtom );
263 if (name) printf( "Format available: %s.\n", name );
264
265 child = child->next;
266 }
267
268
269 return TRUE;
270 }
271
272 bool wxDropTarget::GetData( wxDataObject *data )
273 {
274 return FALSE;
275 }
276
277 void wxDropTarget::UnregisterWidget( GtkWidget *widget )
278 {
279 wxCHECK_RET( widget != NULL, "unregister widget is NULL" );
280
281 gtk_drag_dest_set( widget,
282 (GtkDestDefaults) 0,
283 (GtkTargetEntry*) NULL,
284 0,
285 (GdkDragAction) 0 );
286
287 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
288 GTK_SIGNAL_FUNC(target_drag_leave), (gpointer) this );
289
290 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
291 GTK_SIGNAL_FUNC(target_drag_motion), (gpointer) this );
292
293 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
294 GTK_SIGNAL_FUNC(target_drag_drop), (gpointer) this );
295
296 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
297 GTK_SIGNAL_FUNC(target_drag_data_received), (gpointer) this );
298 }
299
300 void wxDropTarget::RegisterWidget( GtkWidget *widget )
301 {
302 wxCHECK_RET( widget != NULL, "register widget is NULL" );
303
304 GtkTargetEntry format;
305 format.info = 0;
306 format.flags = 0;
307 char buf[100];
308 strcpy( buf, "text/plain" );
309 format.target = buf;
310
311 gtk_drag_dest_set( widget,
312 GTK_DEST_DEFAULT_ALL,
313 &format,
314 1,
315 (GdkDragAction)(GDK_ACTION_COPY | GDK_ACTION_MOVE) );
316
317 gtk_signal_connect( GTK_OBJECT(widget), "drag_leave",
318 GTK_SIGNAL_FUNC(target_drag_leave), (gpointer) this );
319
320 gtk_signal_connect( GTK_OBJECT(widget), "drag_motion",
321 GTK_SIGNAL_FUNC(target_drag_motion), (gpointer) this );
322
323 gtk_signal_connect( GTK_OBJECT(widget), "drag_drop",
324 GTK_SIGNAL_FUNC(target_drag_drop), (gpointer) this );
325
326 gtk_signal_connect( GTK_OBJECT(widget), "drag_data_received",
327 GTK_SIGNAL_FUNC(target_drag_data_received), (gpointer) this );
328 }
329
330 //-------------------------------------------------------------------------
331 // wxTextDropTarget
332 //-------------------------------------------------------------------------
333
334 bool wxTextDropTarget::OnMove( int WXUNUSED(x), int WXUNUSED(y) )
335 {
336 printf( "text move.\n" );
337
338 return IsSupported( wxDF_TEXT ); // same as "TEXT"
339 }
340
341 bool wxTextDropTarget::OnDrop( int x, int y )
342 {
343 printf( "text drop.\n" );
344
345 if (!IsSupported( wxDF_TEXT )) return FALSE;
346
347 wxTextDataObject data;
348 if (!GetData( &data )) return FALSE;
349
350 return OnDropText( x, y, data.GetText() );
351 }
352
353 //-------------------------------------------------------------------------
354 // wxPrivateDropTarget
355 //-------------------------------------------------------------------------
356
357 wxPrivateDropTarget::wxPrivateDropTarget()
358 {
359 m_id = wxTheApp->GetAppName();
360 }
361
362 wxPrivateDropTarget::wxPrivateDropTarget( const wxString &id )
363 {
364 m_id = id;
365 }
366
367 bool wxPrivateDropTarget::OnMove( int WXUNUSED(x), int WXUNUSED(y) )
368 {
369 return IsSupported( m_id );
370 }
371
372 bool wxPrivateDropTarget::OnDrop( int x, int y )
373 {
374 if (!IsSupported( m_id )) return FALSE;
375
376 wxPrivateDataObject data;
377 if (!GetData( &data )) return FALSE;
378
379 return OnDropData( x, y, data.GetData(), data.GetSize() );
380 }
381
382 //----------------------------------------------------------------------------
383 // A drop target which accepts files (dragged from File Manager or Explorer)
384 //----------------------------------------------------------------------------
385
386 bool wxFileDropTarget::OnMove( int WXUNUSED(x), int WXUNUSED(y) )
387 {
388 return IsSupported( wxDF_FILENAME ); // same as "file:ALL"
389 }
390
391 bool wxFileDropTarget::OnDrop( int x, int y )
392 {
393 if (!IsSupported( wxDF_FILENAME )) return FALSE;
394
395 wxFileDataObject data;
396 if (!GetData( &data )) return FALSE;
397
398 /* get number of substrings /root/mytext.txt/0/root/myothertext.txt/0/0 */
399 size_t number = 0;
400 size_t i;
401 size_t size = data.GetFiles().Length();
402 char *text = WXSTRINGCAST data.GetFiles();
403 for ( i = 0; i < size; i++)
404 if (text[i] == 0) number++;
405
406 if (number == 0) return TRUE;
407
408 char **files = new char*[number];
409
410 text = WXSTRINGCAST data.GetFiles();
411 for (i = 0; i < number; i++)
412 {
413 files[i] = text;
414 int len = strlen( text );
415 text += len+1;
416 }
417
418 bool ret = OnDropFiles( x, y, number, files );
419
420 free( files );
421
422 return ret;
423 }
424
425 //-------------------------------------------------------------------------
426 // wxDropSource
427 //-------------------------------------------------------------------------
428
429
430 wxDropSource::wxDropSource( wxWindow *win, const wxIcon &go, const wxIcon &stop )
431 {
432 g_blockEventsOnDrag = TRUE;
433
434 m_window = win;
435 m_widget = win->m_widget;
436 if (win->m_wxwindow) m_widget = win->m_wxwindow;
437
438 m_data = (wxDataBroker*) NULL;
439 m_retValue = wxDragCancel;
440
441 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
442 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
443
444 m_goIcon = go;
445 if (wxNullIcon == go) m_goIcon = wxIcon( page_xpm );
446 m_stopIcon = stop;
447 if (wxNullIcon == stop) m_stopIcon = wxIcon( gv_xpm );
448 }
449
450 wxDropSource::wxDropSource( wxDataObject *data, wxWindow *win, const wxIcon &go, const wxIcon &stop )
451 {
452 g_blockEventsOnDrag = TRUE;
453
454 m_window = win;
455 m_widget = win->m_widget;
456 if (win->m_wxwindow) m_widget = win->m_wxwindow;
457 m_retValue = wxDragCancel;
458
459 if (data)
460 {
461 m_data = new wxDataBroker();
462 m_data->Add( data );
463 }
464 else
465 {
466 m_data = (wxDataBroker*) NULL;
467 }
468
469 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
470 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
471
472 m_goIcon = go;
473 if (wxNullIcon == go) m_goIcon = wxIcon( page_xpm );
474 m_stopIcon = stop;
475 if (wxNullIcon == stop) m_stopIcon = wxIcon( gv_xpm );
476 }
477
478 wxDropSource::wxDropSource( wxDataBroker *data, wxWindow *win )
479 {
480 g_blockEventsOnDrag = TRUE;
481
482 m_window = win;
483 m_widget = win->m_widget;
484 if (win->m_wxwindow) m_widget = win->m_wxwindow;
485 m_retValue = wxDragCancel;
486
487 m_data = data;
488
489 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
490 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
491 }
492
493 void wxDropSource::SetData( wxDataObject *data )
494 {
495 if (m_data) delete m_data;
496
497 if (data)
498 {
499 m_data = new wxDataBroker();
500 m_data->Add( data );
501 }
502 else
503 {
504 m_data = (wxDataBroker*) NULL;
505 }
506 }
507
508 void wxDropSource::SetData( wxDataBroker *data )
509 {
510 if (m_data) delete m_data;
511
512 m_data = data;
513 }
514
515 wxDropSource::~wxDropSource(void)
516 {
517 if (m_data) delete m_data;
518
519 g_blockEventsOnDrag = FALSE;
520 }
521
522 wxDragResult wxDropSource::DoDragDrop( bool WXUNUSED(bAllowMove) )
523 {
524 wxASSERT_MSG( m_data, "wxDragSource: no data" );
525
526 if (!m_data) return (wxDragResult) wxDragNone;
527
528 static GtkWidget *drag_icon = (GtkWidget*) NULL;
529 static GtkWidget *drop_icon = (GtkWidget*) NULL;
530
531 GdkPoint hotspot_1 = {0,-5 };
532
533 if (!drag_icon)
534 {
535 /*
536 drag_icon = shape_create_icon ( m_stopIcon,
537 440, 140, 0,0, GTK_WINDOW_POPUP);
538
539 gtk_signal_connect (GTK_OBJECT (drag_icon), "destroy",
540 GTK_SIGNAL_FUNC(gtk_widget_destroyed),
541 &drag_icon);
542
543 gtk_widget_hide (drag_icon);
544 */
545 }
546
547 GdkPoint hotspot_2 = {-5,-5};
548
549 if (!drop_icon)
550 {
551 /*
552 drop_icon = shape_create_icon ( m_goIcon,
553 440, 140, 0,0, GTK_WINDOW_POPUP);
554
555 gtk_signal_connect (GTK_OBJECT (drop_icon), "destroy",
556 GTK_SIGNAL_FUNC(gtk_widget_destroyed),
557 &drop_icon);
558
559 gtk_widget_hide (drop_icon);
560 */
561 }
562
563
564 return FALSE;
565 }
566
567 void wxDropSource::RegisterWindow(void)
568 {
569 if (!m_data) return;
570 }
571
572 void wxDropSource::UnregisterWindow(void)
573 {
574 if (!m_widget) return;
575 }
576
577
578 #else // NEW_CODE
579
580 //----------------------------------------------------------------------------
581 // forward
582 //----------------------------------------------------------------------------
583
584 GtkWidget *shape_create_icon ( const wxIcon &shape,
585 gint x,
586 gint y,
587 gint px,
588 gint py,
589 gint window_type);
590
591 //-----------------------------------------------------------------------------
592 // globals
593 //-----------------------------------------------------------------------------
594
595 wxDropSource *gs_currentDropSource = (wxDropSource*) NULL;
596
597 //-----------------------------------------------------------------------------
598 // "drop_enter_event"
599 //-----------------------------------------------------------------------------
600
601 static void gtk_target_enter_callback( GtkWidget *WXUNUSED(widget),
602 GdkEventDropEnter *WXUNUSED(event),
603 wxDropTarget *target )
604 {
605 if (target)
606 target->OnEnter();
607 }
608
609 //-----------------------------------------------------------------------------
610 // "drop_leave_event"
611 //-----------------------------------------------------------------------------
612
613 static void gtk_target_leave_callback( GtkWidget *WXUNUSED(widget),
614 GdkEventDropLeave *WXUNUSED(event),
615 wxDropTarget *target )
616 {
617 if (target)
618 target->OnLeave();
619 }
620
621 //-----------------------------------------------------------------------------
622 // "drop_data_available_event"
623 //-----------------------------------------------------------------------------
624
625 static void gtk_target_callback( GtkWidget *widget,
626 GdkEventDropDataAvailable *event,
627 wxDropTarget *target )
628 {
629 if (target)
630 {
631 int x = 0;
632 int y = 0;
633 gdk_window_get_pointer( widget->window, &x, &y, (GdkModifierType *) NULL );
634 /*
635 printf( "Drop data is of type %s.\n", event->data_type );
636 */
637 target->OnDrop( x, y, (const void*)event->data, (size_t)event->data_numbytes );
638 }
639
640 /*
641 g_free (event->data);
642 g_free (event->data_type);
643 */
644 }
645
646 // ----------------------------------------------------------------------------
647 // wxDropTarget
648 // ----------------------------------------------------------------------------
649
650 wxDropTarget::wxDropTarget()
651 {
652 m_format = (wxDataFormat*) NULL;
653 }
654
655 wxDropTarget::~wxDropTarget()
656 {
657 if (m_format) delete m_format;
658 }
659
660 wxDataFormat &wxDropTarget::GetFormat(size_t n) const
661 {
662 return (*m_format);
663 }
664
665 void wxDropTarget::UnregisterWidget( GtkWidget *widget )
666 {
667 if (!widget) return;
668
669 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
670 GTK_SIGNAL_FUNC(gtk_target_callback), (gpointer) this );
671
672 gtk_widget_dnd_drop_set( widget, FALSE, (gchar **) NULL, 0, FALSE );
673 }
674
675 void wxDropTarget::RegisterWidget( GtkWidget *widget )
676 {
677 wxString formats;
678 int valid = 0;
679
680 for ( size_t i = 0; i < GetFormatCount(); i++ )
681 {
682 switch (GetFormat(i).GetType())
683 {
684 case wxDF_TEXT:
685 {
686 if (i > 0) formats += ";";
687 formats += "text/plain";
688 valid++;
689 break;
690 }
691 case wxDF_FILENAME:
692 {
693 if (i > 0) formats += ";";
694 formats += "file:ALL";
695 valid++;
696 break;
697 }
698 case wxDF_PRIVATE:
699 {
700 if (i > 0) formats += ";";
701 wxPrivateDropTarget *pdt = (wxPrivateDropTarget *)this;
702 formats += pdt->GetId();
703 valid++;
704 break;
705 }
706 default:
707 break;
708 }
709 }
710
711 char *str = WXSTRINGCAST formats;
712
713 gtk_widget_dnd_drop_set( widget, TRUE, &str, valid, FALSE );
714
715 gtk_signal_connect( GTK_OBJECT(widget), "drop_data_available_event",
716 GTK_SIGNAL_FUNC(gtk_target_callback), (gpointer) this );
717
718 gtk_signal_connect( GTK_OBJECT(widget), "drop_enter_event",
719 GTK_SIGNAL_FUNC(gtk_target_enter_callback), (gpointer) this );
720
721 gtk_signal_connect( GTK_OBJECT(widget), "drop_leave_event",
722 GTK_SIGNAL_FUNC(gtk_target_leave_callback), (gpointer) this );
723 }
724
725 // ----------------------------------------------------------------------------
726 // wxTextDropTarget
727 // ----------------------------------------------------------------------------
728
729 wxTextDropTarget::wxTextDropTarget()
730 {
731 m_format = new wxDataFormat( wxDF_TEXT );
732 }
733
734 bool wxTextDropTarget::OnDrop( long x, long y, const void *data, size_t WXUNUSED(size) )
735 {
736 OnDropText( x, y, (const char*)data );
737 return TRUE;
738 }
739
740 bool wxTextDropTarget::OnDropText( long x, long y, const char *psz )
741 {
742 /*
743 printf( "Got dropped text: %s.\n", psz );
744 printf( "At x: %d, y: %d.\n", (int)x, (int)y );
745 */
746 return TRUE;
747 }
748
749 size_t wxTextDropTarget::GetFormatCount() const
750 {
751 return 1;
752 }
753
754 // ----------------------------------------------------------------------------
755 // wxPrivateDropTarget
756 // ----------------------------------------------------------------------------
757
758 wxPrivateDropTarget::wxPrivateDropTarget()
759 {
760 m_id = wxTheApp->GetAppName();
761 m_format = new wxDataFormat( m_id );
762 }
763
764 void wxPrivateDropTarget::SetId( const wxString& id )
765 {
766 m_id = id;
767 m_format->SetId( id );
768 }
769
770 size_t wxPrivateDropTarget::GetFormatCount() const
771 {
772 return 1;
773 }
774
775 // ----------------------------------------------------------------------------
776 // wxFileDropTarget
777 // ----------------------------------------------------------------------------
778
779 wxFileDropTarget::wxFileDropTarget()
780 {
781 m_format = new wxDataFormat( wxDF_FILENAME );
782 }
783
784 bool wxFileDropTarget::OnDropFiles( long x, long y, size_t nFiles, const char * const aszFiles[] )
785 {
786 printf( "Got %d dropped files.\n", (int)nFiles );
787 printf( "At x: %d, y: %d.\n", (int)x, (int)y );
788
789 for (size_t i = 0; i < nFiles; i++)
790 {
791 printf( aszFiles[i] );
792 printf( "\n" );
793 }
794
795 return TRUE;
796 }
797
798 bool wxFileDropTarget::OnDrop(long x, long y, const void *data, size_t size )
799 {
800 size_t number = 0;
801 size_t i;
802 char *text = (char*) data;
803 for ( i = 0; i < size; i++)
804 if (text[i] == 0) number++;
805
806 if (number == 0) return TRUE;
807
808 char **files = new char*[number];
809
810 text = (char*) data;
811 for (i = 0; i < number; i++)
812 {
813 files[i] = text;
814 int len = strlen( text );
815 text += len+1;
816 }
817
818 bool ret = OnDropFiles( x, y, 1, files );
819
820 free( files );
821
822 return ret;
823 }
824
825 size_t wxFileDropTarget::GetFormatCount() const
826 {
827 return 1;
828 }
829
830 //-------------------------------------------------------------------------
831 // wxDropSource
832 //-------------------------------------------------------------------------
833
834 static void
835 shape_motion (GtkWidget *widget,
836 GdkEventMotion * /*event*/);
837
838 //-----------------------------------------------------------------------------
839 // "drag_request_event"
840 //-----------------------------------------------------------------------------
841
842 void gtk_drag_callback( GtkWidget *widget, GdkEventDragRequest *event, wxDropSource *source )
843 {
844 wxDataBroker *data = source->m_data;
845
846 if (!data) return;
847
848 wxNode *node = data->m_dataObjects.First();
849 {
850 wxDataObject *dobj = (wxDataObject*) node->Data();
851
852 if ((strcmp(event->data_type,"file:ALL") == 0) &&
853 (dobj->GetFormat().GetType() == wxDF_FILENAME))
854 {
855 wxFileDataObject *file_object = (wxFileDataObject*) dobj;
856
857 wxString text = file_object->GetFiles();
858
859 char *s = WXSTRINGCAST text;
860
861 gtk_widget_dnd_data_set( widget,
862 (GdkEvent*)event,
863 (unsigned char*) s,
864 (int) text.Length()+1 );
865
866 source->m_retValue = wxDragCopy;
867
868 return;
869 }
870
871 if ((strcmp(event->data_type,"text/plain") == 0) &&
872 (dobj->GetFormat().GetType() == wxDF_TEXT))
873 {
874 wxTextDataObject *text_object = (wxTextDataObject*) dobj;
875
876 wxString text = text_object->GetText();
877
878 char *s = WXSTRINGCAST text;
879
880 gtk_widget_dnd_data_set( widget,
881 (GdkEvent*)event,
882 (unsigned char*) s,
883 (int) text.Length()+1 );
884
885 source->m_retValue = wxDragCopy;
886
887 return;
888 }
889
890 if (dobj->GetFormat().GetType() == wxDF_PRIVATE)
891 {
892 wxPrivateDataObject *pdo = (wxPrivateDataObject*) dobj;
893
894 if (pdo->GetId() == event->data_type)
895 {
896 gtk_widget_dnd_data_set( widget,
897 (GdkEvent*)event,
898 (unsigned char*) pdo->GetData(),
899 (int) pdo->GetSize() );
900
901 source->m_retValue = wxDragCopy;
902
903 return;
904 }
905 }
906
907 node = node->Next();
908 }
909 }
910
911 wxDropSource::wxDropSource( wxWindow *win, const wxIcon &go, const wxIcon &stop )
912 {
913 g_blockEventsOnDrag = TRUE;
914
915 m_window = win;
916 m_widget = win->m_widget;
917 if (win->m_wxwindow) m_widget = win->m_wxwindow;
918
919 m_data = (wxDataBroker*) NULL;
920 m_retValue = wxDragCancel;
921
922 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
923 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
924
925 m_goIcon = go;
926 if (wxNullIcon == go) m_goIcon = wxIcon( page_xpm );
927 m_stopIcon = stop;
928 if (wxNullIcon == stop) m_stopIcon = wxIcon( gv_xpm );
929 }
930
931 wxDropSource::wxDropSource( wxDataObject *data, wxWindow *win, const wxIcon &go, const wxIcon &stop )
932 {
933 g_blockEventsOnDrag = TRUE;
934
935 m_window = win;
936 m_widget = win->m_widget;
937 if (win->m_wxwindow) m_widget = win->m_wxwindow;
938 m_retValue = wxDragCancel;
939
940 if (data)
941 {
942 m_data = new wxDataBroker();
943 m_data->Add( data );
944 }
945 else
946 {
947 m_data = (wxDataBroker*) NULL;
948 }
949
950 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
951 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
952
953 m_goIcon = go;
954 if (wxNullIcon == go) m_goIcon = wxIcon( page_xpm );
955 m_stopIcon = stop;
956 if (wxNullIcon == stop) m_stopIcon = wxIcon( gv_xpm );
957 }
958
959 wxDropSource::wxDropSource( wxDataBroker *data, wxWindow *win )
960 {
961 g_blockEventsOnDrag = TRUE;
962
963 m_window = win;
964 m_widget = win->m_widget;
965 if (win->m_wxwindow) m_widget = win->m_wxwindow;
966 m_retValue = wxDragCancel;
967
968 m_data = data;
969
970 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
971 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
972 }
973
974 void wxDropSource::SetData( wxDataObject *data )
975 {
976 if (m_data) delete m_data;
977
978 if (data)
979 {
980 m_data = new wxDataBroker();
981 m_data->Add( data );
982 }
983 else
984 {
985 m_data = (wxDataBroker*) NULL;
986 }
987 }
988
989 void wxDropSource::SetData( wxDataBroker *data )
990 {
991 if (m_data) delete m_data;
992
993 m_data = data;
994 }
995
996 wxDropSource::~wxDropSource(void)
997 {
998 if (m_data) delete m_data;
999
1000 g_blockEventsOnDrag = FALSE;
1001 }
1002
1003 wxDragResult wxDropSource::DoDragDrop( bool WXUNUSED(bAllowMove) )
1004 {
1005 if (gdk_dnd.dnd_grabbed) return (wxDragResult) wxDragNone;
1006 if (gdk_dnd.drag_really) return (wxDragResult) wxDragNone;
1007
1008 wxASSERT_MSG( m_data, "wxDragSource: no data" );
1009
1010 if (!m_data) return (wxDragResult) wxDragNone;
1011
1012 static GtkWidget *drag_icon = (GtkWidget*) NULL;
1013 static GtkWidget *drop_icon = (GtkWidget*) NULL;
1014
1015 GdkPoint hotspot_1 = {0,-5 };
1016
1017 if (!drag_icon)
1018 {
1019 drag_icon = shape_create_icon ( m_stopIcon,
1020 440, 140, 0,0, GTK_WINDOW_POPUP);
1021
1022 gtk_signal_connect (GTK_OBJECT (drag_icon), "destroy",
1023 GTK_SIGNAL_FUNC(gtk_widget_destroyed),
1024 &drag_icon);
1025
1026 gtk_widget_hide (drag_icon);
1027 }
1028
1029 GdkPoint hotspot_2 = {-5,-5};
1030
1031 if (!drop_icon)
1032 {
1033 drop_icon = shape_create_icon ( m_goIcon,
1034 440, 140, 0,0, GTK_WINDOW_POPUP);
1035
1036 gtk_signal_connect (GTK_OBJECT (drop_icon), "destroy",
1037 GTK_SIGNAL_FUNC(gtk_widget_destroyed),
1038 &drop_icon);
1039
1040 gtk_widget_hide (drop_icon);
1041 }
1042
1043
1044 gdk_dnd_set_drag_shape( drag_icon->window,
1045 &hotspot_1,
1046 drop_icon->window,
1047 &hotspot_2);
1048
1049
1050 GdkWindowPrivate *wp = (GdkWindowPrivate*) m_widget->window;
1051
1052 RegisterWindow();
1053
1054 gdk_dnd.drag_perhaps = TRUE;
1055
1056 gdk_dnd.dnd_drag_start.x = 5;
1057 gdk_dnd.dnd_drag_start.y = 5;
1058 gdk_dnd.real_sw = wp;
1059
1060 if (gdk_dnd.drag_startwindows)
1061 {
1062 g_free( gdk_dnd.drag_startwindows );
1063 gdk_dnd.drag_startwindows = (GdkWindow **) NULL;
1064 }
1065 gdk_dnd.drag_numwindows = gdk_dnd.drag_really = 0;
1066
1067 XWindowAttributes dnd_winattr;
1068 XGetWindowAttributes( gdk_display, wp->xwindow, &dnd_winattr );
1069 wp->dnd_drag_savedeventmask = dnd_winattr.your_event_mask;
1070
1071 gdk_dnd_drag_addwindow( m_widget->window );
1072
1073 GdkEventDragBegin ev;
1074 ev.type = GDK_DRAG_BEGIN;
1075 ev.window = m_widget->window;
1076 ev.u.allflags = 0;
1077 ev.u.flags.protocol_version = DND_PROTOCOL_VERSION;
1078
1079 gdk_event_put( (GdkEvent*)&ev );
1080
1081 XGrabPointer( gdk_display, wp->xwindow, False,
1082 ButtonMotionMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
1083 GrabModeAsync, GrabModeAsync, gdk_root_window, None, CurrentTime );
1084
1085 gdk_dnd_set_drag_cursors( m_defaultCursor.GetCursor(), m_goaheadCursor.GetCursor() );
1086
1087 gdk_dnd.dnd_grabbed = TRUE;
1088 gdk_dnd.drag_really = 1;
1089
1090 int x = 0;
1091 int y = 0;
1092 wxGetMousePosition( &x, &y );
1093
1094 gdk_dnd_display_drag_cursor( x, y, FALSE, TRUE );
1095
1096 gs_currentDropSource = this;
1097
1098 while (gdk_dnd.drag_really || gdk_dnd.drag_perhaps) wxYield();
1099
1100 gs_currentDropSource = (wxDropSource*) NULL;
1101
1102 UnregisterWindow();
1103
1104 g_blockEventsOnDrag = FALSE;
1105
1106 return m_retValue;
1107 }
1108
1109 void wxDropSource::RegisterWindow(void)
1110 {
1111 if (!m_data) return;
1112
1113 wxString formats;
1114
1115 wxNode *node = m_data->m_dataObjects.First();
1116 while (node)
1117 {
1118 wxDataObject* dobj = (wxDataObject*) node->Data();
1119
1120 switch (dobj->GetFormat().GetType())
1121 {
1122 case wxDF_TEXT:
1123 {
1124 formats += "text/plain";
1125 break;
1126 }
1127 case wxDF_FILENAME:
1128 {
1129 formats += "file:ALL";
1130 break;
1131 }
1132 case wxDF_PRIVATE:
1133 {
1134 wxPrivateDataObject* pdo = (wxPrivateDataObject*) m_data;
1135 formats += pdo->GetId();
1136 break;
1137 }
1138 default:
1139 break;
1140 }
1141 node = node->Next();
1142 }
1143
1144 char *str = WXSTRINGCAST formats;
1145
1146 gtk_widget_dnd_drag_set( m_widget, TRUE, &str, 1 );
1147
1148 gtk_signal_connect( GTK_OBJECT(m_widget), "drag_request_event",
1149 GTK_SIGNAL_FUNC(gtk_drag_callback), (gpointer)this );
1150 }
1151
1152 void wxDropSource::UnregisterWindow(void)
1153 {
1154 if (!m_widget) return;
1155
1156 gtk_widget_dnd_drag_set( m_widget, FALSE, (gchar **) NULL, 0 );
1157
1158 gtk_signal_disconnect_by_data( GTK_OBJECT(m_widget), (gpointer)this );
1159 }
1160
1161
1162 /*
1163 * Shaped Windows
1164 */
1165 static GdkWindow *root_win = (GdkWindow*) NULL;
1166
1167 typedef struct _cursoroffset {gint x,y;} CursorOffset;
1168
1169 static void
1170 shape_pressed (GtkWidget *widget, GdkEventButton *event)
1171 {
1172 CursorOffset *p;
1173
1174 /* ignore double and triple click */
1175 if (event->type != GDK_BUTTON_PRESS)
1176 return;
1177
1178 p = (CursorOffset *)gtk_object_get_user_data (GTK_OBJECT(widget));
1179 p->x = (int) event->x;
1180 p->y = (int) event->y;
1181
1182 gtk_grab_add (widget);
1183 gdk_pointer_grab (widget->window, TRUE,
1184 (GdkEventMask)
1185 (GDK_BUTTON_RELEASE_MASK |
1186 GDK_BUTTON_MOTION_MASK |
1187 GDK_POINTER_MOTION_HINT_MASK),
1188 (GdkWindow*)NULL,
1189 (GdkCursor*) NULL, 0);
1190 }
1191
1192
1193 static void
1194 shape_released (GtkWidget *widget)
1195 {
1196 gtk_grab_remove (widget);
1197 gdk_pointer_ungrab (0);
1198 }
1199
1200 static void
1201 shape_motion (GtkWidget *widget,
1202 GdkEventMotion * /*event*/ )
1203 {
1204 gint xp, yp;
1205 CursorOffset * p;
1206 GdkModifierType mask;
1207
1208 p = (CursorOffset *)gtk_object_get_user_data (GTK_OBJECT (widget));
1209
1210 /*
1211 * Can't use event->x / event->y here
1212 * because I need absolute coordinates.
1213 */
1214
1215 gdk_window_get_pointer (root_win, &xp, &yp, &mask);
1216 gtk_widget_set_uposition (widget, xp - p->x, yp - p->y);
1217
1218 if (gs_currentDropSource) gs_currentDropSource->GiveFeedback( wxDragCopy, FALSE );
1219 }
1220
1221 GtkWidget *
1222 shape_create_icon (const wxIcon &shape,
1223 gint x,
1224 gint y,
1225 gint px,
1226 gint py,
1227 gint window_type)
1228 {
1229 /*
1230 * GDK_WINDOW_TOPLEVEL works also, giving you a title border
1231 */
1232 GtkWidget *window = gtk_window_new ((GtkWindowType)window_type);
1233
1234 GtkWidget *fixed = gtk_fixed_new ();
1235 gtk_widget_set_usize (fixed, 100,100);
1236 gtk_container_add (GTK_CONTAINER (window), fixed);
1237 gtk_widget_show (fixed);
1238
1239 gtk_widget_set_events (window,
1240 gtk_widget_get_events (window) |
1241 GDK_BUTTON_MOTION_MASK |
1242 GDK_POINTER_MOTION_HINT_MASK |
1243 GDK_BUTTON_PRESS_MASK);
1244
1245 gtk_widget_realize (window);
1246
1247 GdkBitmap *mask = (GdkBitmap*) NULL;
1248 if (shape.GetMask()) mask = shape.GetMask()->GetBitmap();
1249
1250 GtkWidget *pixmap = gtk_pixmap_new (shape.GetPixmap(), mask);
1251 gtk_fixed_put (GTK_FIXED (fixed), pixmap, px,py);
1252 gtk_widget_show (pixmap);
1253
1254 gtk_widget_shape_combine_mask (window, mask, px,py);
1255
1256
1257 gtk_signal_connect (GTK_OBJECT (window), "button_press_event",
1258 GTK_SIGNAL_FUNC (shape_pressed),NULL);
1259 gtk_signal_connect (GTK_OBJECT (window), "button_release_event",
1260 GTK_SIGNAL_FUNC (shape_released),NULL);
1261 gtk_signal_connect (GTK_OBJECT (window), "motion_notify_event",
1262 GTK_SIGNAL_FUNC (shape_motion),NULL);
1263
1264 CursorOffset*icon_pos = g_new (CursorOffset, 1);
1265 gtk_object_set_user_data(GTK_OBJECT(window), icon_pos);
1266
1267 gtk_widget_set_uposition (window, x, y);
1268 gtk_widget_show (window);
1269
1270 return window;
1271 }
1272
1273 #endif
1274 // NEW_GTK_DND_CODE
1275
1276 #endif
1277
1278 // wxUSE_DRAG_AND_DROP