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