]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/dnd.cpp
Another Unicode fix.
[wxWidgets.git] / src / gtk / dnd.cpp
CommitLineData
c801d85f
KB
1///////////////////////////////////////////////////////////////////////////////
2// Name: dnd.cpp
3// Purpose: wxDropTarget class
4// Author: Robert Roebling
a81258be 5// Id: $Id$
01111366
RR
6// Copyright: (c) 1998 Robert Roebling
7// Licence: wxWindows licence
c801d85f
KB
8///////////////////////////////////////////////////////////////////////////////
9
10#ifdef __GNUG__
11#pragma implementation "dnd.h"
12#endif
13
14#include "wx/dnd.h"
ac57418f 15
06cfab17 16#if wxUSE_DRAG_AND_DROP
ac57418f 17
c801d85f
KB
18#include "wx/window.h"
19#include "wx/app.h"
20#include "wx/gdicmn.h"
b527aac5
RR
21#include "wx/intl.h"
22#include "wx/utils.h"
c801d85f 23
83624f79
RR
24#include "gdk/gdk.h"
25#include "gtk/gtk.h"
c801d85f
KB
26#include "gdk/gdkprivate.h"
27
8a126fcc
RR
28#include "gtk/gtkdnd.h"
29#include "gtk/gtkselection.h"
c801d85f 30
22d5903e
RR
31//----------------------------------------------------------------------------
32// global data
33//----------------------------------------------------------------------------
c801d85f
KB
34
35extern bool g_blockEventsOnDrag;
36
22d5903e
RR
37//----------------------------------------------------------------------------
38// standard icons
39//----------------------------------------------------------------------------
40
41/* XPM */
42static char * gv_xpm[] = {
43"40 34 3 1",
44" s None c None",
45". c black",
46"X c white",
47" ",
48" ",
49" ...... ",
50" ..XXXXXX.. ",
51" .XXXXXXXXXX. ",
52" .XXXXXXXXXXXX. ",
53" .XXXXXXXXXXXX. ",
54" .XXXXXXXXXXXXXX. ",
55" .XXX..XXXX..XXX. ",
56" ....XX....XX....XX. ",
57" .XXX.XXX..XXXX..XXX.... ",
58" .XXXXXXXXXXXXXXXXXXX.XXX. ",
59" .XXXXXXXXXXXXXXXXXXXXXXXX. ",
60" .XXXXXXXXXXXXXXXXXXXXXXXX. ",
61" ..XXXXXXXXXXXXXXXXXXXXXX. ",
62" .XXXXXXXXXXXXXXXXXX... ",
63" ..XXXXXXXXXXXXXXXX. ",
64" .XXXXXXXXXXXXXXXX. ",
65" .XXXXXXXXXXXXXXXX. ",
66" .XXXXXXXXXXXXXXXXX. ",
67" .XXXXXXXXXXXXXXXXX. ",
68" .XXXXXXXXXXXXXXXXXX. ",
69" .XXXXXXXXXXXXXXXXXXX. ",
70" .XXXXXXXXXXXXXXXXXXXXX. ",
71" .XXXXXXXXXXXXXX.XXXXXXX. ",
72" .XXXXXXX.XXXXXXX.XXXXXXX. ",
73" .XXXXXXXX.XXXXXXX.XXXXXXX. ",
74" .XXXXXXX...XXXXX...XXXXX. ",
75" .XXXXXXX. ..... ..... ",
76" ..XXXX.. ",
77" .... ",
78" ",
79" ",
80" "};
81
82/* XPM */
83static char * page_xpm[] = {
84/* width height ncolors chars_per_pixel */
85"32 32 5 1",
86/* colors */
87" s None c None",
88". c black",
89"X c wheat",
90"o c tan",
91"O c #6699FF",
92/* pixels */
93" ................... ",
94" .XXXXXXXXXXXXXXXXX.. ",
95" .XXXXXXXXXXXXXXXXX.o. ",
96" .XXXXXXXXXXXXXXXXX.oo. ",
97" .XXXXXXXXXXXXXXXXX.ooo. ",
98" .XXXXXXXXXXXXXXXXX.oooo. ",
99" .XXXXXXXXXXXXXXXXX....... ",
100" .XXXXXOOOOOOOOOOXXXooooo. ",
101" .XXXXXXXXXXXXXXXXXXooooo. ",
102" .XXXXXOOOOOOOOOOXXXXXXXX. ",
103" .XXXXXXXXXXXXXXXXXXXXXXX. ",
104" .XXXXXXXOOOOOOOOOXXXXXXX. ",
105" .XXXXXXXXXXXXXXXXXXXXXXX. ",
106" .XXXXXXOOOOOOOOOOXXXXXXX. ",
107" .XXXXXXXXXXXXXXXXXXXXXXX. ",
108" .XXXXXOOOOOOOOOOXXXXXXXX. ",
109" .XXXXXXXXXXXXXXXXXXXXXXX. ",
110" .XXXXXXXOOOOOOOOOXXXXXXX. ",
111" .XXXXXXXXXXXXXXXXXXXXXXX. ",
112" .XXXXXXOOOOOOOOOOXXXXXXX. ",
113" .XXXXXXXXXXXXXXXXXXXXXXX. ",
114" .XXXXXOOOOOOOOOOXXXXXXXX. ",
115" .XXXXXXXXXXXXXXXXXXXXXXX. ",
116" .XXXXXXOOOOOOOOOOXXXXXXX. ",
117" .XXXXXXXXXXXXXXXXXXXXXXX. ",
118" .XXXXXOOOOOOOXXXXXXXXXXX. ",
119" .XXXXXXXXXXXXXXXXXXXXXXX. ",
120" .XXXXXXXXXXXXXXXXXXXXXXX. ",
121" .XXXXXXXXXXXXXXXXXXXXXXX. ",
122" .XXXXXXXXXXXXXXXXXXXXXXX. ",
123" .XXXXXXXXXXXXXXXXXXXXXXX. ",
124" ......................... "};
125
126
4ba47b40 127
33a5bc52
RR
128// ----------------------------------------------------------------------------
129// "drag_leave"
130// ----------------------------------------------------------------------------
131
132static void target_drag_leave( GtkWidget *WXUNUSED(widget),
d6086ea6
RR
133 GdkDragContext *context,
134 guint WXUNUSED(time),
829e3e8d 135 wxDropTarget *drop_target )
33a5bc52 136{
829e3e8d
RR
137 /* inform the wxDropTarget about the current GdkDragContext.
138 this is only valid for the duration of this call */
139 drop_target->SetDragContext( context );
140
141 /* we don't need return values. this event is just for
142 information */
143 drop_target->OnLeave();
144
145 /* this has to be done because GDK has no "drag_enter" event */
146 drop_target->m_firstMotion = TRUE;
147
148 /* after this, invalidate the drop_target's GdkDragContext */
149 drop_target->SetDragContext( (GdkDragContext*) NULL );
33a5bc52
RR
150}
151
152// ----------------------------------------------------------------------------
153// "drag_motion"
154// ----------------------------------------------------------------------------
155
156static gboolean target_drag_motion( GtkWidget *WXUNUSED(widget),
157 GdkDragContext *context,
d6086ea6
RR
158 gint x,
159 gint y,
160 guint time,
829e3e8d 161 wxDropTarget *drop_target )
33a5bc52 162{
829e3e8d
RR
163 /* Owen Taylor: "if the coordinates not in a drop zone,
164 return FALSE, otherwise call gtk_drag_status() and
165 return TRUE" */
166
167 /* inform the wxDropTarget about the current GdkDragContext.
168 this is only valid for the duration of this call */
169 drop_target->SetDragContext( context );
d6086ea6 170
829e3e8d 171 if (drop_target->m_firstMotion)
d6086ea6 172 {
829e3e8d
RR
173 /* the first "drag_motion" event substitutes a "drag_enter" event */
174 drop_target->OnEnter();
d6086ea6
RR
175 }
176
829e3e8d
RR
177 /* give program a chance to react (i.e. to say no by returning FALSE) */
178 bool ret = drop_target->OnMove( x, y );
179
180 /* we don't yet handle which "actions" (i.e. copy or move)
181 the target accepts. so far we simply accept the
182 suggested action. TODO. */
183 if (ret)
184 gdk_drag_status( context, context->suggested_action, time );
185
186 /* after this, invalidate the drop_target's GdkDragContext */
187 drop_target->SetDragContext( (GdkDragContext*) NULL );
188
189 /* this has to be done because GDK has no "drag_enter" event */
190 drop_target->m_firstMotion = FALSE;
191
192 return ret;
33a5bc52
RR
193}
194
195// ----------------------------------------------------------------------------
196// "drag_drop"
197// ----------------------------------------------------------------------------
198
199static gboolean target_drag_drop( GtkWidget *widget,
200 GdkDragContext *context,
201 gint x,
202 gint y,
829e3e8d
RR
203 guint time,
204 wxDropTarget *drop_target )
33a5bc52 205{
829e3e8d
RR
206 /* Owen Taylor: "if the drop is not in a drop zone,
207 return FALSE, otherwise, if you aren't accepting
208 the drop, call gtk_drag_finish() with success == FALSE
209 otherwise call gtk_drag_data_get()" */
4ba47b40
RR
210
211// printf( "drop.\n" );
829e3e8d
RR
212
213 /* this seems to make a difference between not accepting
214 due to wrong target area and due to wrong format. let
215 us hope that this is not required.. */
33a5bc52 216
829e3e8d
RR
217 /* inform the wxDropTarget about the current GdkDragContext.
218 this is only valid for the duration of this call */
219 drop_target->SetDragContext( context );
220
221 /* inform the wxDropTarget about the current drag widget.
222 this is only valid for the duration of this call */
223 drop_target->SetDragWidget( widget );
224
225 /* inform the wxDropTarget about the current drag time.
226 this is only valid for the duration of this call */
227 drop_target->SetDragTime( time );
228
229 bool ret = drop_target->OnDrop( x, y );
230
5af019af 231 if (!ret)
829e3e8d
RR
232 {
233 /* cancel the whole thing */
234 gtk_drag_finish( context,
235 FALSE, /* no success */
236 FALSE, /* don't delete data on dropping side */
237 time );
238 }
239
240 /* after this, invalidate the drop_target's GdkDragContext */
241 drop_target->SetDragContext( (GdkDragContext*) NULL );
242
243 /* after this, invalidate the drop_target's drag widget */
244 drop_target->SetDragWidget( (GtkWidget*) NULL );
245
246 /* this has to be done because GDK has no "drag_enter" event */
247 drop_target->m_firstMotion = TRUE;
248
249 return ret;
33a5bc52
RR
250}
251
252// ----------------------------------------------------------------------------
253// "drag_data_received"
254// ----------------------------------------------------------------------------
255
256static void target_drag_data_received( GtkWidget *WXUNUSED(widget),
257 GdkDragContext *context,
258 gint x,
259 gint y,
260 GtkSelectionData *data,
261 guint WXUNUSED(info),
829e3e8d
RR
262 guint time,
263 wxDropTarget *drop_target )
33a5bc52 264{
829e3e8d
RR
265 /* Owen Taylor: "call gtk_drag_finish() with
266 success == TRUE" */
267
4ba47b40
RR
268// printf( "data received.\n" );
269
829e3e8d 270 if ((data->length <= 0) || (data->format != 8))
33a5bc52 271 {
829e3e8d
RR
272 /* negative data length and non 8-bit data format
273 qualifies for junk */
274 gtk_drag_finish (context, FALSE, FALSE, time);
5af019af
RR
275
276 return;
829e3e8d 277 }
5af019af
RR
278
279 /* inform the wxDropTarget about the current GtkSelectionData.
280 this is only valid for the duration of this call */
281 drop_target->SetDragData( data );
282
283 if (drop_target->OnData( x, y ))
829e3e8d 284 {
829e3e8d 285 /* tell GTK that data transfer was successfull */
ab8884ac 286 gtk_drag_finish( context, TRUE, FALSE, time );
33a5bc52 287 }
5af019af
RR
288 else
289 {
290 /* tell GTK that data transfer was not successfull */
291 gtk_drag_finish( context, FALSE, FALSE, time );
292 }
293
294 /* after this, invalidate the drop_target's drag data */
295 drop_target->SetDragData( (GtkSelectionData*) NULL );
33a5bc52
RR
296}
297
4ba47b40 298//----------------------------------------------------------------------------
33a5bc52 299// wxDropTarget
4ba47b40 300//----------------------------------------------------------------------------
33a5bc52 301
f5368809
RR
302wxDropTarget::wxDropTarget()
303{
829e3e8d
RR
304 m_firstMotion = TRUE;
305 m_dragContext = (GdkDragContext*) NULL;
306 m_dragWidget = (GtkWidget*) NULL;
5af019af 307 m_dragData = (GtkSelectionData*) NULL;
829e3e8d 308 m_dragTime = 0;
f5368809
RR
309}
310
311wxDropTarget::~wxDropTarget()
312{
313}
314
d6086ea6
RR
315void wxDropTarget::OnEnter()
316{
317}
318
319void wxDropTarget::OnLeave()
320{
321}
322
829e3e8d 323bool wxDropTarget::OnMove( int WXUNUSED(x), int WXUNUSED(y) )
d6086ea6 324{
d6086ea6
RR
325 return TRUE;
326}
327
829e3e8d 328bool wxDropTarget::OnDrop( int WXUNUSED(x), int WXUNUSED(y) )
d6086ea6 329{
829e3e8d 330 return FALSE;
d6086ea6
RR
331}
332
5af019af
RR
333bool wxDropTarget::OnData( int WXUNUSED(x), int WXUNUSED(y) )
334{
335 return FALSE;
336}
337
338bool wxDropTarget::RequestData( wxDataFormat format )
339{
340 if (!m_dragContext) return FALSE;
341 if (!m_dragWidget) return FALSE;
342
343 /* this should trigger an "drag_data_received" event */
344 gtk_drag_get_data( m_dragWidget,
345 m_dragContext,
346 format.GetAtom(),
347 m_dragTime );
348
349 return TRUE;
350}
351
d6086ea6 352bool wxDropTarget::IsSupported( wxDataFormat format )
22d5903e 353{
22d5903e
RR
354 if (!m_dragContext) return FALSE;
355
356 GList *child = m_dragContext->targets;
357 while (child)
358 {
359 GdkAtom formatAtom = (GdkAtom) GPOINTER_TO_INT(child->data);
829e3e8d 360
4ba47b40
RR
361// char *name = gdk_atom_name( formatAtom );
362// if (name) printf( "Format available: %s.\n", name );
829e3e8d
RR
363
364 if (formatAtom == format.GetAtom()) return TRUE;
22d5903e
RR
365 child = child->next;
366 }
829e3e8d
RR
367
368 return FALSE;
d6086ea6
RR
369}
370
5af019af 371bool wxDropTarget::GetData( wxDataObject *data_object )
d6086ea6 372{
5af019af 373 if (!m_dragData) return FALSE;
4ba47b40 374
5af019af
RR
375 if (m_dragData->target != data_object->GetFormat().GetAtom()) return FALSE;
376
377 if (data_object->GetFormat().GetType() == wxDF_TEXT)
378 {
379 wxTextDataObject *text_object = (wxTextDataObject*)data_object;
380 text_object->SetText( (const char*)m_dragData->data );
381 } else
382
383 if (data_object->GetFormat().GetType() == wxDF_FILENAME)
384 {
385 } else
386
387 if (data_object->GetFormat().GetType() == wxDF_PRIVATE)
388 {
389 wxPrivateDataObject *priv_object = (wxPrivateDataObject*)data_object;
390 priv_object->SetData( (const char*)m_dragData->data, (size_t)m_dragData->length );
391 }
829e3e8d 392
5af019af 393 return TRUE;
d6086ea6
RR
394}
395
f5368809
RR
396void wxDropTarget::UnregisterWidget( GtkWidget *widget )
397{
93c5dd39 398 wxCHECK_RET( widget != NULL, _T("unregister widget is NULL") );
f5368809 399
829e3e8d 400 gtk_drag_dest_unset( widget );
33a5bc52 401
d6086ea6 402 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
33a5bc52
RR
403 GTK_SIGNAL_FUNC(target_drag_leave), (gpointer) this );
404
d6086ea6 405 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
33a5bc52
RR
406 GTK_SIGNAL_FUNC(target_drag_motion), (gpointer) this );
407
d6086ea6 408 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
33a5bc52
RR
409 GTK_SIGNAL_FUNC(target_drag_drop), (gpointer) this );
410
d6086ea6 411 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
33a5bc52 412 GTK_SIGNAL_FUNC(target_drag_data_received), (gpointer) this );
f5368809
RR
413}
414
415void wxDropTarget::RegisterWidget( GtkWidget *widget )
416{
93c5dd39 417 wxCHECK_RET( widget != NULL, _T("register widget is NULL") );
f5368809 418
829e3e8d
RR
419 /* gtk_drag_dest_set() determines what default behaviour we'd like
420 GTK to supply. we don't want to specify out targets (=formats)
421 or actions in advance (i.e. not GTK_DEST_DEFAULT_MOTION and
422 not GTK_DEST_DEFAULT_DROP). instead we react individually to
423 "drag_motion" and "drag_drop" events. this makes it possible
424 to allow dropping on only a small area. we should set
425 GTK_DEST_DEFAULT_HIGHLIGHT as this will switch on the nice
426 highlighting if dragging over standard controls, but this
427 seems to be broken without the other two. */
f5368809 428
d6086ea6 429 gtk_drag_dest_set( widget,
829e3e8d
RR
430 (GtkDestDefaults) 0, /* no default behaviour */
431 (GtkTargetEntry*) NULL, /* we don't supply any formats here */
432 0, /* number of targets = 0 */
433 (GdkDragAction) 0 ); /* we don't supply any actions here */
33a5bc52 434
d6086ea6 435 gtk_signal_connect( GTK_OBJECT(widget), "drag_leave",
33a5bc52
RR
436 GTK_SIGNAL_FUNC(target_drag_leave), (gpointer) this );
437
d6086ea6 438 gtk_signal_connect( GTK_OBJECT(widget), "drag_motion",
33a5bc52
RR
439 GTK_SIGNAL_FUNC(target_drag_motion), (gpointer) this );
440
d6086ea6 441 gtk_signal_connect( GTK_OBJECT(widget), "drag_drop",
33a5bc52
RR
442 GTK_SIGNAL_FUNC(target_drag_drop), (gpointer) this );
443
d6086ea6 444 gtk_signal_connect( GTK_OBJECT(widget), "drag_data_received",
33a5bc52 445 GTK_SIGNAL_FUNC(target_drag_data_received), (gpointer) this );
f5368809
RR
446}
447
d6086ea6 448//-------------------------------------------------------------------------
f5368809 449// wxTextDropTarget
d6086ea6 450//-------------------------------------------------------------------------
f5368809 451
d6086ea6 452bool wxTextDropTarget::OnMove( int WXUNUSED(x), int WXUNUSED(y) )
f5368809 453{
5af019af 454 return IsSupported( wxDF_TEXT );
f5368809
RR
455}
456
5af019af 457bool wxTextDropTarget::OnDrop( int WXUNUSED(x), int WXUNUSED(y) )
f5368809 458{
5af019af
RR
459 if (IsSupported( wxDF_TEXT ))
460 {
461 RequestData( wxDF_TEXT );
462 return TRUE;
463 }
829e3e8d 464
5af019af
RR
465 return FALSE;
466}
467
468bool wxTextDropTarget::OnData( int x, int y )
469{
d6086ea6
RR
470 wxTextDataObject data;
471 if (!GetData( &data )) return FALSE;
f5368809 472
93c5dd39 473 OnDropText( x, y, data.GetText().mbc_str() );
5af019af 474
829e3e8d 475 return TRUE;
f5368809
RR
476}
477
478//-------------------------------------------------------------------------
d6086ea6 479// wxPrivateDropTarget
f5368809
RR
480//-------------------------------------------------------------------------
481
d6086ea6 482wxPrivateDropTarget::wxPrivateDropTarget()
f5368809 483{
d6086ea6 484 m_id = wxTheApp->GetAppName();
f5368809
RR
485}
486
d6086ea6 487wxPrivateDropTarget::wxPrivateDropTarget( const wxString &id )
f5368809 488{
d6086ea6 489 m_id = id;
f5368809
RR
490}
491
d6086ea6 492bool wxPrivateDropTarget::OnMove( int WXUNUSED(x), int WXUNUSED(y) )
f5368809 493{
d6086ea6 494 return IsSupported( m_id );
f5368809
RR
495}
496
5af019af
RR
497bool wxPrivateDropTarget::OnDrop( int WXUNUSED(x), int WXUNUSED(y) )
498{
499 if (!IsSupported( m_id ))
500 {
501 RequestData( m_id );
502 return FALSE;
503 }
504
505 return FALSE;
506}
507
508bool wxPrivateDropTarget::OnData( int x, int y )
f5368809 509{
d6086ea6 510 if (!IsSupported( m_id )) return FALSE;
829e3e8d 511
d6086ea6
RR
512 wxPrivateDataObject data;
513 if (!GetData( &data )) return FALSE;
514
829e3e8d
RR
515 OnDropData( x, y, data.GetData(), data.GetSize() );
516
517 return TRUE;
f5368809 518}
d6086ea6
RR
519
520//----------------------------------------------------------------------------
521// A drop target which accepts files (dragged from File Manager or Explorer)
522//----------------------------------------------------------------------------
523
524bool wxFileDropTarget::OnMove( int WXUNUSED(x), int WXUNUSED(y) )
f5368809 525{
5af019af 526 return IsSupported( wxDF_FILENAME );
f5368809
RR
527}
528
d6086ea6 529bool wxFileDropTarget::OnDrop( int x, int y )
f5368809 530{
5af019af
RR
531 if (IsSupported( wxDF_FILENAME ))
532 {
533 RequestData( wxDF_FILENAME );
534 return TRUE;
535 }
536
537 return FALSE;
829e3e8d
RR
538}
539
5af019af 540bool wxFileDropTarget::OnData( int x, int y )
829e3e8d 541{
d6086ea6 542 wxFileDataObject data;
5af019af 543 if (!GetData( &data )) return FALSE;
d6086ea6
RR
544
545 /* get number of substrings /root/mytext.txt/0/root/myothertext.txt/0/0 */
546 size_t number = 0;
547 size_t i;
548 size_t size = data.GetFiles().Length();
93c5dd39 549 wxChar *text = WXSTRINGCAST data.GetFiles();
d6086ea6
RR
550 for ( i = 0; i < size; i++)
551 if (text[i] == 0) number++;
552
5af019af 553 if (number == 0) return FALSE;
f5368809 554
93c5dd39 555 wxChar **files = new wxChar*[number];
f5368809 556
d6086ea6
RR
557 text = WXSTRINGCAST data.GetFiles();
558 for (i = 0; i < number; i++)
f5368809 559 {
d6086ea6 560 files[i] = text;
93c5dd39 561 int len = wxStrlen( text );
d6086ea6 562 text += len+1;
f5368809 563 }
f5368809 564
829e3e8d 565 OnDropFiles( x, y, number, files );
d6086ea6
RR
566
567 free( files );
5af019af
RR
568
569 return TRUE;
f5368809
RR
570}
571
4ba47b40
RR
572//----------------------------------------------------------------------------
573// "drag_data_get"
574//----------------------------------------------------------------------------
575
576static void
577source_drag_data_get (GtkWidget *WXUNUSED(widget),
578 GdkDragContext *context,
579 GtkSelectionData *selection_data,
580 guint WXUNUSED(info),
581 guint WXUNUSED(time),
582 wxDropSource *drop_source )
583{
5af019af
RR
584// char *name = gdk_atom_name( selection_data->target );
585// if (name) printf( "Format requested: %s.\n", name );
4ba47b40
RR
586
587 wxNode *node = drop_source->m_data->m_dataObjects.First();
588 while (node)
589 {
590 wxDataObject *data_object = (wxDataObject*) node->Data();
591 if (data_object->GetFormat().GetAtom() == selection_data->target)
592 {
593 size_t data_size = data_object->GetSize();
594 if (data_size > 0)
595 {
596 guchar *buffer = new guchar[data_size];
597 data_object->WriteData( buffer );
598
599 gtk_selection_data_set( selection_data,
600 selection_data->target,
601 8, /* 8-bit */
602 buffer,
603 data_size );
604
605 free( buffer );
606
607 /* so far only copy, no moves. TODO. */
608 drop_source->m_retValue = wxDragCopy;
609
610 return;
611 }
612 }
613
614 node = node->Next();
615 }
616
617 drop_source->m_retValue = wxDragCancel;
618}
619
620//----------------------------------------------------------------------------
621// "drag_data_delete"
622//----------------------------------------------------------------------------
623
624static void source_drag_data_delete( GtkWidget *WXUNUSED(widget),
625 GdkDragContext *WXUNUSED(context),
626 wxDropSource *drop_source )
627{
628// printf( "Delete the data!\n" );
33a5bc52 629
4ba47b40
RR
630 drop_source->m_retValue = wxDragMove;
631}
632
633//----------------------------------------------------------------------------
634// "drag_begin"
635//----------------------------------------------------------------------------
636
637static void source_drag_begin( GtkWidget *WXUNUSED(widget),
638 GdkDragContext *WXUNUSED(context),
639 wxDropSource *WXUNUSED(drop_source) )
640{
641// printf( "drag_begin.\n" );
642}
643
644//----------------------------------------------------------------------------
645// "drag_end"
646//----------------------------------------------------------------------------
647
648static void source_drag_end( GtkWidget *WXUNUSED(widget),
649 GdkDragContext *WXUNUSED(context),
650 wxDropSource *drop_source )
651{
652// printf( "drag_end.\n" );
653
654 drop_source->m_waiting = FALSE;
655}
656
657//---------------------------------------------------------------------------
658// wxDropSource
659//---------------------------------------------------------------------------
22d5903e
RR
660
661wxDropSource::wxDropSource( wxWindow *win, const wxIcon &go, const wxIcon &stop )
662{
663 g_blockEventsOnDrag = TRUE;
4ba47b40 664 m_waiting = TRUE;
22d5903e
RR
665
666 m_window = win;
667 m_widget = win->m_widget;
668 if (win->m_wxwindow) m_widget = win->m_wxwindow;
669
670 m_data = (wxDataBroker*) NULL;
671 m_retValue = wxDragCancel;
672
673 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
674 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
675
676 m_goIcon = go;
677 if (wxNullIcon == go) m_goIcon = wxIcon( page_xpm );
678 m_stopIcon = stop;
679 if (wxNullIcon == stop) m_stopIcon = wxIcon( gv_xpm );
680}
681
682wxDropSource::wxDropSource( wxDataObject *data, wxWindow *win, const wxIcon &go, const wxIcon &stop )
683{
4ba47b40 684 m_waiting = TRUE;
22d5903e
RR
685
686 m_window = win;
687 m_widget = win->m_widget;
688 if (win->m_wxwindow) m_widget = win->m_wxwindow;
689 m_retValue = wxDragCancel;
690
691 if (data)
692 {
693 m_data = new wxDataBroker();
694 m_data->Add( data );
695 }
696 else
697 {
698 m_data = (wxDataBroker*) NULL;
699 }
700
701 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
702 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
703
704 m_goIcon = go;
705 if (wxNullIcon == go) m_goIcon = wxIcon( page_xpm );
706 m_stopIcon = stop;
707 if (wxNullIcon == stop) m_stopIcon = wxIcon( gv_xpm );
708}
709
710wxDropSource::wxDropSource( wxDataBroker *data, wxWindow *win )
711{
22d5903e
RR
712 m_window = win;
713 m_widget = win->m_widget;
714 if (win->m_wxwindow) m_widget = win->m_wxwindow;
715 m_retValue = wxDragCancel;
716
717 m_data = data;
718
719 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
720 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
721}
722
723void wxDropSource::SetData( wxDataObject *data )
724{
725 if (m_data) delete m_data;
726
727 if (data)
728 {
729 m_data = new wxDataBroker();
730 m_data->Add( data );
731 }
732 else
733 {
734 m_data = (wxDataBroker*) NULL;
735 }
736}
737
738void wxDropSource::SetData( wxDataBroker *data )
739{
740 if (m_data) delete m_data;
741
742 m_data = data;
743}
744
745wxDropSource::~wxDropSource(void)
746{
747 if (m_data) delete m_data;
748
749 g_blockEventsOnDrag = FALSE;
750}
751
752wxDragResult wxDropSource::DoDragDrop( bool WXUNUSED(bAllowMove) )
753{
93c5dd39 754 wxASSERT_MSG( m_data, _T("wxDragSource: no data") );
22d5903e
RR
755
756 if (!m_data) return (wxDragResult) wxDragNone;
757
4ba47b40
RR
758 g_blockEventsOnDrag = TRUE;
759
760 RegisterWindow();
761
762 m_waiting = TRUE;
22d5903e 763
4ba47b40
RR
764 GtkTargetList *target_list = gtk_target_list_new( (GtkTargetEntry*) NULL, 0 );
765 gtk_target_list_add( target_list, gdk_atom_intern( "STRING", FALSE ), 0, 0 );
766
767 GdkEventMotion event;
768 event.window = m_widget->window;
769 int x = 0;
770 int y = 0;
771 GdkModifierType state;
772 gdk_window_get_pointer( event.window, &x, &y, &state );
773 event.x = x;
774 event.y = y;
775 event.state = state;
776
777 /* GTK wants to know which button was pressed which caused the dragging */
778 int button_number = 0;
779 if (event.state & GDK_BUTTON1_MASK) button_number = 1;
780 else if (event.state & GDK_BUTTON2_MASK) button_number = 2;
781 else if (event.state & GDK_BUTTON3_MASK) button_number = 3;
782
783 /* don't start dragging if no button is down */
784 if (button_number)
22d5903e 785 {
4ba47b40
RR
786 GdkDragContext *context = gtk_drag_begin( m_widget,
787 target_list,
788 GDK_ACTION_COPY,
789 button_number, /* number of mouse button which started drag */
790 (GdkEvent*) &event );
22d5903e 791
4ba47b40
RR
792 wxMask *mask = m_goIcon.GetMask();
793 GdkBitmap *bm = (GdkBitmap *) NULL;
794 if (mask) bm = mask->GetBitmap();
795 GdkPixmap *pm = m_goIcon.GetPixmap();
22d5903e 796
4ba47b40
RR
797 gtk_drag_set_icon_pixmap( context,
798 gtk_widget_get_colormap( m_widget ),
799 pm,
800 bm,
801 0,
802 0 );
803
5af019af
RR
804 gdk_flush();
805
4ba47b40
RR
806 while (m_waiting) wxYield();
807 }
22d5903e 808
4ba47b40
RR
809 g_blockEventsOnDrag = FALSE;
810
811 UnregisterWindow();
812
813 return m_retValue;
22d5903e
RR
814}
815
4ba47b40 816void wxDropSource::RegisterWindow()
22d5903e 817{
4ba47b40
RR
818 if (!m_widget) return;
819
820 gtk_signal_connect( GTK_OBJECT(m_widget), "drag_data_get",
821 GTK_SIGNAL_FUNC (source_drag_data_get), (gpointer) this);
822 gtk_signal_connect (GTK_OBJECT(m_widget), "drag_data_delete",
823 GTK_SIGNAL_FUNC (source_drag_data_delete), (gpointer) this );
824 gtk_signal_connect (GTK_OBJECT(m_widget), "drag_begin",
825 GTK_SIGNAL_FUNC (source_drag_begin), (gpointer) this );
826 gtk_signal_connect (GTK_OBJECT(m_widget), "drag_end",
827 GTK_SIGNAL_FUNC (source_drag_end), (gpointer) this );
828
22d5903e
RR
829}
830
4ba47b40 831void wxDropSource::UnregisterWindow()
22d5903e
RR
832{
833 if (!m_widget) return;
4ba47b40
RR
834
835 gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget),
836 GTK_SIGNAL_FUNC(source_drag_data_get), (gpointer) this );
837 gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget),
838 GTK_SIGNAL_FUNC(source_drag_data_delete), (gpointer) this );
839 gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget),
840 GTK_SIGNAL_FUNC(source_drag_begin), (gpointer) this );
841 gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget),
842 GTK_SIGNAL_FUNC(source_drag_end), (gpointer) this );
22d5903e
RR
843}
844
ac57418f
RR
845#endif
846
93c5dd39 847 // wxUSE_DRAG_AND_DROP