]> git.saurik.com Git - wxWidgets.git/blame - src/gtk1/dnd.cpp
Fixed wxZlibOutputStream::Sync
[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
RR
369/*
370 wxPrintf( _T("format: %s.\n"), format.GetId().c_str() );
371 if (format.GetType() == wxDF_PRIVATE) wxPrintf( _T("private data.\n") );
372 if (format.GetType() == wxDF_TEXT) wxPrintf( _T("text data.\n") );
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{
93c5dd39 440 wxCHECK_RET( widget != NULL, _T("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{
93c5dd39 459 wxCHECK_RET( widget != NULL, _T("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
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
748wxDropSource::wxDropSource( wxDataObject *data, wxWindow *win, const wxIcon &go, const wxIcon &stop )
749{
4ba47b40 750 m_waiting = TRUE;
f03fc89f 751
22d5903e 752 m_window = win;
a2053b27
RR
753 m_widget = win->m_widget;
754 if (win->m_wxwindow) m_widget = win->m_wxwindow;
22d5903e 755 m_retValue = wxDragCancel;
f03fc89f 756
22d5903e
RR
757 if (data)
758 {
759 m_data = new wxDataBroker();
f03fc89f 760 m_data->Add( data );
22d5903e
RR
761 }
762 else
763 {
764 m_data = (wxDataBroker*) NULL;
765 }
766
767 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
768 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
f03fc89f 769
22d5903e
RR
770 m_goIcon = go;
771 if (wxNullIcon == go) m_goIcon = wxIcon( page_xpm );
772 m_stopIcon = stop;
773 if (wxNullIcon == stop) m_stopIcon = wxIcon( gv_xpm );
774}
775
776wxDropSource::wxDropSource( wxDataBroker *data, wxWindow *win )
777{
22d5903e 778 m_window = win;
a2053b27
RR
779 m_widget = win->m_widget;
780 if (win->m_wxwindow) m_widget = win->m_wxwindow;
22d5903e 781 m_retValue = wxDragCancel;
f03fc89f 782
22d5903e
RR
783 m_data = data;
784
785 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
786 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
787}
788
789void wxDropSource::SetData( wxDataObject *data )
790{
791 if (m_data) delete m_data;
f03fc89f 792
22d5903e
RR
793 if (data)
794 {
795 m_data = new wxDataBroker();
f03fc89f 796 m_data->Add( data );
22d5903e
RR
797 }
798 else
799 {
800 m_data = (wxDataBroker*) NULL;
801 }
802}
803
804void wxDropSource::SetData( wxDataBroker *data )
805{
806 if (m_data) delete m_data;
f03fc89f 807
22d5903e
RR
808 m_data = data;
809}
810
811wxDropSource::~wxDropSource(void)
812{
813 if (m_data) delete m_data;
814
815 g_blockEventsOnDrag = FALSE;
816}
f03fc89f 817
22d5903e
RR
818wxDragResult wxDropSource::DoDragDrop( bool WXUNUSED(bAllowMove) )
819{
93c5dd39 820 wxASSERT_MSG( m_data, _T("wxDragSource: no data") );
f03fc89f 821
22d5903e 822 if (!m_data) return (wxDragResult) wxDragNone;
f03fc89f 823
4ba47b40 824 g_blockEventsOnDrag = TRUE;
f03fc89f 825
4ba47b40 826 RegisterWindow();
f03fc89f 827
4ba47b40 828 m_waiting = TRUE;
22d5903e 829
19da4326 830 GdkAtom atom = gdk_atom_intern( "STRING", FALSE );
b453e1b2 831// printf( "atom id: %d.\n", (int)atom );
19da4326 832
4ba47b40 833 GtkTargetList *target_list = gtk_target_list_new( (GtkTargetEntry*) NULL, 0 );
19da4326 834 gtk_target_list_add( target_list, atom, 0, 0 );
f03fc89f 835
4ba47b40
RR
836 GdkEventMotion event;
837 event.window = m_widget->window;
838 int x = 0;
839 int y = 0;
840 GdkModifierType state;
841 gdk_window_get_pointer( event.window, &x, &y, &state );
842 event.x = x;
843 event.y = y;
844 event.state = state;
19da4326 845 event.time = GDK_CURRENT_TIME;
f03fc89f 846
4ba47b40
RR
847 /* GTK wants to know which button was pressed which caused the dragging */
848 int button_number = 0;
849 if (event.state & GDK_BUTTON1_MASK) button_number = 1;
850 else if (event.state & GDK_BUTTON2_MASK) button_number = 2;
851 else if (event.state & GDK_BUTTON3_MASK) button_number = 3;
852
b453e1b2
RR
853#if wxUSE_THREADS
854 /* disable GUI threads */
855 wxapp_uninstall_thread_wakeup();
856#endif
857
4ba47b40
RR
858 /* don't start dragging if no button is down */
859 if (button_number)
22d5903e 860 {
4ba47b40
RR
861 GdkDragContext *context = gtk_drag_begin( m_widget,
862 target_list,
f03fc89f
VZ
863 GDK_ACTION_COPY,
864 button_number, /* number of mouse button which started drag */
865 (GdkEvent*) &event );
866
4ba47b40
RR
867 wxMask *mask = m_goIcon.GetMask();
868 GdkBitmap *bm = (GdkBitmap *) NULL;
869 if (mask) bm = mask->GetBitmap();
f03fc89f
VZ
870 GdkPixmap *pm = m_goIcon.GetPixmap();
871
4ba47b40 872 gtk_drag_set_icon_pixmap( context,
f03fc89f
VZ
873 gtk_widget_get_colormap( m_widget ),
874 pm,
875 bm,
876 0,
877 0 );
878
19da4326 879 while (m_waiting) gtk_main_iteration();;
4ba47b40 880 }
22d5903e 881
b453e1b2
RR
882#if wxUSE_THREADS
883 /* re-enable GUI threads */
884 wxapp_install_thread_wakeup();
885#endif
886
4ba47b40 887 g_blockEventsOnDrag = FALSE;
f03fc89f 888
4ba47b40
RR
889 UnregisterWindow();
890
891 return m_retValue;
22d5903e
RR
892}
893
4ba47b40 894void wxDropSource::RegisterWindow()
22d5903e 895{
4ba47b40 896 if (!m_widget) return;
f03fc89f 897
4ba47b40 898 gtk_signal_connect( GTK_OBJECT(m_widget), "drag_data_get",
f03fc89f 899 GTK_SIGNAL_FUNC (source_drag_data_get), (gpointer) this);
4ba47b40 900 gtk_signal_connect (GTK_OBJECT(m_widget), "drag_data_delete",
f03fc89f 901 GTK_SIGNAL_FUNC (source_drag_data_delete), (gpointer) this );
4ba47b40 902 gtk_signal_connect (GTK_OBJECT(m_widget), "drag_begin",
f03fc89f 903 GTK_SIGNAL_FUNC (source_drag_begin), (gpointer) this );
4ba47b40 904 gtk_signal_connect (GTK_OBJECT(m_widget), "drag_end",
f03fc89f 905 GTK_SIGNAL_FUNC (source_drag_end), (gpointer) this );
4ba47b40 906
22d5903e
RR
907}
908
4ba47b40 909void wxDropSource::UnregisterWindow()
22d5903e
RR
910{
911 if (!m_widget) return;
f03fc89f 912
4ba47b40 913 gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget),
f03fc89f 914 GTK_SIGNAL_FUNC(source_drag_data_get), (gpointer) this );
4ba47b40 915 gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget),
f03fc89f 916 GTK_SIGNAL_FUNC(source_drag_data_delete), (gpointer) this );
4ba47b40 917 gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget),
f03fc89f 918 GTK_SIGNAL_FUNC(source_drag_begin), (gpointer) this );
4ba47b40 919 gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget),
f03fc89f 920 GTK_SIGNAL_FUNC(source_drag_end), (gpointer) this );
22d5903e
RR
921}
922
ac57418f
RR
923#endif
924
93c5dd39 925 // wxUSE_DRAG_AND_DROP