]> git.saurik.com Git - wxWidgets.git/blame - src/gtk1/dnd.cpp
Added size hints to dialog,
[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,
1dd989e1 383 format,
f03fc89f
VZ
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
1dd989e1 406 if (formatAtom == format) 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
1dd989e1 417 if (m_dragData->target != data_object->GetFormat()) 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
1dd989e1 524/*
d6086ea6 525wxPrivateDropTarget::wxPrivateDropTarget()
f5368809 526{
d6086ea6 527 m_id = wxTheApp->GetAppName();
f5368809
RR
528}
529
d6086ea6 530wxPrivateDropTarget::wxPrivateDropTarget( const wxString &id )
f5368809 531{
d6086ea6 532 m_id = id;
f5368809
RR
533}
534
8dbf4589 535bool wxPrivateDropTarget::OnMove( long WXUNUSED(x), long WXUNUSED(y) )
f5368809 536{
d6086ea6 537 return IsSupported( m_id );
f5368809
RR
538}
539
8dbf4589 540bool wxPrivateDropTarget::OnDrop( long WXUNUSED(x), long WXUNUSED(y) )
5af019af
RR
541{
542 if (!IsSupported( m_id ))
f03fc89f 543 {
5af019af
RR
544 RequestData( m_id );
545 return FALSE;
546 }
f03fc89f 547
5af019af
RR
548 return FALSE;
549}
550
8dbf4589 551bool wxPrivateDropTarget::OnData( long x, long y )
f5368809 552{
d6086ea6 553 if (!IsSupported( m_id )) return FALSE;
f03fc89f 554
d6086ea6
RR
555 wxPrivateDataObject data;
556 if (!GetData( &data )) return FALSE;
f03fc89f 557
829e3e8d 558 OnDropData( x, y, data.GetData(), data.GetSize() );
f03fc89f 559
829e3e8d 560 return TRUE;
f5368809 561}
1dd989e1 562*/
d6086ea6
RR
563
564//----------------------------------------------------------------------------
565// A drop target which accepts files (dragged from File Manager or Explorer)
566//----------------------------------------------------------------------------
567
8dbf4589 568bool wxFileDropTarget::OnMove( long WXUNUSED(x), long WXUNUSED(y) )
f5368809 569{
5af019af 570 return IsSupported( wxDF_FILENAME );
f5368809
RR
571}
572
8dbf4589 573bool wxFileDropTarget::OnDrop( long x, long y )
f5368809 574{
5af019af
RR
575 if (IsSupported( wxDF_FILENAME ))
576 {
577 RequestData( wxDF_FILENAME );
f03fc89f 578 return TRUE;
5af019af 579 }
f03fc89f 580
5af019af 581 return FALSE;
829e3e8d
RR
582}
583
8dbf4589 584bool wxFileDropTarget::OnData( long x, long y )
829e3e8d 585{
d6086ea6 586 wxFileDataObject data;
5af019af 587 if (!GetData( &data )) return FALSE;
d6086ea6 588
1dd989e1 589 // get number of substrings /root/mytext.txt/0/root/myothertext.txt/0/0
d6086ea6
RR
590 size_t number = 0;
591 size_t i;
592 size_t size = data.GetFiles().Length();
93c5dd39 593 wxChar *text = WXSTRINGCAST data.GetFiles();
d6086ea6
RR
594 for ( i = 0; i < size; i++)
595 if (text[i] == 0) number++;
596
5af019af 597 if (number == 0) return FALSE;
f03fc89f 598
93c5dd39 599 wxChar **files = new wxChar*[number];
f03fc89f 600
d6086ea6
RR
601 text = WXSTRINGCAST data.GetFiles();
602 for (i = 0; i < number; i++)
f5368809 603 {
d6086ea6 604 files[i] = text;
93c5dd39 605 int len = wxStrlen( text );
d6086ea6 606 text += len+1;
f5368809 607 }
f5368809 608
f03fc89f
VZ
609 OnDropFiles( x, y, number, files );
610
d6086ea6 611 free( files );
f03fc89f 612
5af019af 613 return TRUE;
f5368809
RR
614}
615
4ba47b40
RR
616//----------------------------------------------------------------------------
617// "drag_data_get"
618//----------------------------------------------------------------------------
619
f03fc89f 620static void
4ba47b40 621source_drag_data_get (GtkWidget *WXUNUSED(widget),
f03fc89f
VZ
622 GdkDragContext *context,
623 GtkSelectionData *selection_data,
624 guint WXUNUSED(info),
625 guint WXUNUSED(time),
626 wxDropSource *drop_source )
4ba47b40 627{
5549fa65
RR
628 if (g_isIdle) wxapp_install_idle_handler();
629
90e58684
RR
630// printf( "Provide data!\n" );
631
5af019af
RR
632// char *name = gdk_atom_name( selection_data->target );
633// if (name) printf( "Format requested: %s.\n", name );
f03fc89f 634
1dd989e1
RR
635 drop_source->m_retValue = wxDragCancel;
636
637 wxDataObject *data = drop_source->m_data;
638
639 if (!data)
640 return;
641
642 if (!data->IsSupportedFormat(selection_data->target))
643 return;
f03fc89f 644
1dd989e1
RR
645 if (data->GetDataSize(selection_data->target) == 0)
646 return;
647
648 size_t size = data->GetDataSize(selection_data->target);
f03fc89f 649
1dd989e1 650// printf( "data size: %d.\n", (int)data_size );
f03fc89f 651
1dd989e1
RR
652 guchar *d = new guchar[size];
653
654 if (!data->GetDataHere( selection_data->target, (void*)d ))
655 {
656 free( d );
657 return;
658 }
f03fc89f 659
b453e1b2 660#if wxUSE_THREADS
1dd989e1
RR
661 /* disable GUI threads */
662 wxapp_uninstall_thread_wakeup();
b453e1b2 663#endif
8e193f38 664
4ba47b40 665 gtk_selection_data_set( selection_data,
f03fc89f
VZ
666 selection_data->target,
667 8, // 8-bit
1dd989e1
RR
668 d,
669 size );
f03fc89f 670
b453e1b2 671#if wxUSE_THREADS
1dd989e1
RR
672 /* enable GUI threads */
673 wxapp_install_thread_wakeup();
b453e1b2 674#endif
f03fc89f 675
1dd989e1
RR
676 free( d );
677
678 /* so far only copy, no moves. TODO. */
679 drop_source->m_retValue = wxDragCopy;
4ba47b40 680}
f03fc89f 681
4ba47b40
RR
682//----------------------------------------------------------------------------
683// "drag_data_delete"
684//----------------------------------------------------------------------------
685
686static void source_drag_data_delete( GtkWidget *WXUNUSED(widget),
f03fc89f
VZ
687 GdkDragContext *WXUNUSED(context),
688 wxDropSource *drop_source )
4ba47b40 689{
5549fa65
RR
690 if (g_isIdle) wxapp_install_idle_handler();
691
b453e1b2 692// printf( "Delete the data!\n" );
33a5bc52 693
4ba47b40
RR
694 drop_source->m_retValue = wxDragMove;
695}
f03fc89f 696
4ba47b40
RR
697//----------------------------------------------------------------------------
698// "drag_begin"
699//----------------------------------------------------------------------------
700
701static void source_drag_begin( GtkWidget *WXUNUSED(widget),
f03fc89f
VZ
702 GdkDragContext *WXUNUSED(context),
703 wxDropSource *WXUNUSED(drop_source) )
4ba47b40 704{
5549fa65
RR
705 if (g_isIdle) wxapp_install_idle_handler();
706
b453e1b2 707// printf( "drag_begin.\n" );
4ba47b40 708}
f03fc89f 709
4ba47b40
RR
710//----------------------------------------------------------------------------
711// "drag_end"
712//----------------------------------------------------------------------------
713
714static void source_drag_end( GtkWidget *WXUNUSED(widget),
f03fc89f
VZ
715 GdkDragContext *WXUNUSED(context),
716 wxDropSource *drop_source )
4ba47b40 717{
5549fa65
RR
718 if (g_isIdle) wxapp_install_idle_handler();
719
b453e1b2 720// printf( "drag_end.\n" );
4ba47b40
RR
721
722 drop_source->m_waiting = FALSE;
723}
f03fc89f 724
4ba47b40
RR
725//---------------------------------------------------------------------------
726// wxDropSource
727//---------------------------------------------------------------------------
22d5903e
RR
728
729wxDropSource::wxDropSource( wxWindow *win, const wxIcon &go, const wxIcon &stop )
730{
731 g_blockEventsOnDrag = TRUE;
4ba47b40 732 m_waiting = TRUE;
f03fc89f 733
22d5903e 734 m_window = win;
a2053b27
RR
735 m_widget = win->m_widget;
736 if (win->m_wxwindow) m_widget = win->m_wxwindow;
f03fc89f 737
1dd989e1 738 m_data = (wxDataObject*) NULL;
22d5903e
RR
739 m_retValue = wxDragCancel;
740
741 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
742 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
f03fc89f 743
22d5903e
RR
744 m_goIcon = go;
745 if (wxNullIcon == go) m_goIcon = wxIcon( page_xpm );
746 m_stopIcon = stop;
747 if (wxNullIcon == stop) m_stopIcon = wxIcon( gv_xpm );
748}
749
8e193f38
VZ
750wxDropSource::wxDropSource( wxDataObject& data, wxWindow *win,
751 const wxIcon &go, const wxIcon &stop )
22d5903e 752{
4ba47b40 753 m_waiting = TRUE;
f03fc89f 754
22d5903e 755 m_window = win;
a2053b27
RR
756 m_widget = win->m_widget;
757 if (win->m_wxwindow) m_widget = win->m_wxwindow;
22d5903e 758 m_retValue = wxDragCancel;
f03fc89f 759
1dd989e1 760 m_data = &data;
22d5903e
RR
761
762 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
763 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
f03fc89f 764
22d5903e
RR
765 m_goIcon = go;
766 if (wxNullIcon == go) m_goIcon = wxIcon( page_xpm );
767 m_stopIcon = stop;
768 if (wxNullIcon == stop) m_stopIcon = wxIcon( gv_xpm );
769}
770
8e193f38
VZ
771void wxDropSource::SetData( wxDataObject& data )
772{
1dd989e1 773 if (m_data)
8e193f38
VZ
774 delete m_data;
775
1dd989e1 776 m_data = &data;
22d5903e
RR
777}
778
8e193f38 779wxDropSource::~wxDropSource()
22d5903e 780{
1dd989e1
RR
781 if (m_data)
782// delete m_data;
22d5903e
RR
783
784 g_blockEventsOnDrag = FALSE;
785}
f03fc89f 786
22d5903e
RR
787wxDragResult wxDropSource::DoDragDrop( bool WXUNUSED(bAllowMove) )
788{
223d09f6 789 wxASSERT_MSG( m_data, wxT("wxDragSource: no data") );
f03fc89f 790
22d5903e 791 if (!m_data) return (wxDragResult) wxDragNone;
f03fc89f 792
4ba47b40 793 g_blockEventsOnDrag = TRUE;
f03fc89f 794
4ba47b40 795 RegisterWindow();
f03fc89f 796
4ba47b40 797 m_waiting = TRUE;
22d5903e 798
19da4326 799 GdkAtom atom = gdk_atom_intern( "STRING", FALSE );
b453e1b2 800// printf( "atom id: %d.\n", (int)atom );
19da4326 801
4ba47b40 802 GtkTargetList *target_list = gtk_target_list_new( (GtkTargetEntry*) NULL, 0 );
19da4326 803 gtk_target_list_add( target_list, atom, 0, 0 );
f03fc89f 804
4ba47b40
RR
805 GdkEventMotion event;
806 event.window = m_widget->window;
807 int x = 0;
808 int y = 0;
809 GdkModifierType state;
810 gdk_window_get_pointer( event.window, &x, &y, &state );
811 event.x = x;
812 event.y = y;
813 event.state = state;
19da4326 814 event.time = GDK_CURRENT_TIME;
f03fc89f 815
4ba47b40
RR
816 /* GTK wants to know which button was pressed which caused the dragging */
817 int button_number = 0;
818 if (event.state & GDK_BUTTON1_MASK) button_number = 1;
819 else if (event.state & GDK_BUTTON2_MASK) button_number = 2;
820 else if (event.state & GDK_BUTTON3_MASK) button_number = 3;
821
b453e1b2
RR
822#if wxUSE_THREADS
823 /* disable GUI threads */
824 wxapp_uninstall_thread_wakeup();
825#endif
8e193f38 826
4ba47b40
RR
827 /* don't start dragging if no button is down */
828 if (button_number)
22d5903e 829 {
4ba47b40
RR
830 GdkDragContext *context = gtk_drag_begin( m_widget,
831 target_list,
f03fc89f
VZ
832 GDK_ACTION_COPY,
833 button_number, /* number of mouse button which started drag */
834 (GdkEvent*) &event );
835
4ba47b40
RR
836 wxMask *mask = m_goIcon.GetMask();
837 GdkBitmap *bm = (GdkBitmap *) NULL;
838 if (mask) bm = mask->GetBitmap();
f03fc89f
VZ
839 GdkPixmap *pm = m_goIcon.GetPixmap();
840
4ba47b40 841 gtk_drag_set_icon_pixmap( context,
f03fc89f
VZ
842 gtk_widget_get_colormap( m_widget ),
843 pm,
844 bm,
845 0,
846 0 );
847
19da4326 848 while (m_waiting) gtk_main_iteration();;
4ba47b40 849 }
22d5903e 850
b453e1b2
RR
851#if wxUSE_THREADS
852 /* re-enable GUI threads */
853 wxapp_install_thread_wakeup();
854#endif
8e193f38 855
4ba47b40 856 g_blockEventsOnDrag = FALSE;
f03fc89f 857
4ba47b40
RR
858 UnregisterWindow();
859
860 return m_retValue;
22d5903e
RR
861}
862
4ba47b40 863void wxDropSource::RegisterWindow()
22d5903e 864{
4ba47b40 865 if (!m_widget) return;
f03fc89f 866
4ba47b40 867 gtk_signal_connect( GTK_OBJECT(m_widget), "drag_data_get",
f03fc89f 868 GTK_SIGNAL_FUNC (source_drag_data_get), (gpointer) this);
4ba47b40 869 gtk_signal_connect (GTK_OBJECT(m_widget), "drag_data_delete",
f03fc89f 870 GTK_SIGNAL_FUNC (source_drag_data_delete), (gpointer) this );
4ba47b40 871 gtk_signal_connect (GTK_OBJECT(m_widget), "drag_begin",
f03fc89f 872 GTK_SIGNAL_FUNC (source_drag_begin), (gpointer) this );
4ba47b40 873 gtk_signal_connect (GTK_OBJECT(m_widget), "drag_end",
f03fc89f 874 GTK_SIGNAL_FUNC (source_drag_end), (gpointer) this );
4ba47b40 875
22d5903e
RR
876}
877
4ba47b40 878void wxDropSource::UnregisterWindow()
22d5903e
RR
879{
880 if (!m_widget) return;
f03fc89f 881
4ba47b40 882 gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget),
f03fc89f 883 GTK_SIGNAL_FUNC(source_drag_data_get), (gpointer) this );
4ba47b40 884 gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget),
f03fc89f 885 GTK_SIGNAL_FUNC(source_drag_data_delete), (gpointer) this );
4ba47b40 886 gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget),
f03fc89f 887 GTK_SIGNAL_FUNC(source_drag_begin), (gpointer) this );
4ba47b40 888 gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget),
f03fc89f 889 GTK_SIGNAL_FUNC(source_drag_end), (gpointer) this );
22d5903e
RR
890}
891
ac57418f
RR
892#endif
893
93c5dd39 894 // wxUSE_DRAG_AND_DROP