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