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