]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/gtk/dnd.cpp
Menu/toolbar event handling now tries the window with the focus first.
[wxWidgets.git] / src / gtk / dnd.cpp
... / ...
CommitLineData
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
34extern bool g_blockEventsOnDrag;
35
36//----------------------------------------------------------------------------
37// standard icons
38//----------------------------------------------------------------------------
39
40/* XPM */
41static 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 */
82static 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
135static 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
149static 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
175static 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
197static 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
222wxDropTarget::wxDropTarget()
223{
224}
225
226wxDropTarget::~wxDropTarget()
227{
228}
229
230void wxDropTarget::OnEnter()
231{
232}
233
234void wxDropTarget::OnLeave()
235{
236}
237
238bool wxDropTarget::OnMove( int x, int y )
239{
240 printf( "generic move %d %d.\n", x, y );
241
242 return TRUE;
243}
244
245bool wxDropTarget::OnDrop( int x, int y )
246{
247 printf( "generic drop %d %d.\n", x, y );
248
249 return TRUE;
250}
251
252bool 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
272bool wxDropTarget::GetData( wxDataObject *data )
273{
274 return FALSE;
275}
276
277void 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
300void 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
334bool 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
341bool 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
357wxPrivateDropTarget::wxPrivateDropTarget()
358{
359 m_id = wxTheApp->GetAppName();
360}
361
362wxPrivateDropTarget::wxPrivateDropTarget( const wxString &id )
363{
364 m_id = id;
365}
366
367bool wxPrivateDropTarget::OnMove( int WXUNUSED(x), int WXUNUSED(y) )
368{
369 return IsSupported( m_id );
370}
371
372bool 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
386bool wxFileDropTarget::OnMove( int WXUNUSED(x), int WXUNUSED(y) )
387{
388 return IsSupported( wxDF_FILENAME ); // same as "file:ALL"
389}
390
391bool 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
430wxDropSource::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
450wxDropSource::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
478wxDropSource::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
493void 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
508void wxDropSource::SetData( wxDataBroker *data )
509{
510 if (m_data) delete m_data;
511
512 m_data = data;
513}
514
515wxDropSource::~wxDropSource(void)
516{
517 if (m_data) delete m_data;
518
519 g_blockEventsOnDrag = FALSE;
520}
521
522wxDragResult 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
567void wxDropSource::RegisterWindow(void)
568{
569 if (!m_data) return;
570}
571
572void wxDropSource::UnregisterWindow(void)
573{
574 if (!m_widget) return;
575}
576
577
578#else // NEW_CODE
579
580//----------------------------------------------------------------------------
581// forward
582//----------------------------------------------------------------------------
583
584GtkWidget *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
595wxDropSource *gs_currentDropSource = (wxDropSource*) NULL;
596
597//-----------------------------------------------------------------------------
598// "drop_enter_event"
599//-----------------------------------------------------------------------------
600
601static 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
613static 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
625static 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
650wxDropTarget::wxDropTarget()
651{
652 m_format = (wxDataFormat*) NULL;
653}
654
655wxDropTarget::~wxDropTarget()
656{
657 if (m_format) delete m_format;
658}
659
660wxDataFormat &wxDropTarget::GetFormat(size_t n) const
661{
662 return (*m_format);
663}
664
665void 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
675void 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
729wxTextDropTarget::wxTextDropTarget()
730{
731 m_format = new wxDataFormat( wxDF_TEXT );
732}
733
734bool 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
740bool 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
749size_t wxTextDropTarget::GetFormatCount() const
750{
751 return 1;
752}
753
754// ----------------------------------------------------------------------------
755// wxPrivateDropTarget
756// ----------------------------------------------------------------------------
757
758wxPrivateDropTarget::wxPrivateDropTarget()
759{
760 m_id = wxTheApp->GetAppName();
761 m_format = new wxDataFormat( m_id );
762}
763
764void wxPrivateDropTarget::SetId( const wxString& id )
765{
766 m_id = id;
767 m_format->SetId( id );
768}
769
770size_t wxPrivateDropTarget::GetFormatCount() const
771{
772 return 1;
773}
774
775// ----------------------------------------------------------------------------
776// wxFileDropTarget
777// ----------------------------------------------------------------------------
778
779wxFileDropTarget::wxFileDropTarget()
780{
781 m_format = new wxDataFormat( wxDF_FILENAME );
782}
783
784bool 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
798bool 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
825size_t wxFileDropTarget::GetFormatCount() const
826{
827 return 1;
828}
829
830//-------------------------------------------------------------------------
831// wxDropSource
832//-------------------------------------------------------------------------
833
834static void
835shape_motion (GtkWidget *widget,
836 GdkEventMotion * /*event*/);
837
838//-----------------------------------------------------------------------------
839// "drag_request_event"
840//-----------------------------------------------------------------------------
841
842void 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
911wxDropSource::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
931wxDropSource::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
959wxDropSource::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
974void 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
989void wxDropSource::SetData( wxDataBroker *data )
990{
991 if (m_data) delete m_data;
992
993 m_data = data;
994}
995
996wxDropSource::~wxDropSource(void)
997{
998 if (m_data) delete m_data;
999
1000 g_blockEventsOnDrag = FALSE;
1001}
1002
1003wxDragResult 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
1109void 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
1152void 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 */
1165static GdkWindow *root_win = (GdkWindow*) NULL;
1166
1167typedef struct _cursoroffset {gint x,y;} CursorOffset;
1168
1169static void
1170shape_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
1193static void
1194shape_released (GtkWidget *widget)
1195{
1196 gtk_grab_remove (widget);
1197 gdk_pointer_ungrab (0);
1198}
1199
1200static void
1201shape_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
1221GtkWidget *
1222shape_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