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