Changed clipboard text format id from "STRING" to "TEXT"
[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
32 // ----------------------------------------------------------------------------
33
34 extern bool g_blockEventsOnDrag;
35
36 #if (GTK_MINOR_VERSION > 0)
37
38 #include "gtk/gtkdnd.h"
39 #include "gtk/gtkselection.h"
40
41 // ----------------------------------------------------------------------------
42 // "drag_leave"
43 // ----------------------------------------------------------------------------
44
45 static void target_drag_leave( GtkWidget *WXUNUSED(widget),
46 GdkDragContext *context,
47 guint WXUNUSED(time),
48 wxDropTarget *dt )
49 {
50 dt->SetDragContext( context );
51 dt->OnLeave();
52 dt->SetDragContext( (GdkDragContext*) NULL );
53 }
54
55 // ----------------------------------------------------------------------------
56 // "drag_motion"
57 // ----------------------------------------------------------------------------
58
59 static gboolean target_drag_motion( GtkWidget *WXUNUSED(widget),
60 GdkDragContext *context,
61 gint x,
62 gint y,
63 guint time,
64 wxDropTarget *dt )
65 {
66 dt->SetDragContext( context );
67
68 if (dt->OnMove( x, y ))
69 {
70 gdk_drag_status( context, context->suggested_action, time );
71 }
72 else
73 {
74 gdk_drag_status( context, (GdkDragAction)0, time );
75 }
76
77 dt->SetDragContext( (GdkDragContext*) NULL );
78 return TRUE;
79 }
80
81 // ----------------------------------------------------------------------------
82 // "drag_drop"
83 // ----------------------------------------------------------------------------
84
85 static gboolean target_drag_drop( GtkWidget *widget,
86 GdkDragContext *context,
87 gint x,
88 gint y,
89 guint time )
90 {
91 printf( "drop at: %d,%d.\n", x, y );
92
93 if (context->targets)
94 {
95 gtk_drag_get_data( widget,
96 context,
97 GPOINTER_TO_INT (context->targets->data),
98 time );
99 }
100 return FALSE;
101 }
102
103 // ----------------------------------------------------------------------------
104 // "drag_data_received"
105 // ----------------------------------------------------------------------------
106
107 static void target_drag_data_received( GtkWidget *WXUNUSED(widget),
108 GdkDragContext *context,
109 gint x,
110 gint y,
111 GtkSelectionData *data,
112 guint WXUNUSED(info),
113 guint time )
114 {
115 printf( "data receive at: %d,%d.\n", x, y );
116
117 if ((data->length >= 0) && (data->format == 8))
118 {
119 wxString str = (const char*)data->data;
120 printf( "Received %s\n.", WXSTRINGCAST str );
121 gtk_drag_finish( context, TRUE, FALSE, time );
122 return;
123 }
124
125 gtk_drag_finish (context, FALSE, FALSE, time);
126 }
127
128 // ----------------------------------------------------------------------------
129 // wxDropTarget
130 // ----------------------------------------------------------------------------
131
132 wxDropTarget::wxDropTarget()
133 {
134 }
135
136 wxDropTarget::~wxDropTarget()
137 {
138 }
139
140 void wxDropTarget::OnEnter()
141 {
142 }
143
144 void wxDropTarget::OnLeave()
145 {
146 }
147
148 bool wxDropTarget::OnMove( int x, int y )
149 {
150 printf( "mouse move %d %d.\n", x, y );
151 return TRUE;
152 }
153
154 bool wxDropTarget::OnDrop( int x, int y )
155 {
156 printf( "mouse move %d %d.\n", x, y );
157 return TRUE;
158 }
159
160 bool wxDropTarget::IsSupported( wxDataFormat format )
161 {
162 return TRUE;
163 }
164
165 bool wxDropTarget::GetData( wxDataObject *data )
166 {
167 return FALSE;
168 }
169
170 void wxDropTarget::UnregisterWidget( GtkWidget *widget )
171 {
172 wxCHECK_RET( widget != NULL, "unregister widget is NULL" );
173
174 gtk_drag_dest_set( widget,
175 (GtkDestDefaults) 0,
176 (GtkTargetEntry*) NULL,
177 0,
178 (GdkDragAction) 0 );
179
180 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
181 GTK_SIGNAL_FUNC(target_drag_leave), (gpointer) this );
182
183 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
184 GTK_SIGNAL_FUNC(target_drag_motion), (gpointer) this );
185
186 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
187 GTK_SIGNAL_FUNC(target_drag_drop), (gpointer) this );
188
189 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
190 GTK_SIGNAL_FUNC(target_drag_data_received), (gpointer) this );
191 }
192
193 void wxDropTarget::RegisterWidget( GtkWidget *widget )
194 {
195 wxCHECK_RET( widget != NULL, "register widget is NULL" );
196
197 GtkTargetEntry format;
198 format.info = 0;
199 format.flags = 0;
200 char buf[100];
201 strcpy( buf, "text/plain" );
202
203 gtk_drag_dest_set( widget,
204 GTK_DEST_DEFAULT_ALL,
205 &format,
206 1,
207 (GdkDragAction)(GDK_ACTION_COPY | GDK_ACTION_MOVE) );
208
209 gtk_signal_connect( GTK_OBJECT(widget), "drag_leave",
210 GTK_SIGNAL_FUNC(target_drag_leave), (gpointer) this );
211
212 gtk_signal_connect( GTK_OBJECT(widget), "drag_motion",
213 GTK_SIGNAL_FUNC(target_drag_motion), (gpointer) this );
214
215 gtk_signal_connect( GTK_OBJECT(widget), "drag_drop",
216 GTK_SIGNAL_FUNC(target_drag_drop), (gpointer) this );
217
218 gtk_signal_connect( GTK_OBJECT(widget), "drag_data_received",
219 GTK_SIGNAL_FUNC(target_drag_data_received), (gpointer) this );
220 }
221
222 //-------------------------------------------------------------------------
223 // wxTextDropTarget
224 //-------------------------------------------------------------------------
225
226 bool wxTextDropTarget::OnMove( int WXUNUSED(x), int WXUNUSED(y) )
227 {
228 return IsSupported( wxDF_TEXT ); // same as "TEXT"
229 }
230
231 bool wxTextDropTarget::OnDrop( int x, int y )
232 {
233 if (!IsSupported( wxDF_TEXT )) return FALSE;
234
235 wxTextDataObject data;
236 if (!GetData( &data )) return FALSE;
237
238 return OnDropText( x, y, data.GetText() );
239 }
240
241 //-------------------------------------------------------------------------
242 // wxPrivateDropTarget
243 //-------------------------------------------------------------------------
244
245 wxPrivateDropTarget::wxPrivateDropTarget()
246 {
247 m_id = wxTheApp->GetAppName();
248 }
249
250 wxPrivateDropTarget::wxPrivateDropTarget( const wxString &id )
251 {
252 m_id = id;
253 }
254
255 bool wxPrivateDropTarget::OnMove( int WXUNUSED(x), int WXUNUSED(y) )
256 {
257 return IsSupported( m_id );
258 }
259
260 bool wxPrivateDropTarget::OnDrop( int x, int y )
261 {
262 if (!IsSupported( m_id )) return FALSE;
263
264 wxPrivateDataObject data;
265 if (!GetData( &data )) return FALSE;
266
267 return OnDropData( x, y, data.GetData(), data.GetSize() );
268 }
269
270 //----------------------------------------------------------------------------
271 // A drop target which accepts files (dragged from File Manager or Explorer)
272 //----------------------------------------------------------------------------
273
274 bool wxFileDropTarget::OnMove( int WXUNUSED(x), int WXUNUSED(y) )
275 {
276 return IsSupported( wxDF_FILENAME ); // same as "file:ALL"
277 }
278
279 bool wxFileDropTarget::OnDrop( int x, int y )
280 {
281 if (!IsSupported( wxDF_FILENAME )) return FALSE;
282
283 wxFileDataObject data;
284 if (!GetData( &data )) return FALSE;
285
286 /* get number of substrings /root/mytext.txt/0/root/myothertext.txt/0/0 */
287 size_t number = 0;
288 size_t i;
289 size_t size = data.GetFiles().Length();
290 char *text = WXSTRINGCAST data.GetFiles();
291 for ( i = 0; i < size; i++)
292 if (text[i] == 0) number++;
293
294 if (number == 0) return TRUE;
295
296 char **files = new char*[number];
297
298 text = WXSTRINGCAST data.GetFiles();
299 for (i = 0; i < number; i++)
300 {
301 files[i] = text;
302 int len = strlen( text );
303 text += len+1;
304 }
305
306 bool ret = OnDropFiles( x, y, number, files );
307
308 free( files );
309
310 return ret;
311 }
312
313 //-------------------------------------------------------------------------
314 // wxDropSource
315 //-------------------------------------------------------------------------
316
317 #else // NEW_CODE
318
319 GtkWidget *shape_create_icon ( const wxIcon &shape,
320 gint x,
321 gint y,
322 gint px,
323 gint py,
324 gint window_type);
325
326 /* XPM */
327 static char * gv_xpm[] = {
328 "40 34 3 1",
329 " s None c None",
330 ". c black",
331 "X c white",
332 " ",
333 " ",
334 " ...... ",
335 " ..XXXXXX.. ",
336 " .XXXXXXXXXX. ",
337 " .XXXXXXXXXXXX. ",
338 " .XXXXXXXXXXXX. ",
339 " .XXXXXXXXXXXXXX. ",
340 " .XXX..XXXX..XXX. ",
341 " ....XX....XX....XX. ",
342 " .XXX.XXX..XXXX..XXX.... ",
343 " .XXXXXXXXXXXXXXXXXXX.XXX. ",
344 " .XXXXXXXXXXXXXXXXXXXXXXXX. ",
345 " .XXXXXXXXXXXXXXXXXXXXXXXX. ",
346 " ..XXXXXXXXXXXXXXXXXXXXXX. ",
347 " .XXXXXXXXXXXXXXXXXX... ",
348 " ..XXXXXXXXXXXXXXXX. ",
349 " .XXXXXXXXXXXXXXXX. ",
350 " .XXXXXXXXXXXXXXXX. ",
351 " .XXXXXXXXXXXXXXXXX. ",
352 " .XXXXXXXXXXXXXXXXX. ",
353 " .XXXXXXXXXXXXXXXXXX. ",
354 " .XXXXXXXXXXXXXXXXXXX. ",
355 " .XXXXXXXXXXXXXXXXXXXXX. ",
356 " .XXXXXXXXXXXXXX.XXXXXXX. ",
357 " .XXXXXXX.XXXXXXX.XXXXXXX. ",
358 " .XXXXXXXX.XXXXXXX.XXXXXXX. ",
359 " .XXXXXXX...XXXXX...XXXXX. ",
360 " .XXXXXXX. ..... ..... ",
361 " ..XXXX.. ",
362 " .... ",
363 " ",
364 " ",
365 " "};
366
367 /* XPM */
368 static char * page_xpm[] = {
369 /* width height ncolors chars_per_pixel */
370 "32 32 5 1",
371 /* colors */
372 " s None c None",
373 ". c black",
374 "X c wheat",
375 "o c tan",
376 "O c #6699FF",
377 /* pixels */
378 " ................... ",
379 " .XXXXXXXXXXXXXXXXX.. ",
380 " .XXXXXXXXXXXXXXXXX.o. ",
381 " .XXXXXXXXXXXXXXXXX.oo. ",
382 " .XXXXXXXXXXXXXXXXX.ooo. ",
383 " .XXXXXXXXXXXXXXXXX.oooo. ",
384 " .XXXXXXXXXXXXXXXXX....... ",
385 " .XXXXXOOOOOOOOOOXXXooooo. ",
386 " .XXXXXXXXXXXXXXXXXXooooo. ",
387 " .XXXXXOOOOOOOOOOXXXXXXXX. ",
388 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
389 " .XXXXXXXOOOOOOOOOXXXXXXX. ",
390 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
391 " .XXXXXXOOOOOOOOOOXXXXXXX. ",
392 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
393 " .XXXXXOOOOOOOOOOXXXXXXXX. ",
394 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
395 " .XXXXXXXOOOOOOOOOXXXXXXX. ",
396 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
397 " .XXXXXXOOOOOOOOOOXXXXXXX. ",
398 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
399 " .XXXXXOOOOOOOOOOXXXXXXXX. ",
400 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
401 " .XXXXXXOOOOOOOOOOXXXXXXX. ",
402 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
403 " .XXXXXOOOOOOOXXXXXXXXXXX. ",
404 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
405 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
406 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
407 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
408 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
409 " ......................... "};
410
411
412 //-----------------------------------------------------------------------------
413 // globals
414 //-----------------------------------------------------------------------------
415
416 wxDropSource *gs_currentDropSource = (wxDropSource*) NULL;
417
418 //-----------------------------------------------------------------------------
419 // "drop_enter_event"
420 //-----------------------------------------------------------------------------
421
422 static void gtk_target_enter_callback( GtkWidget *WXUNUSED(widget),
423 GdkEventDropEnter *WXUNUSED(event),
424 wxDropTarget *target )
425 {
426 if (target)
427 target->OnEnter();
428 }
429
430 //-----------------------------------------------------------------------------
431 // "drop_leave_event"
432 //-----------------------------------------------------------------------------
433
434 static void gtk_target_leave_callback( GtkWidget *WXUNUSED(widget),
435 GdkEventDropLeave *WXUNUSED(event),
436 wxDropTarget *target )
437 {
438 if (target)
439 target->OnLeave();
440 }
441
442 //-----------------------------------------------------------------------------
443 // "drop_data_available_event"
444 //-----------------------------------------------------------------------------
445
446 static void gtk_target_callback( GtkWidget *widget,
447 GdkEventDropDataAvailable *event,
448 wxDropTarget *target )
449 {
450 if (target)
451 {
452 int x = 0;
453 int y = 0;
454 gdk_window_get_pointer( widget->window, &x, &y, (GdkModifierType *) NULL );
455 /*
456 printf( "Drop data is of type %s.\n", event->data_type );
457 */
458 target->OnDrop( x, y, (const void*)event->data, (size_t)event->data_numbytes );
459 }
460
461 /*
462 g_free (event->data);
463 g_free (event->data_type);
464 */
465 }
466
467 // ----------------------------------------------------------------------------
468 // wxDropTarget
469 // ----------------------------------------------------------------------------
470
471 wxDropTarget::wxDropTarget()
472 {
473 m_format = (wxDataFormat*) NULL;
474 }
475
476 wxDropTarget::~wxDropTarget()
477 {
478 if (m_format) delete m_format;
479 }
480
481 wxDataFormat &wxDropTarget::GetFormat(size_t n) const
482 {
483 return (*m_format);
484 }
485
486 void wxDropTarget::UnregisterWidget( GtkWidget *widget )
487 {
488 if (!widget) return;
489
490 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
491 GTK_SIGNAL_FUNC(gtk_target_callback), (gpointer) this );
492
493 gtk_widget_dnd_drop_set( widget, FALSE, (gchar **) NULL, 0, FALSE );
494 }
495
496 void wxDropTarget::RegisterWidget( GtkWidget *widget )
497 {
498 wxString formats;
499 int valid = 0;
500
501 for ( size_t i = 0; i < GetFormatCount(); i++ )
502 {
503 switch (GetFormat(i).GetType())
504 {
505 case wxDF_TEXT:
506 {
507 if (i > 0) formats += ";";
508 formats += "text/plain";
509 valid++;
510 break;
511 }
512 case wxDF_FILENAME:
513 {
514 if (i > 0) formats += ";";
515 formats += "file:ALL";
516 valid++;
517 break;
518 }
519 case wxDF_PRIVATE:
520 {
521 if (i > 0) formats += ";";
522 wxPrivateDropTarget *pdt = (wxPrivateDropTarget *)this;
523 formats += pdt->GetId();
524 valid++;
525 break;
526 }
527 default:
528 break;
529 }
530 }
531
532 char *str = WXSTRINGCAST formats;
533
534 gtk_widget_dnd_drop_set( widget, TRUE, &str, valid, FALSE );
535
536 gtk_signal_connect( GTK_OBJECT(widget), "drop_data_available_event",
537 GTK_SIGNAL_FUNC(gtk_target_callback), (gpointer) this );
538
539 gtk_signal_connect( GTK_OBJECT(widget), "drop_enter_event",
540 GTK_SIGNAL_FUNC(gtk_target_enter_callback), (gpointer) this );
541
542 gtk_signal_connect( GTK_OBJECT(widget), "drop_leave_event",
543 GTK_SIGNAL_FUNC(gtk_target_leave_callback), (gpointer) this );
544 }
545
546 // ----------------------------------------------------------------------------
547 // wxTextDropTarget
548 // ----------------------------------------------------------------------------
549
550 wxTextDropTarget::wxTextDropTarget()
551 {
552 m_format = new wxDataFormat( wxDF_TEXT );
553 }
554
555 bool wxTextDropTarget::OnDrop( long x, long y, const void *data, size_t WXUNUSED(size) )
556 {
557 OnDropText( x, y, (const char*)data );
558 return TRUE;
559 }
560
561 bool wxTextDropTarget::OnDropText( long x, long y, const char *psz )
562 {
563 /*
564 printf( "Got dropped text: %s.\n", psz );
565 printf( "At x: %d, y: %d.\n", (int)x, (int)y );
566 */
567 return TRUE;
568 }
569
570 size_t wxTextDropTarget::GetFormatCount() const
571 {
572 return 1;
573 }
574
575 // ----------------------------------------------------------------------------
576 // wxPrivateDropTarget
577 // ----------------------------------------------------------------------------
578
579 wxPrivateDropTarget::wxPrivateDropTarget()
580 {
581 m_id = wxTheApp->GetAppName();
582 m_format = new wxDataFormat( m_id );
583 }
584
585 void wxPrivateDropTarget::SetId( const wxString& id )
586 {
587 m_id = id;
588 m_format->SetId( id );
589 }
590
591 size_t wxPrivateDropTarget::GetFormatCount() const
592 {
593 return 1;
594 }
595
596 // ----------------------------------------------------------------------------
597 // wxFileDropTarget
598 // ----------------------------------------------------------------------------
599
600 wxFileDropTarget::wxFileDropTarget()
601 {
602 m_format = new wxDataFormat( wxDF_FILENAME );
603 }
604
605 bool wxFileDropTarget::OnDropFiles( long x, long y, size_t nFiles, const char * const aszFiles[] )
606 {
607 printf( "Got %d dropped files.\n", (int)nFiles );
608 printf( "At x: %d, y: %d.\n", (int)x, (int)y );
609
610 for (size_t i = 0; i < nFiles; i++)
611 {
612 printf( aszFiles[i] );
613 printf( "\n" );
614 }
615
616 return TRUE;
617 }
618
619 bool wxFileDropTarget::OnDrop(long x, long y, const void *data, size_t size )
620 {
621 size_t number = 0;
622 size_t i;
623 char *text = (char*) data;
624 for ( i = 0; i < size; i++)
625 if (text[i] == 0) number++;
626
627 if (number == 0) return TRUE;
628
629 char **files = new char*[number];
630
631 text = (char*) data;
632 for (i = 0; i < number; i++)
633 {
634 files[i] = text;
635 int len = strlen( text );
636 text += len+1;
637 }
638
639 bool ret = OnDropFiles( x, y, 1, files );
640
641 free( files );
642
643 return ret;
644 }
645
646 size_t wxFileDropTarget::GetFormatCount() const
647 {
648 return 1;
649 }
650
651 //-------------------------------------------------------------------------
652 // wxDropSource
653 //-------------------------------------------------------------------------
654
655 static void
656 shape_motion (GtkWidget *widget,
657 GdkEventMotion * /*event*/);
658
659 //-----------------------------------------------------------------------------
660 // "drag_request_event"
661 //-----------------------------------------------------------------------------
662
663 void gtk_drag_callback( GtkWidget *widget, GdkEventDragRequest *event, wxDropSource *source )
664 {
665 wxDataBroker *data = source->m_data;
666
667 if (!data) return;
668
669 wxNode *node = data->m_dataObjects.First();
670 {
671 wxDataObject *dobj = (wxDataObject*) node->Data();
672
673 if ((strcmp(event->data_type,"file:ALL") == 0) &&
674 (dobj->GetFormat().GetType() == wxDF_FILENAME))
675 {
676 wxFileDataObject *file_object = (wxFileDataObject*) dobj;
677
678 wxString text = file_object->GetFiles();
679
680 char *s = WXSTRINGCAST text;
681
682 gtk_widget_dnd_data_set( widget,
683 (GdkEvent*)event,
684 (unsigned char*) s,
685 (int) text.Length()+1 );
686
687 source->m_retValue = wxDragCopy;
688
689 return;
690 }
691
692 if ((strcmp(event->data_type,"text/plain") == 0) &&
693 (dobj->GetFormat().GetType() == wxDF_TEXT))
694 {
695 wxTextDataObject *text_object = (wxTextDataObject*) dobj;
696
697 wxString text = text_object->GetText();
698
699 char *s = WXSTRINGCAST text;
700
701 gtk_widget_dnd_data_set( widget,
702 (GdkEvent*)event,
703 (unsigned char*) s,
704 (int) text.Length()+1 );
705
706 source->m_retValue = wxDragCopy;
707
708 return;
709 }
710
711 if (dobj->GetFormat().GetType() == wxDF_PRIVATE)
712 {
713 wxPrivateDataObject *pdo = (wxPrivateDataObject*) dobj;
714
715 if (pdo->GetId() == event->data_type)
716 {
717 gtk_widget_dnd_data_set( widget,
718 (GdkEvent*)event,
719 (unsigned char*) pdo->GetData(),
720 (int) pdo->GetSize() );
721
722 source->m_retValue = wxDragCopy;
723
724 return;
725 }
726 }
727
728 node = node->Next();
729 }
730 }
731
732 wxDropSource::wxDropSource( wxWindow *win, const wxIcon &go, const wxIcon &stop )
733 {
734 g_blockEventsOnDrag = TRUE;
735
736 m_window = win;
737 m_widget = win->m_widget;
738 if (win->m_wxwindow) m_widget = win->m_wxwindow;
739
740 m_data = (wxDataBroker*) NULL;
741 m_retValue = wxDragCancel;
742
743 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
744 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
745
746 m_goIcon = go;
747 if (wxNullIcon == go) m_goIcon = wxIcon( page_xpm );
748 m_stopIcon = stop;
749 if (wxNullIcon == stop) m_stopIcon = wxIcon( gv_xpm );
750 }
751
752 wxDropSource::wxDropSource( wxDataObject *data, wxWindow *win, const wxIcon &go, const wxIcon &stop )
753 {
754 g_blockEventsOnDrag = TRUE;
755
756 m_window = win;
757 m_widget = win->m_widget;
758 if (win->m_wxwindow) m_widget = win->m_wxwindow;
759 m_retValue = wxDragCancel;
760
761 if (data)
762 {
763 m_data = new wxDataBroker();
764 m_data->Add( data );
765 }
766 else
767 {
768 m_data = (wxDataBroker*) NULL;
769 }
770
771 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
772 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
773
774 m_goIcon = go;
775 if (wxNullIcon == go) m_goIcon = wxIcon( page_xpm );
776 m_stopIcon = stop;
777 if (wxNullIcon == stop) m_stopIcon = wxIcon( gv_xpm );
778 }
779
780 wxDropSource::wxDropSource( wxDataBroker *data, wxWindow *win )
781 {
782 g_blockEventsOnDrag = TRUE;
783
784 m_window = win;
785 m_widget = win->m_widget;
786 if (win->m_wxwindow) m_widget = win->m_wxwindow;
787 m_retValue = wxDragCancel;
788
789 m_data = data;
790
791 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
792 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
793 }
794
795 void wxDropSource::SetData( wxDataObject *data )
796 {
797 if (m_data) delete m_data;
798
799 if (data)
800 {
801 m_data = new wxDataBroker();
802 m_data->Add( data );
803 }
804 else
805 {
806 m_data = (wxDataBroker*) NULL;
807 }
808 }
809
810 void wxDropSource::SetData( wxDataBroker *data )
811 {
812 if (m_data) delete m_data;
813
814 m_data = data;
815 }
816
817 wxDropSource::~wxDropSource(void)
818 {
819 if (m_data) delete m_data;
820
821 g_blockEventsOnDrag = FALSE;
822 }
823
824 wxDragResult wxDropSource::DoDragDrop( bool WXUNUSED(bAllowMove) )
825 {
826 if (gdk_dnd.dnd_grabbed) return (wxDragResult) wxDragNone;
827 if (gdk_dnd.drag_really) return (wxDragResult) wxDragNone;
828
829 wxASSERT_MSG( m_data, "wxDragSource: no data" );
830
831 if (!m_data) return (wxDragResult) wxDragNone;
832
833 static GtkWidget *drag_icon = (GtkWidget*) NULL;
834 static GtkWidget *drop_icon = (GtkWidget*) NULL;
835
836 GdkPoint hotspot_1 = {0,-5 };
837
838 if (!drag_icon)
839 {
840 drag_icon = shape_create_icon ( m_stopIcon,
841 440, 140, 0,0, GTK_WINDOW_POPUP);
842
843 gtk_signal_connect (GTK_OBJECT (drag_icon), "destroy",
844 GTK_SIGNAL_FUNC(gtk_widget_destroyed),
845 &drag_icon);
846
847 gtk_widget_hide (drag_icon);
848 }
849
850 GdkPoint hotspot_2 = {-5,-5};
851
852 if (!drop_icon)
853 {
854 drop_icon = shape_create_icon ( m_goIcon,
855 440, 140, 0,0, GTK_WINDOW_POPUP);
856
857 gtk_signal_connect (GTK_OBJECT (drop_icon), "destroy",
858 GTK_SIGNAL_FUNC(gtk_widget_destroyed),
859 &drop_icon);
860
861 gtk_widget_hide (drop_icon);
862 }
863
864
865 gdk_dnd_set_drag_shape( drag_icon->window,
866 &hotspot_1,
867 drop_icon->window,
868 &hotspot_2);
869
870
871 GdkWindowPrivate *wp = (GdkWindowPrivate*) m_widget->window;
872
873 RegisterWindow();
874
875 gdk_dnd.drag_perhaps = TRUE;
876
877 gdk_dnd.dnd_drag_start.x = 5;
878 gdk_dnd.dnd_drag_start.y = 5;
879 gdk_dnd.real_sw = wp;
880
881 if (gdk_dnd.drag_startwindows)
882 {
883 g_free( gdk_dnd.drag_startwindows );
884 gdk_dnd.drag_startwindows = (GdkWindow **) NULL;
885 }
886 gdk_dnd.drag_numwindows = gdk_dnd.drag_really = 0;
887
888 XWindowAttributes dnd_winattr;
889 XGetWindowAttributes( gdk_display, wp->xwindow, &dnd_winattr );
890 wp->dnd_drag_savedeventmask = dnd_winattr.your_event_mask;
891
892 gdk_dnd_drag_addwindow( m_widget->window );
893
894 GdkEventDragBegin ev;
895 ev.type = GDK_DRAG_BEGIN;
896 ev.window = m_widget->window;
897 ev.u.allflags = 0;
898 ev.u.flags.protocol_version = DND_PROTOCOL_VERSION;
899
900 gdk_event_put( (GdkEvent*)&ev );
901
902 XGrabPointer( gdk_display, wp->xwindow, False,
903 ButtonMotionMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
904 GrabModeAsync, GrabModeAsync, gdk_root_window, None, CurrentTime );
905
906 gdk_dnd_set_drag_cursors( m_defaultCursor.GetCursor(), m_goaheadCursor.GetCursor() );
907
908 gdk_dnd.dnd_grabbed = TRUE;
909 gdk_dnd.drag_really = 1;
910
911 int x = 0;
912 int y = 0;
913 wxGetMousePosition( &x, &y );
914
915 gdk_dnd_display_drag_cursor( x, y, FALSE, TRUE );
916
917 gs_currentDropSource = this;
918
919 while (gdk_dnd.drag_really || gdk_dnd.drag_perhaps) wxYield();
920
921 gs_currentDropSource = (wxDropSource*) NULL;
922
923 UnregisterWindow();
924
925 g_blockEventsOnDrag = FALSE;
926
927 return m_retValue;
928 }
929
930 void wxDropSource::RegisterWindow(void)
931 {
932 if (!m_data) return;
933
934 wxString formats;
935
936 wxNode *node = m_data->m_dataObjects.First();
937 while (node)
938 {
939 wxDataObject* dobj = (wxDataObject*) node->Data();
940
941 switch (dobj->GetFormat().GetType())
942 {
943 case wxDF_TEXT:
944 {
945 formats += "text/plain";
946 break;
947 }
948 case wxDF_FILENAME:
949 {
950 formats += "file:ALL";
951 break;
952 }
953 case wxDF_PRIVATE:
954 {
955 wxPrivateDataObject* pdo = (wxPrivateDataObject*) m_data;
956 formats += pdo->GetId();
957 break;
958 }
959 default:
960 break;
961 }
962 node = node->Next();
963 }
964
965 char *str = WXSTRINGCAST formats;
966
967 gtk_widget_dnd_drag_set( m_widget, TRUE, &str, 1 );
968
969 gtk_signal_connect( GTK_OBJECT(m_widget), "drag_request_event",
970 GTK_SIGNAL_FUNC(gtk_drag_callback), (gpointer)this );
971 }
972
973 void wxDropSource::UnregisterWindow(void)
974 {
975 if (!m_widget) return;
976
977 gtk_widget_dnd_drag_set( m_widget, FALSE, (gchar **) NULL, 0 );
978
979 gtk_signal_disconnect_by_data( GTK_OBJECT(m_widget), (gpointer)this );
980 }
981
982
983 /*
984 * Shaped Windows
985 */
986 static GdkWindow *root_win = (GdkWindow*) NULL;
987
988 typedef struct _cursoroffset {gint x,y;} CursorOffset;
989
990 static void
991 shape_pressed (GtkWidget *widget, GdkEventButton *event)
992 {
993 CursorOffset *p;
994
995 /* ignore double and triple click */
996 if (event->type != GDK_BUTTON_PRESS)
997 return;
998
999 p = (CursorOffset *)gtk_object_get_user_data (GTK_OBJECT(widget));
1000 p->x = (int) event->x;
1001 p->y = (int) event->y;
1002
1003 gtk_grab_add (widget);
1004 gdk_pointer_grab (widget->window, TRUE,
1005 (GdkEventMask)
1006 (GDK_BUTTON_RELEASE_MASK |
1007 GDK_BUTTON_MOTION_MASK |
1008 GDK_POINTER_MOTION_HINT_MASK),
1009 (GdkWindow*)NULL,
1010 (GdkCursor*) NULL, 0);
1011 }
1012
1013
1014 static void
1015 shape_released (GtkWidget *widget)
1016 {
1017 gtk_grab_remove (widget);
1018 gdk_pointer_ungrab (0);
1019 }
1020
1021 static void
1022 shape_motion (GtkWidget *widget,
1023 GdkEventMotion * /*event*/ )
1024 {
1025 gint xp, yp;
1026 CursorOffset * p;
1027 GdkModifierType mask;
1028
1029 p = (CursorOffset *)gtk_object_get_user_data (GTK_OBJECT (widget));
1030
1031 /*
1032 * Can't use event->x / event->y here
1033 * because I need absolute coordinates.
1034 */
1035
1036 gdk_window_get_pointer (root_win, &xp, &yp, &mask);
1037 gtk_widget_set_uposition (widget, xp - p->x, yp - p->y);
1038
1039 if (gs_currentDropSource) gs_currentDropSource->GiveFeedback( wxDragCopy, FALSE );
1040 }
1041
1042 GtkWidget *
1043 shape_create_icon (const wxIcon &shape,
1044 gint x,
1045 gint y,
1046 gint px,
1047 gint py,
1048 gint window_type)
1049 {
1050 /*
1051 * GDK_WINDOW_TOPLEVEL works also, giving you a title border
1052 */
1053 GtkWidget *window = gtk_window_new ((GtkWindowType)window_type);
1054
1055 GtkWidget *fixed = gtk_fixed_new ();
1056 gtk_widget_set_usize (fixed, 100,100);
1057 gtk_container_add (GTK_CONTAINER (window), fixed);
1058 gtk_widget_show (fixed);
1059
1060 gtk_widget_set_events (window,
1061 gtk_widget_get_events (window) |
1062 GDK_BUTTON_MOTION_MASK |
1063 GDK_POINTER_MOTION_HINT_MASK |
1064 GDK_BUTTON_PRESS_MASK);
1065
1066 gtk_widget_realize (window);
1067
1068 GdkBitmap *mask = (GdkBitmap*) NULL;
1069 if (shape.GetMask()) mask = shape.GetMask()->GetBitmap();
1070
1071 GtkWidget *pixmap = gtk_pixmap_new (shape.GetPixmap(), mask);
1072 gtk_fixed_put (GTK_FIXED (fixed), pixmap, px,py);
1073 gtk_widget_show (pixmap);
1074
1075 gtk_widget_shape_combine_mask (window, mask, px,py);
1076
1077
1078 gtk_signal_connect (GTK_OBJECT (window), "button_press_event",
1079 GTK_SIGNAL_FUNC (shape_pressed),NULL);
1080 gtk_signal_connect (GTK_OBJECT (window), "button_release_event",
1081 GTK_SIGNAL_FUNC (shape_released),NULL);
1082 gtk_signal_connect (GTK_OBJECT (window), "motion_notify_event",
1083 GTK_SIGNAL_FUNC (shape_motion),NULL);
1084
1085 CursorOffset*icon_pos = g_new (CursorOffset, 1);
1086 gtk_object_set_user_data(GTK_OBJECT(window), icon_pos);
1087
1088 gtk_widget_set_uposition (window, x, y);
1089 gtk_widget_show (window);
1090
1091 return window;
1092 }
1093
1094 #endif
1095 // NEW_GTK_DND_CODE
1096
1097 #endif
1098
1099 // wxUSE_DRAG_AND_DROP