]> git.saurik.com Git - wxWidgets.git/blame - src/gtk1/dnd.cpp
*** empty log message ***
[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
8e00741d
RR
191 bool ret = FALSE;
192
829e3e8d 193 if (drop_target->m_firstMotion)
d6086ea6 194 {
829e3e8d 195 /* the first "drag_motion" event substitutes a "drag_enter" event */
8e00741d
RR
196 ret = drop_target->OnEnter( x, y );
197 }
198 else
199 {
200 /* give program a chance to react (i.e. to say no by returning FALSE) */
201 ret = drop_target->OnMove( x, y );
d6086ea6 202 }
f03fc89f 203
829e3e8d
RR
204 /* we don't yet handle which "actions" (i.e. copy or move)
205 the target accepts. so far we simply accept the
206 suggested action. TODO. */
207 if (ret)
208 gdk_drag_status( context, context->suggested_action, time );
f03fc89f 209
829e3e8d
RR
210 /* after this, invalidate the drop_target's GdkDragContext */
211 drop_target->SetDragContext( (GdkDragContext*) NULL );
f03fc89f 212
829e3e8d
RR
213 /* this has to be done because GDK has no "drag_enter" event */
214 drop_target->m_firstMotion = FALSE;
f03fc89f 215
829e3e8d 216 return ret;
33a5bc52
RR
217}
218
219// ----------------------------------------------------------------------------
220// "drag_drop"
221// ----------------------------------------------------------------------------
222
223static gboolean target_drag_drop( GtkWidget *widget,
f03fc89f
VZ
224 GdkDragContext *context,
225 gint x,
226 gint y,
227 guint time,
228 wxDropTarget *drop_target )
33a5bc52 229{
5549fa65
RR
230 if (g_isIdle) wxapp_install_idle_handler();
231
829e3e8d
RR
232 /* Owen Taylor: "if the drop is not in a drop zone,
233 return FALSE, otherwise, if you aren't accepting
234 the drop, call gtk_drag_finish() with success == FALSE
235 otherwise call gtk_drag_data_get()" */
4ba47b40
RR
236
237// printf( "drop.\n" );
f03fc89f 238
829e3e8d
RR
239 /* this seems to make a difference between not accepting
240 due to wrong target area and due to wrong format. let
241 us hope that this is not required.. */
f03fc89f 242
829e3e8d
RR
243 /* inform the wxDropTarget about the current GdkDragContext.
244 this is only valid for the duration of this call */
245 drop_target->SetDragContext( context );
f03fc89f 246
829e3e8d
RR
247 /* inform the wxDropTarget about the current drag widget.
248 this is only valid for the duration of this call */
249 drop_target->SetDragWidget( widget );
f03fc89f 250
829e3e8d
RR
251 /* inform the wxDropTarget about the current drag time.
252 this is only valid for the duration of this call */
253 drop_target->SetDragTime( time );
f03fc89f 254
829e3e8d 255 bool ret = drop_target->OnDrop( x, y );
f03fc89f 256
5af019af 257 if (!ret)
829e3e8d
RR
258 {
259 /* cancel the whole thing */
260 gtk_drag_finish( context,
f03fc89f
VZ
261 FALSE, /* no success */
262 FALSE, /* don't delete data on dropping side */
263 time );
829e3e8d 264 }
8e00741d
RR
265 else
266 {
267#if wxUSE_THREADS
268 /* disable GUI threads */
269 wxapp_uninstall_thread_wakeup();
270#endif
271
272 GdkAtom format = drop_target->GetMatchingPair();
273 wxASSERT( format );
274
275 /* this should trigger an "drag_data_received" event */
276 gtk_drag_get_data( widget,
277 context,
278 format,
279 time );
280
281#if wxUSE_THREADS
282 /* re-enable GUI threads */
283 wxapp_install_thread_wakeup();
284#endif
285 }
f03fc89f 286
829e3e8d
RR
287 /* after this, invalidate the drop_target's GdkDragContext */
288 drop_target->SetDragContext( (GdkDragContext*) NULL );
f03fc89f 289
829e3e8d
RR
290 /* after this, invalidate the drop_target's drag widget */
291 drop_target->SetDragWidget( (GtkWidget*) NULL );
f03fc89f 292
829e3e8d
RR
293 /* this has to be done because GDK has no "drag_enter" event */
294 drop_target->m_firstMotion = TRUE;
f03fc89f 295
829e3e8d 296 return ret;
33a5bc52
RR
297}
298
299// ----------------------------------------------------------------------------
300// "drag_data_received"
301// ----------------------------------------------------------------------------
302
303static void target_drag_data_received( GtkWidget *WXUNUSED(widget),
f03fc89f
VZ
304 GdkDragContext *context,
305 gint x,
306 gint y,
307 GtkSelectionData *data,
308 guint WXUNUSED(info),
309 guint time,
310 wxDropTarget *drop_target )
33a5bc52 311{
5549fa65
RR
312 if (g_isIdle) wxapp_install_idle_handler();
313
829e3e8d
RR
314 /* Owen Taylor: "call gtk_drag_finish() with
315 success == TRUE" */
316
f03fc89f 317
829e3e8d 318 if ((data->length <= 0) || (data->format != 8))
33a5bc52 319 {
829e3e8d
RR
320 /* negative data length and non 8-bit data format
321 qualifies for junk */
322 gtk_drag_finish (context, FALSE, FALSE, time);
f03fc89f 323
f03fc89f 324 return;
829e3e8d 325 }
f03fc89f 326
a3e7d24d
RR
327 wxLogDebug( wxT( "Drop target: data received") );
328
5af019af
RR
329 /* inform the wxDropTarget about the current GtkSelectionData.
330 this is only valid for the duration of this call */
331 drop_target->SetDragData( data );
f03fc89f 332
5af019af 333 if (drop_target->OnData( x, y ))
829e3e8d 334 {
f03fc89f 335 /* tell GTK that data transfer was successfull */
ab8884ac 336 gtk_drag_finish( context, TRUE, FALSE, time );
33a5bc52 337 }
5af019af
RR
338 else
339 {
f03fc89f 340 /* tell GTK that data transfer was not successfull */
5af019af
RR
341 gtk_drag_finish( context, FALSE, FALSE, time );
342 }
f03fc89f 343
5af019af
RR
344 /* after this, invalidate the drop_target's drag data */
345 drop_target->SetDragData( (GtkSelectionData*) NULL );
33a5bc52
RR
346}
347
4ba47b40 348//----------------------------------------------------------------------------
33a5bc52 349// wxDropTarget
4ba47b40 350//----------------------------------------------------------------------------
33a5bc52 351
8e00741d 352wxDropTarget::wxDropTarget( wxDataObject *data )
f5368809 353{
829e3e8d
RR
354 m_firstMotion = TRUE;
355 m_dragContext = (GdkDragContext*) NULL;
356 m_dragWidget = (GtkWidget*) NULL;
5af019af 357 m_dragData = (GtkSelectionData*) NULL;
829e3e8d 358 m_dragTime = 0;
8e00741d 359 m_data = data;
f5368809
RR
360}
361
362wxDropTarget::~wxDropTarget()
363{
364}
365
8e00741d 366bool wxDropTarget::OnEnter( int WXUNUSED(x), int WXUNUSED(y) )
d6086ea6 367{
8e00741d
RR
368 if (!m_data)
369 return FALSE;
370
371 return (GetMatchingPair() != (GdkAtom) 0);
d6086ea6
RR
372}
373
374void wxDropTarget::OnLeave()
375{
376}
377
8e00741d 378bool wxDropTarget::OnMove( int WXUNUSED(x), int WXUNUSED(y) )
d6086ea6 379{
8e00741d 380 if (!m_data)
a3e7d24d
RR
381 return FALSE;
382
8e00741d 383 return (GetMatchingPair() != (GdkAtom) 0);
d6086ea6
RR
384}
385
8e00741d 386bool wxDropTarget::OnDrop( int WXUNUSED(x), int WXUNUSED(y) )
d6086ea6 387{
8e00741d 388 if (!m_data)
a3e7d24d
RR
389 return FALSE;
390
8e00741d 391 return (GetMatchingPair() != (GdkAtom) 0);
d6086ea6
RR
392}
393
8e00741d 394bool wxDropTarget::OnData( int WXUNUSED(x), int WXUNUSED(y) )
5af019af 395{
8e00741d
RR
396 if (!m_data)
397 return FALSE;
398
399 if (GetMatchingPair() == (GdkAtom) 0)
400 return FALSE;
401
402 return GetData();
5af019af
RR
403}
404
8e00741d 405GdkAtom wxDropTarget::GetMatchingPair()
5af019af 406{
8e00741d
RR
407 if (!m_data)
408 return (GdkAtom) 0;
5af019af 409
8e00741d
RR
410 if (!m_dragContext)
411 return (GdkAtom) 0;
f03fc89f 412
22d5903e
RR
413 GList *child = m_dragContext->targets;
414 while (child)
415 {
416 GdkAtom formatAtom = (GdkAtom) GPOINTER_TO_INT(child->data);
8e00741d 417 wxDataFormat format( formatAtom );
f03fc89f 418
a3e7d24d
RR
419#ifdef __WXDEBUG__
420 char *name = gdk_atom_name( formatAtom );
421 if (name) wxLogDebug( "Drop target: drag has format: %s", name );
422#endif
8e00741d
RR
423 if (m_data->IsSupportedFormat( format ))
424 return formatAtom;
f03fc89f 425
22d5903e
RR
426 child = child->next;
427 }
829e3e8d 428
8e00741d 429 return (GdkAtom) 0;
d6086ea6 430}
f03fc89f 431
8e00741d 432bool wxDropTarget::GetData()
d6086ea6 433{
8e00741d
RR
434 if (!m_dragData)
435 return FALSE;
f03fc89f 436
8e00741d
RR
437 if (!m_data)
438 return FALSE;
f03fc89f 439
8e00741d
RR
440 wxDataFormat dragFormat( m_dragData->target );
441
442 if (!m_data->IsSupportedFormat( dragFormat ))
443 return FALSE;
f03fc89f 444
8e00741d 445 if (dragFormat.GetType() == wxDF_TEXT)
5af019af 446 {
8e00741d
RR
447 wxTextDataObject *text_object = (wxTextDataObject*)m_data;
448 text_object->SetText( (const char*)m_dragData->data );
449 return TRUE;
450 }
f03fc89f 451
8e00741d 452 if (dragFormat.GetType() == wxDF_FILENAME)
5af019af 453 {
8e00741d
RR
454 wxFileDataObject *file_object = (wxFileDataObject*)m_data;
455 file_object->SetFiles( (const char*)m_dragData->data );
456 return TRUE;
5af019af 457 }
f03fc89f 458
8e00741d 459 return FALSE;
d6086ea6 460}
f03fc89f 461
f5368809
RR
462void wxDropTarget::UnregisterWidget( GtkWidget *widget )
463{
223d09f6 464 wxCHECK_RET( widget != NULL, wxT("unregister widget is NULL") );
f03fc89f 465
829e3e8d 466 gtk_drag_dest_unset( widget );
f03fc89f 467
d6086ea6 468 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
f03fc89f 469 GTK_SIGNAL_FUNC(target_drag_leave), (gpointer) this );
33a5bc52 470
d6086ea6 471 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
f03fc89f 472 GTK_SIGNAL_FUNC(target_drag_motion), (gpointer) this );
33a5bc52 473
d6086ea6 474 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
f03fc89f 475 GTK_SIGNAL_FUNC(target_drag_drop), (gpointer) this );
33a5bc52 476
d6086ea6 477 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
f03fc89f 478 GTK_SIGNAL_FUNC(target_drag_data_received), (gpointer) this );
f5368809
RR
479}
480
481void wxDropTarget::RegisterWidget( GtkWidget *widget )
482{
223d09f6 483 wxCHECK_RET( widget != NULL, wxT("register widget is NULL") );
f03fc89f 484
829e3e8d
RR
485 /* gtk_drag_dest_set() determines what default behaviour we'd like
486 GTK to supply. we don't want to specify out targets (=formats)
487 or actions in advance (i.e. not GTK_DEST_DEFAULT_MOTION and
488 not GTK_DEST_DEFAULT_DROP). instead we react individually to
489 "drag_motion" and "drag_drop" events. this makes it possible
f03fc89f 490 to allow dropping on only a small area. we should set
829e3e8d
RR
491 GTK_DEST_DEFAULT_HIGHLIGHT as this will switch on the nice
492 highlighting if dragging over standard controls, but this
493 seems to be broken without the other two. */
f03fc89f 494
d6086ea6 495 gtk_drag_dest_set( widget,
f03fc89f
VZ
496 (GtkDestDefaults) 0, /* no default behaviour */
497 (GtkTargetEntry*) NULL, /* we don't supply any formats here */
498 0, /* number of targets = 0 */
499 (GdkDragAction) 0 ); /* we don't supply any actions here */
500
d6086ea6 501 gtk_signal_connect( GTK_OBJECT(widget), "drag_leave",
f03fc89f 502 GTK_SIGNAL_FUNC(target_drag_leave), (gpointer) this );
33a5bc52 503
d6086ea6 504 gtk_signal_connect( GTK_OBJECT(widget), "drag_motion",
f03fc89f 505 GTK_SIGNAL_FUNC(target_drag_motion), (gpointer) this );
33a5bc52 506
d6086ea6 507 gtk_signal_connect( GTK_OBJECT(widget), "drag_drop",
f03fc89f 508 GTK_SIGNAL_FUNC(target_drag_drop), (gpointer) this );
33a5bc52 509
d6086ea6 510 gtk_signal_connect( GTK_OBJECT(widget), "drag_data_received",
f03fc89f 511 GTK_SIGNAL_FUNC(target_drag_data_received), (gpointer) this );
f5368809
RR
512}
513
4ba47b40
RR
514//----------------------------------------------------------------------------
515// "drag_data_get"
516//----------------------------------------------------------------------------
517
f03fc89f 518static void
4ba47b40 519source_drag_data_get (GtkWidget *WXUNUSED(widget),
f03fc89f
VZ
520 GdkDragContext *context,
521 GtkSelectionData *selection_data,
522 guint WXUNUSED(info),
523 guint WXUNUSED(time),
524 wxDropSource *drop_source )
4ba47b40 525{
5549fa65
RR
526 if (g_isIdle) wxapp_install_idle_handler();
527
a3e7d24d
RR
528#ifdef __WXDEBUG__
529 char *name = gdk_atom_name( selection_data->target );
530 if (name) wxLogDebug( wxT("Drop source: format requested: %s"), name );
531#endif
f03fc89f 532
1dd989e1
RR
533 drop_source->m_retValue = wxDragCancel;
534
535 wxDataObject *data = drop_source->m_data;
536
537 if (!data)
538 return;
539
540 if (!data->IsSupportedFormat(selection_data->target))
541 return;
f03fc89f 542
1dd989e1
RR
543 if (data->GetDataSize(selection_data->target) == 0)
544 return;
545
546 size_t size = data->GetDataSize(selection_data->target);
f03fc89f 547
1dd989e1 548// printf( "data size: %d.\n", (int)data_size );
f03fc89f 549
1dd989e1
RR
550 guchar *d = new guchar[size];
551
552 if (!data->GetDataHere( selection_data->target, (void*)d ))
553 {
554 free( d );
555 return;
556 }
f03fc89f 557
b453e1b2 558#if wxUSE_THREADS
1dd989e1
RR
559 /* disable GUI threads */
560 wxapp_uninstall_thread_wakeup();
b453e1b2 561#endif
8e193f38 562
4ba47b40 563 gtk_selection_data_set( selection_data,
f03fc89f
VZ
564 selection_data->target,
565 8, // 8-bit
1dd989e1
RR
566 d,
567 size );
f03fc89f 568
b453e1b2 569#if wxUSE_THREADS
1dd989e1
RR
570 /* enable GUI threads */
571 wxapp_install_thread_wakeup();
b453e1b2 572#endif
f03fc89f 573
1dd989e1
RR
574 free( d );
575
576 /* so far only copy, no moves. TODO. */
577 drop_source->m_retValue = wxDragCopy;
4ba47b40 578}
f03fc89f 579
4ba47b40
RR
580//----------------------------------------------------------------------------
581// "drag_data_delete"
582//----------------------------------------------------------------------------
583
584static void source_drag_data_delete( GtkWidget *WXUNUSED(widget),
f03fc89f
VZ
585 GdkDragContext *WXUNUSED(context),
586 wxDropSource *drop_source )
4ba47b40 587{
5549fa65
RR
588 if (g_isIdle) wxapp_install_idle_handler();
589
b453e1b2 590// printf( "Delete the data!\n" );
33a5bc52 591
4ba47b40
RR
592 drop_source->m_retValue = wxDragMove;
593}
f03fc89f 594
4ba47b40
RR
595//----------------------------------------------------------------------------
596// "drag_begin"
597//----------------------------------------------------------------------------
598
599static void source_drag_begin( GtkWidget *WXUNUSED(widget),
f03fc89f
VZ
600 GdkDragContext *WXUNUSED(context),
601 wxDropSource *WXUNUSED(drop_source) )
4ba47b40 602{
5549fa65
RR
603 if (g_isIdle) wxapp_install_idle_handler();
604
b453e1b2 605// printf( "drag_begin.\n" );
4ba47b40 606}
f03fc89f 607
4ba47b40
RR
608//----------------------------------------------------------------------------
609// "drag_end"
610//----------------------------------------------------------------------------
611
612static void source_drag_end( GtkWidget *WXUNUSED(widget),
f03fc89f
VZ
613 GdkDragContext *WXUNUSED(context),
614 wxDropSource *drop_source )
4ba47b40 615{
5549fa65
RR
616 if (g_isIdle) wxapp_install_idle_handler();
617
b453e1b2 618// printf( "drag_end.\n" );
4ba47b40
RR
619
620 drop_source->m_waiting = FALSE;
621}
f03fc89f 622
4ba47b40
RR
623//---------------------------------------------------------------------------
624// wxDropSource
625//---------------------------------------------------------------------------
22d5903e
RR
626
627wxDropSource::wxDropSource( wxWindow *win, const wxIcon &go, const wxIcon &stop )
628{
629 g_blockEventsOnDrag = TRUE;
4ba47b40 630 m_waiting = TRUE;
f03fc89f 631
22d5903e 632 m_window = win;
a2053b27
RR
633 m_widget = win->m_widget;
634 if (win->m_wxwindow) m_widget = win->m_wxwindow;
f03fc89f 635
1dd989e1 636 m_data = (wxDataObject*) NULL;
22d5903e
RR
637 m_retValue = wxDragCancel;
638
639 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
640 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
f03fc89f 641
22d5903e
RR
642 m_goIcon = go;
643 if (wxNullIcon == go) m_goIcon = wxIcon( page_xpm );
644 m_stopIcon = stop;
645 if (wxNullIcon == stop) m_stopIcon = wxIcon( gv_xpm );
646}
647
8e193f38
VZ
648wxDropSource::wxDropSource( wxDataObject& data, wxWindow *win,
649 const wxIcon &go, const wxIcon &stop )
22d5903e 650{
4ba47b40 651 m_waiting = TRUE;
f03fc89f 652
22d5903e 653 m_window = win;
a2053b27
RR
654 m_widget = win->m_widget;
655 if (win->m_wxwindow) m_widget = win->m_wxwindow;
22d5903e 656 m_retValue = wxDragCancel;
f03fc89f 657
1dd989e1 658 m_data = &data;
22d5903e
RR
659
660 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
661 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
f03fc89f 662
22d5903e
RR
663 m_goIcon = go;
664 if (wxNullIcon == go) m_goIcon = wxIcon( page_xpm );
665 m_stopIcon = stop;
666 if (wxNullIcon == stop) m_stopIcon = wxIcon( gv_xpm );
667}
668
8e193f38
VZ
669void wxDropSource::SetData( wxDataObject& data )
670{
1dd989e1 671 if (m_data)
8e193f38
VZ
672 delete m_data;
673
1dd989e1 674 m_data = &data;
22d5903e
RR
675}
676
8e193f38 677wxDropSource::~wxDropSource()
22d5903e 678{
1dd989e1
RR
679 if (m_data)
680// delete m_data;
22d5903e
RR
681
682 g_blockEventsOnDrag = FALSE;
683}
f03fc89f 684
22d5903e
RR
685wxDragResult wxDropSource::DoDragDrop( bool WXUNUSED(bAllowMove) )
686{
223d09f6 687 wxASSERT_MSG( m_data, wxT("wxDragSource: no data") );
f03fc89f 688
a3e7d24d
RR
689 if (!m_data)
690 return (wxDragResult) wxDragNone;
f03fc89f 691
a3e7d24d
RR
692 if (m_data->GetFormatCount() == 0)
693 return (wxDragResult) wxDragNone;
694
4ba47b40 695 g_blockEventsOnDrag = TRUE;
f03fc89f 696
4ba47b40 697 RegisterWindow();
f03fc89f 698
4ba47b40 699 m_waiting = TRUE;
22d5903e 700
4ba47b40 701 GtkTargetList *target_list = gtk_target_list_new( (GtkTargetEntry*) NULL, 0 );
a3e7d24d
RR
702
703 wxDataFormat *array = new wxDataFormat[ m_data->GetFormatCount() ];
704 m_data->GetAllFormats( array, TRUE );
705 for (size_t i = 0; i < m_data->GetFormatCount(); i++)
706 {
707 GdkAtom atom = array[i];
708 wxLogDebug( wxT("Supported atom %s"), gdk_atom_name( atom ) );
709 gtk_target_list_add( target_list, atom, 0, 0 );
710 }
711 delete[] array;
f03fc89f 712
4ba47b40
RR
713 GdkEventMotion event;
714 event.window = m_widget->window;
715 int x = 0;
716 int y = 0;
717 GdkModifierType state;
718 gdk_window_get_pointer( event.window, &x, &y, &state );
719 event.x = x;
720 event.y = y;
721 event.state = state;
19da4326 722 event.time = GDK_CURRENT_TIME;
f03fc89f 723
4ba47b40
RR
724 /* GTK wants to know which button was pressed which caused the dragging */
725 int button_number = 0;
726 if (event.state & GDK_BUTTON1_MASK) button_number = 1;
727 else if (event.state & GDK_BUTTON2_MASK) button_number = 2;
728 else if (event.state & GDK_BUTTON3_MASK) button_number = 3;
729
b453e1b2
RR
730#if wxUSE_THREADS
731 /* disable GUI threads */
732 wxapp_uninstall_thread_wakeup();
733#endif
8e193f38 734
4ba47b40
RR
735 /* don't start dragging if no button is down */
736 if (button_number)
22d5903e 737 {
4ba47b40
RR
738 GdkDragContext *context = gtk_drag_begin( m_widget,
739 target_list,
f03fc89f
VZ
740 GDK_ACTION_COPY,
741 button_number, /* number of mouse button which started drag */
742 (GdkEvent*) &event );
743
4ba47b40
RR
744 wxMask *mask = m_goIcon.GetMask();
745 GdkBitmap *bm = (GdkBitmap *) NULL;
746 if (mask) bm = mask->GetBitmap();
f03fc89f
VZ
747 GdkPixmap *pm = m_goIcon.GetPixmap();
748
4ba47b40 749 gtk_drag_set_icon_pixmap( context,
f03fc89f
VZ
750 gtk_widget_get_colormap( m_widget ),
751 pm,
752 bm,
753 0,
754 0 );
755
19da4326 756 while (m_waiting) gtk_main_iteration();;
4ba47b40 757 }
22d5903e 758
b453e1b2
RR
759#if wxUSE_THREADS
760 /* re-enable GUI threads */
761 wxapp_install_thread_wakeup();
762#endif
8e193f38 763
4ba47b40 764 g_blockEventsOnDrag = FALSE;
f03fc89f 765
4ba47b40
RR
766 UnregisterWindow();
767
768 return m_retValue;
22d5903e
RR
769}
770
4ba47b40 771void wxDropSource::RegisterWindow()
22d5903e 772{
4ba47b40 773 if (!m_widget) return;
f03fc89f 774
4ba47b40 775 gtk_signal_connect( GTK_OBJECT(m_widget), "drag_data_get",
f03fc89f 776 GTK_SIGNAL_FUNC (source_drag_data_get), (gpointer) this);
4ba47b40 777 gtk_signal_connect (GTK_OBJECT(m_widget), "drag_data_delete",
f03fc89f 778 GTK_SIGNAL_FUNC (source_drag_data_delete), (gpointer) this );
4ba47b40 779 gtk_signal_connect (GTK_OBJECT(m_widget), "drag_begin",
f03fc89f 780 GTK_SIGNAL_FUNC (source_drag_begin), (gpointer) this );
4ba47b40 781 gtk_signal_connect (GTK_OBJECT(m_widget), "drag_end",
f03fc89f 782 GTK_SIGNAL_FUNC (source_drag_end), (gpointer) this );
4ba47b40 783
22d5903e
RR
784}
785
4ba47b40 786void wxDropSource::UnregisterWindow()
22d5903e
RR
787{
788 if (!m_widget) return;
f03fc89f 789
4ba47b40 790 gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget),
f03fc89f 791 GTK_SIGNAL_FUNC(source_drag_data_get), (gpointer) this );
4ba47b40 792 gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget),
f03fc89f 793 GTK_SIGNAL_FUNC(source_drag_data_delete), (gpointer) this );
4ba47b40 794 gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget),
f03fc89f 795 GTK_SIGNAL_FUNC(source_drag_begin), (gpointer) this );
4ba47b40 796 gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget),
f03fc89f 797 GTK_SIGNAL_FUNC(source_drag_end), (gpointer) this );
22d5903e
RR
798}
799
ac57418f
RR
800#endif
801
93c5dd39 802 // wxUSE_DRAG_AND_DROP