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