]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/dnd.cpp
wxGTK's built-in dockable menu now give their
[wxWidgets.git] / src / gtk / 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
28#include <X11/Xlib.h>
29
22d5903e
RR
30//----------------------------------------------------------------------------
31// global data
32//----------------------------------------------------------------------------
c801d85f
KB
33
34extern bool g_blockEventsOnDrag;
35
22d5903e
RR
36//----------------------------------------------------------------------------
37// standard icons
38//----------------------------------------------------------------------------
39
40/* XPM */
41static char * gv_xpm[] = {
42"40 34 3 1",
43" s None c None",
44". c black",
45"X c white",
46" ",
47" ",
48" ...... ",
49" ..XXXXXX.. ",
50" .XXXXXXXXXX. ",
51" .XXXXXXXXXXXX. ",
52" .XXXXXXXXXXXX. ",
53" .XXXXXXXXXXXXXX. ",
54" .XXX..XXXX..XXX. ",
55" ....XX....XX....XX. ",
56" .XXX.XXX..XXXX..XXX.... ",
57" .XXXXXXXXXXXXXXXXXXX.XXX. ",
58" .XXXXXXXXXXXXXXXXXXXXXXXX. ",
59" .XXXXXXXXXXXXXXXXXXXXXXXX. ",
60" ..XXXXXXXXXXXXXXXXXXXXXX. ",
61" .XXXXXXXXXXXXXXXXXX... ",
62" ..XXXXXXXXXXXXXXXX. ",
63" .XXXXXXXXXXXXXXXX. ",
64" .XXXXXXXXXXXXXXXX. ",
65" .XXXXXXXXXXXXXXXXX. ",
66" .XXXXXXXXXXXXXXXXX. ",
67" .XXXXXXXXXXXXXXXXXX. ",
68" .XXXXXXXXXXXXXXXXXXX. ",
69" .XXXXXXXXXXXXXXXXXXXXX. ",
70" .XXXXXXXXXXXXXX.XXXXXXX. ",
71" .XXXXXXX.XXXXXXX.XXXXXXX. ",
72" .XXXXXXXX.XXXXXXX.XXXXXXX. ",
73" .XXXXXXX...XXXXX...XXXXX. ",
74" .XXXXXXX. ..... ..... ",
75" ..XXXX.. ",
76" .... ",
77" ",
78" ",
79" "};
80
81/* XPM */
82static char * page_xpm[] = {
83/* width height ncolors chars_per_pixel */
84"32 32 5 1",
85/* colors */
86" s None c None",
87". c black",
88"X c wheat",
89"o c tan",
90"O c #6699FF",
91/* pixels */
92" ................... ",
93" .XXXXXXXXXXXXXXXXX.. ",
94" .XXXXXXXXXXXXXXXXX.o. ",
95" .XXXXXXXXXXXXXXXXX.oo. ",
96" .XXXXXXXXXXXXXXXXX.ooo. ",
97" .XXXXXXXXXXXXXXXXX.oooo. ",
98" .XXXXXXXXXXXXXXXXX....... ",
99" .XXXXXOOOOOOOOOOXXXooooo. ",
100" .XXXXXXXXXXXXXXXXXXooooo. ",
101" .XXXXXOOOOOOOOOOXXXXXXXX. ",
102" .XXXXXXXXXXXXXXXXXXXXXXX. ",
103" .XXXXXXXOOOOOOOOOXXXXXXX. ",
104" .XXXXXXXXXXXXXXXXXXXXXXX. ",
105" .XXXXXXOOOOOOOOOOXXXXXXX. ",
106" .XXXXXXXXXXXXXXXXXXXXXXX. ",
107" .XXXXXOOOOOOOOOOXXXXXXXX. ",
108" .XXXXXXXXXXXXXXXXXXXXXXX. ",
109" .XXXXXXXOOOOOOOOOXXXXXXX. ",
110" .XXXXXXXXXXXXXXXXXXXXXXX. ",
111" .XXXXXXOOOOOOOOOOXXXXXXX. ",
112" .XXXXXXXXXXXXXXXXXXXXXXX. ",
113" .XXXXXOOOOOOOOOOXXXXXXXX. ",
114" .XXXXXXXXXXXXXXXXXXXXXXX. ",
115" .XXXXXXOOOOOOOOOOXXXXXXX. ",
116" .XXXXXXXXXXXXXXXXXXXXXXX. ",
117" .XXXXXOOOOOOOXXXXXXXXXXX. ",
118" .XXXXXXXXXXXXXXXXXXXXXXX. ",
119" .XXXXXXXXXXXXXXXXXXXXXXX. ",
120" .XXXXXXXXXXXXXXXXXXXXXXX. ",
121" .XXXXXXXXXXXXXXXXXXXXXXX. ",
122" .XXXXXXXXXXXXXXXXXXXXXXX. ",
123" ......................... "};
124
125
d6086ea6 126#if (GTK_MINOR_VERSION > 0)
f5368809 127
33a5bc52
RR
128#include "gtk/gtkdnd.h"
129#include "gtk/gtkselection.h"
130
4ba47b40 131
33a5bc52
RR
132// ----------------------------------------------------------------------------
133// "drag_leave"
134// ----------------------------------------------------------------------------
135
136static void target_drag_leave( GtkWidget *WXUNUSED(widget),
d6086ea6
RR
137 GdkDragContext *context,
138 guint WXUNUSED(time),
829e3e8d 139 wxDropTarget *drop_target )
33a5bc52 140{
829e3e8d
RR
141 /* inform the wxDropTarget about the current GdkDragContext.
142 this is only valid for the duration of this call */
143 drop_target->SetDragContext( context );
144
145 /* we don't need return values. this event is just for
146 information */
147 drop_target->OnLeave();
148
149 /* this has to be done because GDK has no "drag_enter" event */
150 drop_target->m_firstMotion = TRUE;
151
152 /* after this, invalidate the drop_target's GdkDragContext */
153 drop_target->SetDragContext( (GdkDragContext*) NULL );
33a5bc52
RR
154}
155
156// ----------------------------------------------------------------------------
157// "drag_motion"
158// ----------------------------------------------------------------------------
159
160static gboolean target_drag_motion( GtkWidget *WXUNUSED(widget),
161 GdkDragContext *context,
d6086ea6
RR
162 gint x,
163 gint y,
164 guint time,
829e3e8d 165 wxDropTarget *drop_target )
33a5bc52 166{
829e3e8d
RR
167 /* Owen Taylor: "if the coordinates not in a drop zone,
168 return FALSE, otherwise call gtk_drag_status() and
169 return TRUE" */
170
171 /* inform the wxDropTarget about the current GdkDragContext.
172 this is only valid for the duration of this call */
173 drop_target->SetDragContext( context );
d6086ea6 174
829e3e8d 175 if (drop_target->m_firstMotion)
d6086ea6 176 {
829e3e8d
RR
177 /* the first "drag_motion" event substitutes a "drag_enter" event */
178 drop_target->OnEnter();
d6086ea6
RR
179 }
180
829e3e8d
RR
181 /* give program a chance to react (i.e. to say no by returning FALSE) */
182 bool ret = drop_target->OnMove( x, y );
183
184 /* we don't yet handle which "actions" (i.e. copy or move)
185 the target accepts. so far we simply accept the
186 suggested action. TODO. */
187 if (ret)
188 gdk_drag_status( context, context->suggested_action, time );
189
190 /* after this, invalidate the drop_target's GdkDragContext */
191 drop_target->SetDragContext( (GdkDragContext*) NULL );
192
193 /* this has to be done because GDK has no "drag_enter" event */
194 drop_target->m_firstMotion = FALSE;
195
196 return ret;
33a5bc52
RR
197}
198
199// ----------------------------------------------------------------------------
200// "drag_drop"
201// ----------------------------------------------------------------------------
202
203static gboolean target_drag_drop( GtkWidget *widget,
204 GdkDragContext *context,
205 gint x,
206 gint y,
829e3e8d
RR
207 guint time,
208 wxDropTarget *drop_target )
33a5bc52 209{
829e3e8d
RR
210 /* Owen Taylor: "if the drop is not in a drop zone,
211 return FALSE, otherwise, if you aren't accepting
212 the drop, call gtk_drag_finish() with success == FALSE
213 otherwise call gtk_drag_data_get()" */
4ba47b40
RR
214
215// printf( "drop.\n" );
829e3e8d
RR
216
217 /* this seems to make a difference between not accepting
218 due to wrong target area and due to wrong format. let
219 us hope that this is not required.. */
33a5bc52 220
829e3e8d
RR
221 /* inform the wxDropTarget about the current GdkDragContext.
222 this is only valid for the duration of this call */
223 drop_target->SetDragContext( context );
224
225 /* inform the wxDropTarget about the current drag widget.
226 this is only valid for the duration of this call */
227 drop_target->SetDragWidget( widget );
228
229 /* inform the wxDropTarget about the current drag time.
230 this is only valid for the duration of this call */
231 drop_target->SetDragTime( time );
232
233 bool ret = drop_target->OnDrop( x, y );
234
5af019af 235 if (!ret)
829e3e8d
RR
236 {
237 /* cancel the whole thing */
238 gtk_drag_finish( context,
239 FALSE, /* no success */
240 FALSE, /* don't delete data on dropping side */
241 time );
242 }
243
244 /* after this, invalidate the drop_target's GdkDragContext */
245 drop_target->SetDragContext( (GdkDragContext*) NULL );
246
247 /* after this, invalidate the drop_target's drag widget */
248 drop_target->SetDragWidget( (GtkWidget*) NULL );
249
250 /* this has to be done because GDK has no "drag_enter" event */
251 drop_target->m_firstMotion = TRUE;
252
253 return ret;
33a5bc52
RR
254}
255
256// ----------------------------------------------------------------------------
257// "drag_data_received"
258// ----------------------------------------------------------------------------
259
260static void target_drag_data_received( GtkWidget *WXUNUSED(widget),
261 GdkDragContext *context,
262 gint x,
263 gint y,
264 GtkSelectionData *data,
265 guint WXUNUSED(info),
829e3e8d
RR
266 guint time,
267 wxDropTarget *drop_target )
33a5bc52 268{
829e3e8d
RR
269 /* Owen Taylor: "call gtk_drag_finish() with
270 success == TRUE" */
271
4ba47b40
RR
272// printf( "data received.\n" );
273
829e3e8d 274 if ((data->length <= 0) || (data->format != 8))
33a5bc52 275 {
829e3e8d
RR
276 /* negative data length and non 8-bit data format
277 qualifies for junk */
278 gtk_drag_finish (context, FALSE, FALSE, time);
5af019af
RR
279
280 return;
829e3e8d 281 }
5af019af
RR
282
283 /* inform the wxDropTarget about the current GtkSelectionData.
284 this is only valid for the duration of this call */
285 drop_target->SetDragData( data );
286
287 if (drop_target->OnData( x, y ))
829e3e8d 288 {
829e3e8d 289 /* tell GTK that data transfer was successfull */
ab8884ac 290 gtk_drag_finish( context, TRUE, FALSE, time );
33a5bc52 291 }
5af019af
RR
292 else
293 {
294 /* tell GTK that data transfer was not successfull */
295 gtk_drag_finish( context, FALSE, FALSE, time );
296 }
297
298 /* after this, invalidate the drop_target's drag data */
299 drop_target->SetDragData( (GtkSelectionData*) NULL );
33a5bc52
RR
300}
301
4ba47b40 302//----------------------------------------------------------------------------
33a5bc52 303// wxDropTarget
4ba47b40 304//----------------------------------------------------------------------------
33a5bc52 305
f5368809
RR
306wxDropTarget::wxDropTarget()
307{
829e3e8d
RR
308 m_firstMotion = TRUE;
309 m_dragContext = (GdkDragContext*) NULL;
310 m_dragWidget = (GtkWidget*) NULL;
5af019af 311 m_dragData = (GtkSelectionData*) NULL;
829e3e8d 312 m_dragTime = 0;
f5368809
RR
313}
314
315wxDropTarget::~wxDropTarget()
316{
317}
318
d6086ea6
RR
319void wxDropTarget::OnEnter()
320{
321}
322
323void wxDropTarget::OnLeave()
324{
325}
326
829e3e8d 327bool wxDropTarget::OnMove( int WXUNUSED(x), int WXUNUSED(y) )
d6086ea6 328{
d6086ea6
RR
329 return TRUE;
330}
331
829e3e8d 332bool wxDropTarget::OnDrop( int WXUNUSED(x), int WXUNUSED(y) )
d6086ea6 333{
829e3e8d 334 return FALSE;
d6086ea6
RR
335}
336
5af019af
RR
337bool wxDropTarget::OnData( int WXUNUSED(x), int WXUNUSED(y) )
338{
339 return FALSE;
340}
341
342bool wxDropTarget::RequestData( wxDataFormat format )
343{
344 if (!m_dragContext) return FALSE;
345 if (!m_dragWidget) return FALSE;
346
347 /* this should trigger an "drag_data_received" event */
348 gtk_drag_get_data( m_dragWidget,
349 m_dragContext,
350 format.GetAtom(),
351 m_dragTime );
352
353 return TRUE;
354}
355
d6086ea6 356bool wxDropTarget::IsSupported( wxDataFormat format )
22d5903e 357{
22d5903e
RR
358 if (!m_dragContext) return FALSE;
359
360 GList *child = m_dragContext->targets;
361 while (child)
362 {
363 GdkAtom formatAtom = (GdkAtom) GPOINTER_TO_INT(child->data);
829e3e8d 364
4ba47b40
RR
365// char *name = gdk_atom_name( formatAtom );
366// if (name) printf( "Format available: %s.\n", name );
829e3e8d
RR
367
368 if (formatAtom == format.GetAtom()) return TRUE;
22d5903e
RR
369 child = child->next;
370 }
829e3e8d
RR
371
372 return FALSE;
d6086ea6
RR
373}
374
5af019af 375bool wxDropTarget::GetData( wxDataObject *data_object )
d6086ea6 376{
5af019af 377 if (!m_dragData) return FALSE;
4ba47b40 378
5af019af
RR
379 if (m_dragData->target != data_object->GetFormat().GetAtom()) return FALSE;
380
381 if (data_object->GetFormat().GetType() == wxDF_TEXT)
382 {
383 wxTextDataObject *text_object = (wxTextDataObject*)data_object;
384 text_object->SetText( (const char*)m_dragData->data );
385 } else
386
387 if (data_object->GetFormat().GetType() == wxDF_FILENAME)
388 {
389 } else
390
391 if (data_object->GetFormat().GetType() == wxDF_PRIVATE)
392 {
393 wxPrivateDataObject *priv_object = (wxPrivateDataObject*)data_object;
394 priv_object->SetData( (const char*)m_dragData->data, (size_t)m_dragData->length );
395 }
829e3e8d 396
5af019af 397 return TRUE;
d6086ea6
RR
398}
399
f5368809
RR
400void wxDropTarget::UnregisterWidget( GtkWidget *widget )
401{
d6086ea6 402 wxCHECK_RET( widget != NULL, "unregister widget is NULL" );
f5368809 403
829e3e8d 404 gtk_drag_dest_unset( widget );
33a5bc52 405
d6086ea6 406 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
33a5bc52
RR
407 GTK_SIGNAL_FUNC(target_drag_leave), (gpointer) this );
408
d6086ea6 409 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
33a5bc52
RR
410 GTK_SIGNAL_FUNC(target_drag_motion), (gpointer) this );
411
d6086ea6 412 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
33a5bc52
RR
413 GTK_SIGNAL_FUNC(target_drag_drop), (gpointer) this );
414
d6086ea6 415 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
33a5bc52 416 GTK_SIGNAL_FUNC(target_drag_data_received), (gpointer) this );
f5368809
RR
417}
418
419void wxDropTarget::RegisterWidget( GtkWidget *widget )
420{
d6086ea6 421 wxCHECK_RET( widget != NULL, "register widget is NULL" );
f5368809 422
829e3e8d
RR
423 /* gtk_drag_dest_set() determines what default behaviour we'd like
424 GTK to supply. we don't want to specify out targets (=formats)
425 or actions in advance (i.e. not GTK_DEST_DEFAULT_MOTION and
426 not GTK_DEST_DEFAULT_DROP). instead we react individually to
427 "drag_motion" and "drag_drop" events. this makes it possible
428 to allow dropping on only a small area. we should set
429 GTK_DEST_DEFAULT_HIGHLIGHT as this will switch on the nice
430 highlighting if dragging over standard controls, but this
431 seems to be broken without the other two. */
f5368809 432
d6086ea6 433 gtk_drag_dest_set( widget,
829e3e8d
RR
434 (GtkDestDefaults) 0, /* no default behaviour */
435 (GtkTargetEntry*) NULL, /* we don't supply any formats here */
436 0, /* number of targets = 0 */
437 (GdkDragAction) 0 ); /* we don't supply any actions here */
33a5bc52 438
d6086ea6 439 gtk_signal_connect( GTK_OBJECT(widget), "drag_leave",
33a5bc52
RR
440 GTK_SIGNAL_FUNC(target_drag_leave), (gpointer) this );
441
d6086ea6 442 gtk_signal_connect( GTK_OBJECT(widget), "drag_motion",
33a5bc52
RR
443 GTK_SIGNAL_FUNC(target_drag_motion), (gpointer) this );
444
d6086ea6 445 gtk_signal_connect( GTK_OBJECT(widget), "drag_drop",
33a5bc52
RR
446 GTK_SIGNAL_FUNC(target_drag_drop), (gpointer) this );
447
d6086ea6 448 gtk_signal_connect( GTK_OBJECT(widget), "drag_data_received",
33a5bc52 449 GTK_SIGNAL_FUNC(target_drag_data_received), (gpointer) this );
f5368809
RR
450}
451
d6086ea6 452//-------------------------------------------------------------------------
f5368809 453// wxTextDropTarget
d6086ea6 454//-------------------------------------------------------------------------
f5368809 455
d6086ea6 456bool wxTextDropTarget::OnMove( int WXUNUSED(x), int WXUNUSED(y) )
f5368809 457{
5af019af 458 return IsSupported( wxDF_TEXT );
f5368809
RR
459}
460
5af019af 461bool wxTextDropTarget::OnDrop( int WXUNUSED(x), int WXUNUSED(y) )
f5368809 462{
5af019af
RR
463 if (IsSupported( wxDF_TEXT ))
464 {
465 RequestData( wxDF_TEXT );
466 return TRUE;
467 }
829e3e8d 468
5af019af
RR
469 return FALSE;
470}
471
472bool wxTextDropTarget::OnData( int x, int y )
473{
d6086ea6
RR
474 wxTextDataObject data;
475 if (!GetData( &data )) return FALSE;
f5368809 476
829e3e8d 477 OnDropText( x, y, data.GetText() );
5af019af 478
829e3e8d 479 return TRUE;
f5368809
RR
480}
481
482//-------------------------------------------------------------------------
d6086ea6 483// wxPrivateDropTarget
f5368809
RR
484//-------------------------------------------------------------------------
485
d6086ea6 486wxPrivateDropTarget::wxPrivateDropTarget()
f5368809 487{
d6086ea6 488 m_id = wxTheApp->GetAppName();
f5368809
RR
489}
490
d6086ea6 491wxPrivateDropTarget::wxPrivateDropTarget( const wxString &id )
f5368809 492{
d6086ea6 493 m_id = id;
f5368809
RR
494}
495
d6086ea6 496bool wxPrivateDropTarget::OnMove( int WXUNUSED(x), int WXUNUSED(y) )
f5368809 497{
d6086ea6 498 return IsSupported( m_id );
f5368809
RR
499}
500
5af019af
RR
501bool wxPrivateDropTarget::OnDrop( int WXUNUSED(x), int WXUNUSED(y) )
502{
503 if (!IsSupported( m_id ))
504 {
505 RequestData( m_id );
506 return FALSE;
507 }
508
509 return FALSE;
510}
511
512bool wxPrivateDropTarget::OnData( int x, int y )
f5368809 513{
d6086ea6 514 if (!IsSupported( m_id )) return FALSE;
829e3e8d 515
d6086ea6
RR
516 wxPrivateDataObject data;
517 if (!GetData( &data )) return FALSE;
518
829e3e8d
RR
519 OnDropData( x, y, data.GetData(), data.GetSize() );
520
521 return TRUE;
f5368809 522}
d6086ea6
RR
523
524//----------------------------------------------------------------------------
525// A drop target which accepts files (dragged from File Manager or Explorer)
526//----------------------------------------------------------------------------
527
528bool wxFileDropTarget::OnMove( int WXUNUSED(x), int WXUNUSED(y) )
f5368809 529{
5af019af 530 return IsSupported( wxDF_FILENAME );
f5368809
RR
531}
532
d6086ea6 533bool wxFileDropTarget::OnDrop( int x, int y )
f5368809 534{
5af019af
RR
535 if (IsSupported( wxDF_FILENAME ))
536 {
537 RequestData( wxDF_FILENAME );
538 return TRUE;
539 }
540
541 return FALSE;
829e3e8d
RR
542}
543
5af019af 544bool wxFileDropTarget::OnData( int x, int y )
829e3e8d 545{
d6086ea6 546 wxFileDataObject data;
5af019af 547 if (!GetData( &data )) return FALSE;
d6086ea6
RR
548
549 /* get number of substrings /root/mytext.txt/0/root/myothertext.txt/0/0 */
550 size_t number = 0;
551 size_t i;
552 size_t size = data.GetFiles().Length();
553 char *text = WXSTRINGCAST data.GetFiles();
554 for ( i = 0; i < size; i++)
555 if (text[i] == 0) number++;
556
5af019af 557 if (number == 0) return FALSE;
f5368809 558
d6086ea6 559 char **files = new char*[number];
f5368809 560
d6086ea6
RR
561 text = WXSTRINGCAST data.GetFiles();
562 for (i = 0; i < number; i++)
f5368809 563 {
d6086ea6
RR
564 files[i] = text;
565 int len = strlen( text );
566 text += len+1;
f5368809 567 }
f5368809 568
829e3e8d 569 OnDropFiles( x, y, number, files );
d6086ea6
RR
570
571 free( files );
5af019af
RR
572
573 return TRUE;
f5368809
RR
574}
575
4ba47b40
RR
576//----------------------------------------------------------------------------
577// "drag_data_get"
578//----------------------------------------------------------------------------
579
580static void
581source_drag_data_get (GtkWidget *WXUNUSED(widget),
582 GdkDragContext *context,
583 GtkSelectionData *selection_data,
584 guint WXUNUSED(info),
585 guint WXUNUSED(time),
586 wxDropSource *drop_source )
587{
5af019af
RR
588// char *name = gdk_atom_name( selection_data->target );
589// if (name) printf( "Format requested: %s.\n", name );
4ba47b40
RR
590
591 wxNode *node = drop_source->m_data->m_dataObjects.First();
592 while (node)
593 {
594 wxDataObject *data_object = (wxDataObject*) node->Data();
595 if (data_object->GetFormat().GetAtom() == selection_data->target)
596 {
597 size_t data_size = data_object->GetSize();
598 if (data_size > 0)
599 {
600 guchar *buffer = new guchar[data_size];
601 data_object->WriteData( buffer );
602
603 gtk_selection_data_set( selection_data,
604 selection_data->target,
605 8, /* 8-bit */
606 buffer,
607 data_size );
608
609 free( buffer );
610
611 /* so far only copy, no moves. TODO. */
612 drop_source->m_retValue = wxDragCopy;
613
614 return;
615 }
616 }
617
618 node = node->Next();
619 }
620
621 drop_source->m_retValue = wxDragCancel;
622}
623
624//----------------------------------------------------------------------------
625// "drag_data_delete"
626//----------------------------------------------------------------------------
627
628static void source_drag_data_delete( GtkWidget *WXUNUSED(widget),
629 GdkDragContext *WXUNUSED(context),
630 wxDropSource *drop_source )
631{
632// printf( "Delete the data!\n" );
33a5bc52 633
4ba47b40
RR
634 drop_source->m_retValue = wxDragMove;
635}
636
637//----------------------------------------------------------------------------
638// "drag_begin"
639//----------------------------------------------------------------------------
640
641static void source_drag_begin( GtkWidget *WXUNUSED(widget),
642 GdkDragContext *WXUNUSED(context),
643 wxDropSource *WXUNUSED(drop_source) )
644{
645// printf( "drag_begin.\n" );
646}
647
648//----------------------------------------------------------------------------
649// "drag_end"
650//----------------------------------------------------------------------------
651
652static void source_drag_end( GtkWidget *WXUNUSED(widget),
653 GdkDragContext *WXUNUSED(context),
654 wxDropSource *drop_source )
655{
656// printf( "drag_end.\n" );
657
658 drop_source->m_waiting = FALSE;
659}
660
661//---------------------------------------------------------------------------
662// wxDropSource
663//---------------------------------------------------------------------------
22d5903e
RR
664
665wxDropSource::wxDropSource( wxWindow *win, const wxIcon &go, const wxIcon &stop )
666{
667 g_blockEventsOnDrag = TRUE;
4ba47b40 668 m_waiting = TRUE;
22d5903e
RR
669
670 m_window = win;
671 m_widget = win->m_widget;
672 if (win->m_wxwindow) m_widget = win->m_wxwindow;
673
674 m_data = (wxDataBroker*) NULL;
675 m_retValue = wxDragCancel;
676
677 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
678 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
679
680 m_goIcon = go;
681 if (wxNullIcon == go) m_goIcon = wxIcon( page_xpm );
682 m_stopIcon = stop;
683 if (wxNullIcon == stop) m_stopIcon = wxIcon( gv_xpm );
684}
685
686wxDropSource::wxDropSource( wxDataObject *data, wxWindow *win, const wxIcon &go, const wxIcon &stop )
687{
4ba47b40 688 m_waiting = TRUE;
22d5903e
RR
689
690 m_window = win;
691 m_widget = win->m_widget;
692 if (win->m_wxwindow) m_widget = win->m_wxwindow;
693 m_retValue = wxDragCancel;
694
695 if (data)
696 {
697 m_data = new wxDataBroker();
698 m_data->Add( data );
699 }
700 else
701 {
702 m_data = (wxDataBroker*) NULL;
703 }
704
705 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
706 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
707
708 m_goIcon = go;
709 if (wxNullIcon == go) m_goIcon = wxIcon( page_xpm );
710 m_stopIcon = stop;
711 if (wxNullIcon == stop) m_stopIcon = wxIcon( gv_xpm );
712}
713
714wxDropSource::wxDropSource( wxDataBroker *data, wxWindow *win )
715{
22d5903e
RR
716 m_window = win;
717 m_widget = win->m_widget;
718 if (win->m_wxwindow) m_widget = win->m_wxwindow;
719 m_retValue = wxDragCancel;
720
721 m_data = data;
722
723 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
724 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
725}
726
727void wxDropSource::SetData( wxDataObject *data )
728{
729 if (m_data) delete m_data;
730
731 if (data)
732 {
733 m_data = new wxDataBroker();
734 m_data->Add( data );
735 }
736 else
737 {
738 m_data = (wxDataBroker*) NULL;
739 }
740}
741
742void wxDropSource::SetData( wxDataBroker *data )
743{
744 if (m_data) delete m_data;
745
746 m_data = data;
747}
748
749wxDropSource::~wxDropSource(void)
750{
751 if (m_data) delete m_data;
752
753 g_blockEventsOnDrag = FALSE;
754}
755
756wxDragResult wxDropSource::DoDragDrop( bool WXUNUSED(bAllowMove) )
757{
758 wxASSERT_MSG( m_data, "wxDragSource: no data" );
759
760 if (!m_data) return (wxDragResult) wxDragNone;
761
4ba47b40
RR
762 g_blockEventsOnDrag = TRUE;
763
764 RegisterWindow();
765
766 m_waiting = TRUE;
22d5903e 767
4ba47b40
RR
768 GtkTargetList *target_list = gtk_target_list_new( (GtkTargetEntry*) NULL, 0 );
769 gtk_target_list_add( target_list, gdk_atom_intern( "STRING", FALSE ), 0, 0 );
770
771 GdkEventMotion event;
772 event.window = m_widget->window;
773 int x = 0;
774 int y = 0;
775 GdkModifierType state;
776 gdk_window_get_pointer( event.window, &x, &y, &state );
777 event.x = x;
778 event.y = y;
779 event.state = state;
780
781 /* GTK wants to know which button was pressed which caused the dragging */
782 int button_number = 0;
783 if (event.state & GDK_BUTTON1_MASK) button_number = 1;
784 else if (event.state & GDK_BUTTON2_MASK) button_number = 2;
785 else if (event.state & GDK_BUTTON3_MASK) button_number = 3;
786
787 /* don't start dragging if no button is down */
788 if (button_number)
22d5903e 789 {
4ba47b40
RR
790 GdkDragContext *context = gtk_drag_begin( m_widget,
791 target_list,
792 GDK_ACTION_COPY,
793 button_number, /* number of mouse button which started drag */
794 (GdkEvent*) &event );
22d5903e 795
4ba47b40
RR
796 wxMask *mask = m_goIcon.GetMask();
797 GdkBitmap *bm = (GdkBitmap *) NULL;
798 if (mask) bm = mask->GetBitmap();
799 GdkPixmap *pm = m_goIcon.GetPixmap();
22d5903e 800
4ba47b40
RR
801 gtk_drag_set_icon_pixmap( context,
802 gtk_widget_get_colormap( m_widget ),
803 pm,
804 bm,
805 0,
806 0 );
807
5af019af
RR
808 gdk_flush();
809
4ba47b40
RR
810 while (m_waiting) wxYield();
811 }
22d5903e 812
4ba47b40
RR
813 g_blockEventsOnDrag = FALSE;
814
815 UnregisterWindow();
816
817 return m_retValue;
22d5903e
RR
818}
819
4ba47b40 820void wxDropSource::RegisterWindow()
22d5903e 821{
4ba47b40
RR
822 if (!m_widget) return;
823
824 gtk_signal_connect( GTK_OBJECT(m_widget), "drag_data_get",
825 GTK_SIGNAL_FUNC (source_drag_data_get), (gpointer) this);
826 gtk_signal_connect (GTK_OBJECT(m_widget), "drag_data_delete",
827 GTK_SIGNAL_FUNC (source_drag_data_delete), (gpointer) this );
828 gtk_signal_connect (GTK_OBJECT(m_widget), "drag_begin",
829 GTK_SIGNAL_FUNC (source_drag_begin), (gpointer) this );
830 gtk_signal_connect (GTK_OBJECT(m_widget), "drag_end",
831 GTK_SIGNAL_FUNC (source_drag_end), (gpointer) this );
832
22d5903e
RR
833}
834
4ba47b40 835void wxDropSource::UnregisterWindow()
22d5903e
RR
836{
837 if (!m_widget) return;
4ba47b40
RR
838
839 gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget),
840 GTK_SIGNAL_FUNC(source_drag_data_get), (gpointer) this );
841 gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget),
842 GTK_SIGNAL_FUNC(source_drag_data_delete), (gpointer) this );
843 gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget),
844 GTK_SIGNAL_FUNC(source_drag_begin), (gpointer) this );
845 gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget),
846 GTK_SIGNAL_FUNC(source_drag_end), (gpointer) this );
22d5903e
RR
847}
848
849
33a5bc52
RR
850#else // NEW_CODE
851
22d5903e
RR
852//----------------------------------------------------------------------------
853// forward
854//----------------------------------------------------------------------------
855
e4677d31 856GtkWidget *shape_create_icon ( const wxIcon &shape,
a802c3a1
RR
857 gint x,
858 gint y,
859 gint px,
860 gint py,
861 gint window_type);
862
b666df2c
RR
863//-----------------------------------------------------------------------------
864// globals
865//-----------------------------------------------------------------------------
866
867wxDropSource *gs_currentDropSource = (wxDropSource*) NULL;
868
869//-----------------------------------------------------------------------------
870// "drop_enter_event"
871//-----------------------------------------------------------------------------
872
873static void gtk_target_enter_callback( GtkWidget *WXUNUSED(widget),
874 GdkEventDropEnter *WXUNUSED(event),
875 wxDropTarget *target )
876{
877 if (target)
878 target->OnEnter();
879}
880
881//-----------------------------------------------------------------------------
882// "drop_leave_event"
883//-----------------------------------------------------------------------------
884
885static void gtk_target_leave_callback( GtkWidget *WXUNUSED(widget),
886 GdkEventDropLeave *WXUNUSED(event),
887 wxDropTarget *target )
888{
889 if (target)
890 target->OnLeave();
891}
892
33a5bc52
RR
893//-----------------------------------------------------------------------------
894// "drop_data_available_event"
895//-----------------------------------------------------------------------------
896
897static void gtk_target_callback( GtkWidget *widget,
898 GdkEventDropDataAvailable *event,
899 wxDropTarget *target )
900{
901 if (target)
902 {
903 int x = 0;
904 int y = 0;
905 gdk_window_get_pointer( widget->window, &x, &y, (GdkModifierType *) NULL );
ab8884ac
RR
906/*
907 printf( "Drop data is of type %s.\n", event->data_type );
908*/
33a5bc52
RR
909 target->OnDrop( x, y, (const void*)event->data, (size_t)event->data_numbytes );
910 }
911
912/*
913 g_free (event->data);
914 g_free (event->data_type);
915*/
916}
f5368809 917
c801d85f
KB
918// ----------------------------------------------------------------------------
919// wxDropTarget
920// ----------------------------------------------------------------------------
921
922wxDropTarget::wxDropTarget()
923{
0d2a2b60 924 m_format = (wxDataFormat*) NULL;
ff7b1510 925}
c801d85f
KB
926
927wxDropTarget::~wxDropTarget()
928{
0d2a2b60
RR
929 if (m_format) delete m_format;
930}
931
932wxDataFormat &wxDropTarget::GetFormat(size_t n) const
933{
934 return (*m_format);
ff7b1510 935}
c801d85f 936
c801d85f
KB
937void wxDropTarget::UnregisterWidget( GtkWidget *widget )
938{
33a5bc52 939 if (!widget) return;
e3e65dac 940
33a5bc52
RR
941 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
942 GTK_SIGNAL_FUNC(gtk_target_callback), (gpointer) this );
943
944 gtk_widget_dnd_drop_set( widget, FALSE, (gchar **) NULL, 0, FALSE );
ff7b1510 945}
c801d85f 946
e3e65dac
RR
947void wxDropTarget::RegisterWidget( GtkWidget *widget )
948{
33a5bc52
RR
949 wxString formats;
950 int valid = 0;
e3e65dac 951
33a5bc52 952 for ( size_t i = 0; i < GetFormatCount(); i++ )
e3e65dac 953 {
0d2a2b60 954 switch (GetFormat(i).GetType())
33a5bc52
RR
955 {
956 case wxDF_TEXT:
ab8884ac
RR
957 {
958 if (i > 0) formats += ";";
959 formats += "text/plain";
960 valid++;
961 break;
962 }
963 case wxDF_FILENAME:
964 {
965 if (i > 0) formats += ";";
966 formats += "file:ALL";
967 valid++;
968 break;
969 }
970 case wxDF_PRIVATE:
971 {
972 if (i > 0) formats += ";";
973 wxPrivateDropTarget *pdt = (wxPrivateDropTarget *)this;
ab8884ac
RR
974 formats += pdt->GetId();
975 valid++;
976 break;
977 }
978 default:
33a5bc52
RR
979 break;
980 }
ff7b1510 981 }
e3e65dac 982
33a5bc52 983 char *str = WXSTRINGCAST formats;
ab8884ac 984
33a5bc52
RR
985 gtk_widget_dnd_drop_set( widget, TRUE, &str, valid, FALSE );
986
987 gtk_signal_connect( GTK_OBJECT(widget), "drop_data_available_event",
988 GTK_SIGNAL_FUNC(gtk_target_callback), (gpointer) this );
b666df2c
RR
989
990 gtk_signal_connect( GTK_OBJECT(widget), "drop_enter_event",
991 GTK_SIGNAL_FUNC(gtk_target_enter_callback), (gpointer) this );
992
993 gtk_signal_connect( GTK_OBJECT(widget), "drop_leave_event",
994 GTK_SIGNAL_FUNC(gtk_target_leave_callback), (gpointer) this );
ff7b1510 995}
e3e65dac 996
c801d85f
KB
997// ----------------------------------------------------------------------------
998// wxTextDropTarget
999// ----------------------------------------------------------------------------
1000
0d2a2b60
RR
1001wxTextDropTarget::wxTextDropTarget()
1002{
1003 m_format = new wxDataFormat( wxDF_TEXT );
1004}
1005
dc86cb34 1006bool wxTextDropTarget::OnDrop( long x, long y, const void *data, size_t WXUNUSED(size) )
c801d85f 1007{
33a5bc52
RR
1008 OnDropText( x, y, (const char*)data );
1009 return TRUE;
ff7b1510 1010}
c801d85f
KB
1011
1012bool wxTextDropTarget::OnDropText( long x, long y, const char *psz )
1013{
ab8884ac 1014/*
33a5bc52
RR
1015 printf( "Got dropped text: %s.\n", psz );
1016 printf( "At x: %d, y: %d.\n", (int)x, (int)y );
ab8884ac 1017*/
33a5bc52 1018 return TRUE;
ff7b1510 1019}
c801d85f 1020
e3e65dac 1021size_t wxTextDropTarget::GetFormatCount() const
c801d85f 1022{
33a5bc52 1023 return 1;
e3e65dac
RR
1024}
1025
ab8884ac
RR
1026// ----------------------------------------------------------------------------
1027// wxPrivateDropTarget
1028// ----------------------------------------------------------------------------
1029
1030wxPrivateDropTarget::wxPrivateDropTarget()
1031{
1032 m_id = wxTheApp->GetAppName();
0d2a2b60 1033 m_format = new wxDataFormat( m_id );
ab8884ac
RR
1034}
1035
0d2a2b60 1036void wxPrivateDropTarget::SetId( const wxString& id )
ab8884ac 1037{
0d2a2b60
RR
1038 m_id = id;
1039 m_format->SetId( id );
ab8884ac
RR
1040}
1041
0d2a2b60 1042size_t wxPrivateDropTarget::GetFormatCount() const
ab8884ac 1043{
0d2a2b60 1044 return 1;
ab8884ac
RR
1045}
1046
e3e65dac
RR
1047// ----------------------------------------------------------------------------
1048// wxFileDropTarget
1049// ----------------------------------------------------------------------------
1050
0d2a2b60
RR
1051wxFileDropTarget::wxFileDropTarget()
1052{
1053 m_format = new wxDataFormat( wxDF_FILENAME );
1054}
1055
e5403d7c 1056bool wxFileDropTarget::OnDropFiles( long x, long y, size_t nFiles, const char * const aszFiles[] )
e3e65dac 1057{
33a5bc52
RR
1058 printf( "Got %d dropped files.\n", (int)nFiles );
1059 printf( "At x: %d, y: %d.\n", (int)x, (int)y );
ab8884ac 1060
33a5bc52
RR
1061 for (size_t i = 0; i < nFiles; i++)
1062 {
1063 printf( aszFiles[i] );
1064 printf( "\n" );
1065 }
ab8884ac 1066
33a5bc52 1067 return TRUE;
e3e65dac
RR
1068}
1069
dc86cb34 1070bool wxFileDropTarget::OnDrop(long x, long y, const void *data, size_t size )
e3e65dac 1071{
33a5bc52 1072 size_t number = 0;
4dba84be 1073 size_t i;
33a5bc52 1074 char *text = (char*) data;
4dba84be 1075 for ( i = 0; i < size; i++)
33a5bc52 1076 if (text[i] == 0) number++;
e5403d7c 1077
33a5bc52 1078 if (number == 0) return TRUE;
e5403d7c 1079
33a5bc52 1080 char **files = new char*[number];
e5403d7c 1081
33a5bc52 1082 text = (char*) data;
4dba84be 1083 for (i = 0; i < number; i++)
33a5bc52
RR
1084 {
1085 files[i] = text;
1086 int len = strlen( text );
1087 text += len+1;
1088 }
e3e65dac 1089
33a5bc52 1090 bool ret = OnDropFiles( x, y, 1, files );
e5403d7c 1091
33a5bc52 1092 free( files );
e5403d7c 1093
33a5bc52 1094 return ret;
e3e65dac
RR
1095}
1096
1097size_t wxFileDropTarget::GetFormatCount() const
1098{
33a5bc52 1099 return 1;
e3e65dac
RR
1100}
1101
c801d85f 1102//-------------------------------------------------------------------------
e3e65dac 1103// wxDropSource
c801d85f
KB
1104//-------------------------------------------------------------------------
1105
b527aac5
RR
1106static void
1107shape_motion (GtkWidget *widget,
b666df2c 1108 GdkEventMotion * /*event*/);
b527aac5 1109
c801d85f 1110//-----------------------------------------------------------------------------
0d2a2b60
RR
1111// "drag_request_event"
1112//-----------------------------------------------------------------------------
c801d85f 1113
0d2a2b60 1114void gtk_drag_callback( GtkWidget *widget, GdkEventDragRequest *event, wxDropSource *source )
c801d85f 1115{
0d2a2b60
RR
1116 wxDataBroker *data = source->m_data;
1117
1118 if (!data) return;
1119
1120 wxNode *node = data->m_dataObjects.First();
8b53e5a2 1121 {
0d2a2b60
RR
1122 wxDataObject *dobj = (wxDataObject*) node->Data();
1123
1124 if ((strcmp(event->data_type,"file:ALL") == 0) &&
1125 (dobj->GetFormat().GetType() == wxDF_FILENAME))
8b53e5a2 1126 {
0d2a2b60 1127 wxFileDataObject *file_object = (wxFileDataObject*) dobj;
8b53e5a2 1128
0d2a2b60 1129 wxString text = file_object->GetFiles();
8b53e5a2 1130
2830bf19
RR
1131 char *s = WXSTRINGCAST text;
1132
8b53e5a2 1133 gtk_widget_dnd_data_set( widget,
0d2a2b60 1134 (GdkEvent*)event,
2830bf19
RR
1135 (unsigned char*) s,
1136 (int) text.Length()+1 );
8b53e5a2 1137
0d2a2b60
RR
1138 source->m_retValue = wxDragCopy;
1139
1140 return;
8b53e5a2
RR
1141 }
1142
0d2a2b60
RR
1143 if ((strcmp(event->data_type,"text/plain") == 0) &&
1144 (dobj->GetFormat().GetType() == wxDF_TEXT))
8b53e5a2 1145 {
0d2a2b60 1146 wxTextDataObject *text_object = (wxTextDataObject*) dobj;
8b53e5a2 1147
0d2a2b60 1148 wxString text = text_object->GetText();
8b53e5a2 1149
2830bf19
RR
1150 char *s = WXSTRINGCAST text;
1151
8b53e5a2 1152 gtk_widget_dnd_data_set( widget,
0d2a2b60 1153 (GdkEvent*)event,
2830bf19
RR
1154 (unsigned char*) s,
1155 (int) text.Length()+1 );
8b53e5a2 1156
0d2a2b60
RR
1157 source->m_retValue = wxDragCopy;
1158
1159 return;
8b53e5a2
RR
1160 }
1161
0d2a2b60 1162 if (dobj->GetFormat().GetType() == wxDF_PRIVATE)
8b53e5a2 1163 {
0d2a2b60
RR
1164 wxPrivateDataObject *pdo = (wxPrivateDataObject*) dobj;
1165
1166 if (pdo->GetId() == event->data_type)
1167 {
1168 gtk_widget_dnd_data_set( widget,
1169 (GdkEvent*)event,
1170 (unsigned char*) pdo->GetData(),
1171 (int) pdo->GetSize() );
1172
1173 source->m_retValue = wxDragCopy;
1174
1175 return;
1176 }
8b53e5a2 1177 }
0d2a2b60
RR
1178
1179 node = node->Next();
8b53e5a2 1180 }
ff7b1510 1181}
c801d85f 1182
e4677d31 1183wxDropSource::wxDropSource( wxWindow *win, const wxIcon &go, const wxIcon &stop )
c801d85f 1184{
ab8884ac 1185 g_blockEventsOnDrag = TRUE;
e3e65dac 1186
ab8884ac
RR
1187 m_window = win;
1188 m_widget = win->m_widget;
1189 if (win->m_wxwindow) m_widget = win->m_wxwindow;
c801d85f 1190
0d2a2b60 1191 m_data = (wxDataBroker*) NULL;
ab8884ac 1192 m_retValue = wxDragCancel;
e3e65dac 1193
ab8884ac
RR
1194 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
1195 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
e4677d31
RR
1196
1197 m_goIcon = go;
1198 if (wxNullIcon == go) m_goIcon = wxIcon( page_xpm );
1199 m_stopIcon = stop;
1200 if (wxNullIcon == stop) m_stopIcon = wxIcon( gv_xpm );
ff7b1510 1201}
c801d85f 1202
e4677d31 1203wxDropSource::wxDropSource( wxDataObject *data, wxWindow *win, const wxIcon &go, const wxIcon &stop )
c801d85f 1204{
ab8884ac 1205 g_blockEventsOnDrag = TRUE;
e3e65dac 1206
ab8884ac
RR
1207 m_window = win;
1208 m_widget = win->m_widget;
1209 if (win->m_wxwindow) m_widget = win->m_wxwindow;
1210 m_retValue = wxDragCancel;
e3e65dac 1211
0d2a2b60
RR
1212 if (data)
1213 {
1214 m_data = new wxDataBroker();
1215 m_data->Add( data );
1216 }
1217 else
1218 {
1219 m_data = (wxDataBroker*) NULL;
1220 }
e3e65dac 1221
ab8884ac
RR
1222 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
1223 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
e4677d31
RR
1224
1225 m_goIcon = go;
1226 if (wxNullIcon == go) m_goIcon = wxIcon( page_xpm );
1227 m_stopIcon = stop;
1228 if (wxNullIcon == stop) m_stopIcon = wxIcon( gv_xpm );
ff7b1510 1229}
e3e65dac 1230
0d2a2b60
RR
1231wxDropSource::wxDropSource( wxDataBroker *data, wxWindow *win )
1232{
1233 g_blockEventsOnDrag = TRUE;
1234
1235 m_window = win;
1236 m_widget = win->m_widget;
1237 if (win->m_wxwindow) m_widget = win->m_wxwindow;
1238 m_retValue = wxDragCancel;
1239
1240 m_data = data;
1241
1242 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
1243 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
1244}
1245
1246void wxDropSource::SetData( wxDataObject *data )
1247{
1248 if (m_data) delete m_data;
1249
1250 if (data)
1251 {
1252 m_data = new wxDataBroker();
1253 m_data->Add( data );
1254 }
1255 else
1256 {
1257 m_data = (wxDataBroker*) NULL;
1258 }
1259}
1260
1261void wxDropSource::SetData( wxDataBroker *data )
c801d85f 1262{
0d2a2b60
RR
1263 if (m_data) delete m_data;
1264
1265 m_data = data;
ff7b1510 1266}
c801d85f 1267
e3e65dac 1268wxDropSource::~wxDropSource(void)
c801d85f 1269{
0d2a2b60 1270 if (m_data) delete m_data;
e3e65dac 1271
ab8884ac 1272 g_blockEventsOnDrag = FALSE;
ff7b1510 1273}
e3e65dac 1274
46ccb510 1275wxDragResult wxDropSource::DoDragDrop( bool WXUNUSED(bAllowMove) )
e3e65dac 1276{
ab8884ac
RR
1277 if (gdk_dnd.dnd_grabbed) return (wxDragResult) wxDragNone;
1278 if (gdk_dnd.drag_really) return (wxDragResult) wxDragNone;
e3e65dac 1279
ab8884ac 1280 wxASSERT_MSG( m_data, "wxDragSource: no data" );
b6af8d80 1281
ab8884ac 1282 if (!m_data) return (wxDragResult) wxDragNone;
c801d85f 1283
ab8884ac
RR
1284 static GtkWidget *drag_icon = (GtkWidget*) NULL;
1285 static GtkWidget *drop_icon = (GtkWidget*) NULL;
a802c3a1 1286
ab8884ac 1287 GdkPoint hotspot_1 = {0,-5 };
a802c3a1 1288
ab8884ac
RR
1289 if (!drag_icon)
1290 {
e4677d31 1291 drag_icon = shape_create_icon ( m_stopIcon,
a802c3a1
RR
1292 440, 140, 0,0, GTK_WINDOW_POPUP);
1293
1294 gtk_signal_connect (GTK_OBJECT (drag_icon), "destroy",
1295 GTK_SIGNAL_FUNC(gtk_widget_destroyed),
1296 &drag_icon);
1297
1298 gtk_widget_hide (drag_icon);
ab8884ac 1299 }
a802c3a1 1300
ab8884ac 1301 GdkPoint hotspot_2 = {-5,-5};
a802c3a1 1302
ab8884ac
RR
1303 if (!drop_icon)
1304 {
e4677d31 1305 drop_icon = shape_create_icon ( m_goIcon,
a802c3a1
RR
1306 440, 140, 0,0, GTK_WINDOW_POPUP);
1307
1308 gtk_signal_connect (GTK_OBJECT (drop_icon), "destroy",
1309 GTK_SIGNAL_FUNC(gtk_widget_destroyed),
1310 &drop_icon);
1311
1312 gtk_widget_hide (drop_icon);
ab8884ac 1313 }
b527aac5 1314
a802c3a1 1315
b527aac5 1316 gdk_dnd_set_drag_shape( drag_icon->window,
a802c3a1
RR
1317 &hotspot_1,
1318 drop_icon->window,
1319 &hotspot_2);
1320
1321
ab8884ac 1322 GdkWindowPrivate *wp = (GdkWindowPrivate*) m_widget->window;
c801d85f 1323
ab8884ac 1324 RegisterWindow();
c801d85f 1325
ab8884ac 1326 gdk_dnd.drag_perhaps = TRUE;
c801d85f 1327
ab8884ac
RR
1328 gdk_dnd.dnd_drag_start.x = 5;
1329 gdk_dnd.dnd_drag_start.y = 5;
1330 gdk_dnd.real_sw = wp;
c801d85f 1331
ab8884ac
RR
1332 if (gdk_dnd.drag_startwindows)
1333 {
1334 g_free( gdk_dnd.drag_startwindows );
1335 gdk_dnd.drag_startwindows = (GdkWindow **) NULL;
1336 }
1337 gdk_dnd.drag_numwindows = gdk_dnd.drag_really = 0;
c801d85f 1338
ab8884ac
RR
1339 XWindowAttributes dnd_winattr;
1340 XGetWindowAttributes( gdk_display, wp->xwindow, &dnd_winattr );
1341 wp->dnd_drag_savedeventmask = dnd_winattr.your_event_mask;
c801d85f 1342
ab8884ac 1343 gdk_dnd_drag_addwindow( m_widget->window );
c801d85f 1344
ab8884ac
RR
1345 GdkEventDragBegin ev;
1346 ev.type = GDK_DRAG_BEGIN;
1347 ev.window = m_widget->window;
1348 ev.u.allflags = 0;
1349 ev.u.flags.protocol_version = DND_PROTOCOL_VERSION;
c801d85f 1350
ab8884ac 1351 gdk_event_put( (GdkEvent*)&ev );
c801d85f 1352
ab8884ac
RR
1353 XGrabPointer( gdk_display, wp->xwindow, False,
1354 ButtonMotionMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
1355 GrabModeAsync, GrabModeAsync, gdk_root_window, None, CurrentTime );
c801d85f 1356
ab8884ac 1357 gdk_dnd_set_drag_cursors( m_defaultCursor.GetCursor(), m_goaheadCursor.GetCursor() );
c801d85f 1358
ab8884ac
RR
1359 gdk_dnd.dnd_grabbed = TRUE;
1360 gdk_dnd.drag_really = 1;
e3e65dac 1361
ab8884ac
RR
1362 int x = 0;
1363 int y = 0;
1364 wxGetMousePosition( &x, &y );
e3e65dac 1365
ab8884ac 1366 gdk_dnd_display_drag_cursor( x, y, FALSE, TRUE );
b666df2c
RR
1367
1368 gs_currentDropSource = this;
1369
ab8884ac 1370 while (gdk_dnd.drag_really || gdk_dnd.drag_perhaps) wxYield();
b666df2c
RR
1371
1372 gs_currentDropSource = (wxDropSource*) NULL;
c801d85f 1373
ab8884ac 1374 UnregisterWindow();
e3e65dac 1375
ab8884ac 1376 g_blockEventsOnDrag = FALSE;
30dea054 1377
ab8884ac 1378 return m_retValue;
ff7b1510 1379}
c801d85f 1380
e3e65dac 1381void wxDropSource::RegisterWindow(void)
c801d85f 1382{
ab8884ac 1383 if (!m_data) return;
c801d85f 1384
ab8884ac 1385 wxString formats;
e3e65dac 1386
0d2a2b60
RR
1387 wxNode *node = m_data->m_dataObjects.First();
1388 while (node)
e3e65dac 1389 {
0d2a2b60
RR
1390 wxDataObject* dobj = (wxDataObject*) node->Data();
1391
1392 switch (dobj->GetFormat().GetType())
1393 {
1394 case wxDF_TEXT:
1395 {
1396 formats += "text/plain";
1397 break;
1398 }
1399 case wxDF_FILENAME:
1400 {
1401 formats += "file:ALL";
1402 break;
1403 }
1404 case wxDF_PRIVATE:
1405 {
1406 wxPrivateDataObject* pdo = (wxPrivateDataObject*) m_data;
1407 formats += pdo->GetId();
1408 break;
1409 }
1410 default:
1411 break;
ab8884ac 1412 }
0d2a2b60 1413 node = node->Next();
e3e65dac 1414 }
c801d85f 1415
ab8884ac 1416 char *str = WXSTRINGCAST formats;
c801d85f 1417
ab8884ac 1418 gtk_widget_dnd_drag_set( m_widget, TRUE, &str, 1 );
c801d85f 1419
ab8884ac
RR
1420 gtk_signal_connect( GTK_OBJECT(m_widget), "drag_request_event",
1421 GTK_SIGNAL_FUNC(gtk_drag_callback), (gpointer)this );
ff7b1510 1422}
c801d85f 1423
e3e65dac 1424void wxDropSource::UnregisterWindow(void)
c801d85f 1425{
ab8884ac 1426 if (!m_widget) return;
c801d85f 1427
ab8884ac 1428 gtk_widget_dnd_drag_set( m_widget, FALSE, (gchar **) NULL, 0 );
e3e65dac 1429
ab8884ac 1430 gtk_signal_disconnect_by_data( GTK_OBJECT(m_widget), (gpointer)this );
ff7b1510 1431}
f5368809 1432
a802c3a1
RR
1433
1434/*
1435 * Shaped Windows
1436 */
bbe0af5b 1437static GdkWindow *root_win = (GdkWindow*) NULL;
a802c3a1
RR
1438
1439typedef struct _cursoroffset {gint x,y;} CursorOffset;
1440
1441static void
1442shape_pressed (GtkWidget *widget, GdkEventButton *event)
1443{
1444 CursorOffset *p;
1445
1446 /* ignore double and triple click */
1447 if (event->type != GDK_BUTTON_PRESS)
1448 return;
1449
b527aac5 1450 p = (CursorOffset *)gtk_object_get_user_data (GTK_OBJECT(widget));
a802c3a1
RR
1451 p->x = (int) event->x;
1452 p->y = (int) event->y;
1453
1454 gtk_grab_add (widget);
1455 gdk_pointer_grab (widget->window, TRUE,
b527aac5
RR
1456 (GdkEventMask)
1457 (GDK_BUTTON_RELEASE_MASK |
1458 GDK_BUTTON_MOTION_MASK |
1459 GDK_POINTER_MOTION_HINT_MASK),
bbe0af5b
RR
1460 (GdkWindow*)NULL,
1461 (GdkCursor*) NULL, 0);
a802c3a1
RR
1462}
1463
1464
1465static void
1466shape_released (GtkWidget *widget)
1467{
1468 gtk_grab_remove (widget);
1469 gdk_pointer_ungrab (0);
1470}
1471
1472static void
1473shape_motion (GtkWidget *widget,
b666df2c 1474 GdkEventMotion * /*event*/ )
a802c3a1
RR
1475{
1476 gint xp, yp;
1477 CursorOffset * p;
1478 GdkModifierType mask;
1479
b527aac5 1480 p = (CursorOffset *)gtk_object_get_user_data (GTK_OBJECT (widget));
a802c3a1
RR
1481
1482 /*
1483 * Can't use event->x / event->y here
1484 * because I need absolute coordinates.
1485 */
b666df2c 1486
a802c3a1
RR
1487 gdk_window_get_pointer (root_win, &xp, &yp, &mask);
1488 gtk_widget_set_uposition (widget, xp - p->x, yp - p->y);
b666df2c
RR
1489
1490 if (gs_currentDropSource) gs_currentDropSource->GiveFeedback( wxDragCopy, FALSE );
a802c3a1
RR
1491}
1492
1493GtkWidget *
e4677d31 1494shape_create_icon (const wxIcon &shape,
a802c3a1
RR
1495 gint x,
1496 gint y,
1497 gint px,
1498 gint py,
1499 gint window_type)
1500{
a802c3a1
RR
1501 /*
1502 * GDK_WINDOW_TOPLEVEL works also, giving you a title border
1503 */
e4677d31 1504 GtkWidget *window = gtk_window_new ((GtkWindowType)window_type);
a802c3a1 1505
e4677d31 1506 GtkWidget *fixed = gtk_fixed_new ();
a802c3a1
RR
1507 gtk_widget_set_usize (fixed, 100,100);
1508 gtk_container_add (GTK_CONTAINER (window), fixed);
1509 gtk_widget_show (fixed);
1510
1511 gtk_widget_set_events (window,
1512 gtk_widget_get_events (window) |
1513 GDK_BUTTON_MOTION_MASK |
1514 GDK_POINTER_MOTION_HINT_MASK |
1515 GDK_BUTTON_PRESS_MASK);
1516
1517 gtk_widget_realize (window);
1518
e4677d31
RR
1519 GdkBitmap *mask = (GdkBitmap*) NULL;
1520 if (shape.GetMask()) mask = shape.GetMask()->GetBitmap();
a802c3a1 1521
e4677d31 1522 GtkWidget *pixmap = gtk_pixmap_new (shape.GetPixmap(), mask);
a802c3a1
RR
1523 gtk_fixed_put (GTK_FIXED (fixed), pixmap, px,py);
1524 gtk_widget_show (pixmap);
1525
e4677d31 1526 gtk_widget_shape_combine_mask (window, mask, px,py);
a802c3a1
RR
1527
1528
1529 gtk_signal_connect (GTK_OBJECT (window), "button_press_event",
1530 GTK_SIGNAL_FUNC (shape_pressed),NULL);
1531 gtk_signal_connect (GTK_OBJECT (window), "button_release_event",
1532 GTK_SIGNAL_FUNC (shape_released),NULL);
1533 gtk_signal_connect (GTK_OBJECT (window), "motion_notify_event",
1534 GTK_SIGNAL_FUNC (shape_motion),NULL);
1535
e4677d31 1536 CursorOffset*icon_pos = g_new (CursorOffset, 1);
a802c3a1
RR
1537 gtk_object_set_user_data(GTK_OBJECT(window), icon_pos);
1538
1539 gtk_widget_set_uposition (window, x, y);
1540 gtk_widget_show (window);
1541
1542 return window;
1543}
1544
f5368809
RR
1545#endif
1546 // NEW_GTK_DND_CODE
1547
ac57418f
RR
1548#endif
1549
1550 // wxUSE_DRAG_AND_DROP