GTK's dnd is broken, not mine
[wxWidgets.git] / src / gtk / dnd.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: dnd.cpp
3 // Purpose: wxDropTarget class
4 // Author: Robert Roebling
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 ///////////////////////////////////////////////////////////////////////////////
9
10 #ifdef __GNUG__
11 #pragma implementation "dnd.h"
12 #endif
13
14 #include "wx/dnd.h"
15 #include "wx/window.h"
16 #include "wx/app.h"
17 #include "wx/gdicmn.h"
18 #include <wx/intl.h>
19
20 #include "gdk/gdkprivate.h"
21
22 #include <X11/Xlib.h>
23
24 // ----------------------------------------------------------------------------
25 // global
26 // ----------------------------------------------------------------------------
27
28 extern bool g_blockEventsOnDrag;
29
30 #ifdef NEW_GTK_DND_CODE
31
32 #include "gtk/gtkdnd.h"
33 #include "gtk/gtkselection.h"
34
35 // ----------------------------------------------------------------------------
36 // "drag_leave"
37 // ----------------------------------------------------------------------------
38
39 static void target_drag_leave( GtkWidget *WXUNUSED(widget),
40 GdkDragContext *WXUNUSED(context),
41 guint WXUNUSED(time) )
42 {
43 printf( "leave.\n" );
44 }
45
46 // ----------------------------------------------------------------------------
47 // "drag_motion"
48 // ----------------------------------------------------------------------------
49
50 static gboolean target_drag_motion( GtkWidget *WXUNUSED(widget),
51 GdkDragContext *context,
52 gint WXUNUSED(x),
53 gint WXUNUSED(y),
54 guint time )
55 {
56 printf( "motion.\n" );
57 gdk_drag_status( context, context->suggested_action, time );
58 return TRUE;
59 }
60
61 // ----------------------------------------------------------------------------
62 // "drag_drop"
63 // ----------------------------------------------------------------------------
64
65 static gboolean target_drag_drop( GtkWidget *widget,
66 GdkDragContext *context,
67 gint x,
68 gint y,
69 guint time )
70 {
71 printf( "drop at: %d,%d.\n", x, y );
72
73 if (context->targets)
74 {
75 gtk_drag_get_data( widget,
76 context,
77 GPOINTER_TO_INT (context->targets->data),
78 time );
79 }
80 return FALSE;
81 }
82
83 // ----------------------------------------------------------------------------
84 // "drag_data_received"
85 // ----------------------------------------------------------------------------
86
87 static void target_drag_data_received( GtkWidget *WXUNUSED(widget),
88 GdkDragContext *context,
89 gint x,
90 gint y,
91 GtkSelectionData *data,
92 guint WXUNUSED(info),
93 guint time )
94 {
95 printf( "data receive at: %d,%d.\n", x, y );
96
97 if ((data->length >= 0) && (data->format == 8))
98 {
99 wxString str = (const char*)data->data;
100 printf( "Received %s\n.", WXSTRINGCAST str );
101 gtk_drag_finish( context, TRUE, FALSE, time );
102 return;
103 }
104
105 gtk_drag_finish (context, FALSE, FALSE, time);
106 }
107
108 // ----------------------------------------------------------------------------
109 // wxDropTarget
110 // ----------------------------------------------------------------------------
111
112 wxDropTarget::wxDropTarget()
113 {
114 }
115
116 wxDropTarget::~wxDropTarget()
117 {
118 }
119
120 void wxDropTarget::UnregisterWidget( GtkWidget *widget )
121 {
122 wxCHECK_RET( widget != NULL, "unregister widget is NULL" );
123
124 gtk_drag_dest_set( widget,
125 (GtkDestDefaults) 0,
126 (GtkTargetEntry*) NULL,
127 0,
128 (GdkDragAction) 0 );
129
130 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
131 GTK_SIGNAL_FUNC(target_drag_leave), (gpointer) this );
132
133 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
134 GTK_SIGNAL_FUNC(target_drag_motion), (gpointer) this );
135
136 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
137 GTK_SIGNAL_FUNC(target_drag_drop), (gpointer) this );
138
139 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
140 GTK_SIGNAL_FUNC(target_drag_data_received), (gpointer) this );
141 }
142
143 void wxDropTarget::RegisterWidget( GtkWidget *widget )
144 {
145 wxCHECK_RET( widget != NULL, "register widget is NULL" );
146
147 GtkTargetEntry format;
148 format.info = 0;
149 format.flags = 0;
150
151 int valid = 0;
152 for ( size_t i = 0; i < GetFormatCount(); i++ )
153 {
154 wxDataFormat df = GetFormat( i );
155 switch (df)
156 {
157 case wxDF_TEXT:
158 format.target = "text/plain";
159 valid++;
160 break;
161 case wxDF_FILENAME:
162 format.target = "file:ALL";
163 valid++;
164 break;
165 default:
166 break;
167 }
168 }
169
170 wxASSERT_MSG( valid != 0, "No valid DnD format supported." );
171
172 gtk_drag_dest_set( widget,
173 GTK_DEST_DEFAULT_ALL,
174 &format,
175 1,
176 (GdkDragAction)(GDK_ACTION_COPY | GDK_ACTION_MOVE) );
177
178 gtk_signal_connect( GTK_OBJECT(widget), "drag_leave",
179 GTK_SIGNAL_FUNC(target_drag_leave), (gpointer) this );
180
181 gtk_signal_connect( GTK_OBJECT(widget), "drag_motion",
182 GTK_SIGNAL_FUNC(target_drag_motion), (gpointer) this );
183
184 gtk_signal_connect( GTK_OBJECT(widget), "drag_drop",
185 GTK_SIGNAL_FUNC(target_drag_drop), (gpointer) this );
186
187 gtk_signal_connect( GTK_OBJECT(widget), "drag_data_received",
188 GTK_SIGNAL_FUNC(target_drag_data_received), (gpointer) this );
189 }
190
191 // ----------------------------------------------------------------------------
192 // wxTextDropTarget
193 // ----------------------------------------------------------------------------
194
195 bool wxTextDropTarget::OnDrop( long x, long y, const void *data, size_t WXUNUSED(size) )
196 {
197 OnDropText( x, y, (const char*)data );
198 return TRUE;
199 }
200
201 bool wxTextDropTarget::OnDropText( long x, long y, const char *psz )
202 {
203 printf( "Got dropped text: %s.\n", psz );
204 printf( "At x: %d, y: %d.\n", (int)x, (int)y );
205 return TRUE;
206 }
207
208 size_t wxTextDropTarget::GetFormatCount() const
209 {
210 return 1;
211 }
212
213 wxDataFormat wxTextDropTarget::GetFormat(size_t WXUNUSED(n)) const
214 {
215 return wxDF_TEXT;
216 }
217
218 // ----------------------------------------------------------------------------
219 // wxFileDropTarget
220 // ----------------------------------------------------------------------------
221
222 bool wxFileDropTarget::OnDropFiles( long x, long y, size_t nFiles, const char * const aszFiles[] )
223 {
224 printf( "Got %d dropped files.\n", (int)nFiles );
225 printf( "At x: %d, y: %d.\n", (int)x, (int)y );
226 for (size_t i = 0; i < nFiles; i++)
227 {
228 printf( aszFiles[i] );
229 printf( "\n" );
230 }
231 return TRUE;
232 }
233
234 bool wxFileDropTarget::OnDrop(long x, long y, const void *data, size_t size )
235 {
236 size_t number = 0;
237 char *text = (char*) data;
238 for (size_t i = 0; i < size; i++)
239 if (text[i] == 0) number++;
240
241 if (number == 0) return TRUE;
242
243 char **files = new char*[number];
244
245 text = (char*) data;
246 for (size_t i = 0; i < number; i++)
247 {
248 files[i] = text;
249 int len = strlen( text );
250 text += len+1;
251 }
252
253 bool ret = OnDropFiles( x, y, 1, files );
254
255 free( files );
256
257 return ret;
258 }
259
260 size_t wxFileDropTarget::GetFormatCount() const
261 {
262 return 1;
263 }
264
265 wxDataFormat wxFileDropTarget::GetFormat(size_t WXUNUSED(n)) const
266 {
267 return wxDF_FILENAME;
268 }
269
270 //-------------------------------------------------------------------------
271 // wxDropSource
272 //-------------------------------------------------------------------------
273
274 wxDropSource::wxDropSource( wxWindow *win )
275 {
276 g_blockEventsOnDrag = TRUE;
277
278 m_window = win;
279 m_widget = win->m_widget;
280 if (win->m_wxwindow) m_widget = win->m_wxwindow;
281
282 m_data = (wxDataObject *) NULL;
283 m_retValue = wxDragCancel;
284
285 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
286 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
287 }
288
289 wxDropSource::wxDropSource( wxDataObject &data, wxWindow *win )
290 {
291 g_blockEventsOnDrag = TRUE;
292
293 m_window = win;
294 m_widget = win->m_widget;
295 if (win->m_wxwindow) m_widget = win->m_wxwindow;
296 m_retValue = wxDragCancel;
297
298 m_data = &data;
299
300 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
301 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
302 }
303
304 void wxDropSource::SetData( wxDataObject &data )
305 {
306 m_data = &data;
307 }
308
309 wxDropSource::~wxDropSource(void)
310 {
311 // if (m_data) delete m_data;
312
313 g_blockEventsOnDrag = FALSE;
314 }
315
316 wxDragResult wxDropSource::DoDragDrop( bool WXUNUSED(bAllowMove) )
317 {
318 wxASSERT_MSG( m_data, "wxDragSource: no data" );
319
320 if (!m_data) return (wxDragResult) wxDragNone;
321 if (m_data->GetDataSize() == 0) return (wxDragResult) wxDragNone;
322
323 RegisterWindow();
324
325 // TODO
326
327 UnregisterWindow();
328
329 g_blockEventsOnDrag = FALSE;
330
331 return m_retValue;
332 }
333
334 void wxDropSource::RegisterWindow(void)
335 {
336 if (!m_data) return;
337
338 wxString formats;
339
340 wxDataFormat df = m_data->GetPreferredFormat();
341
342 switch (df)
343 {
344 case wxDF_TEXT:
345 formats += "text/plain";
346 break;
347 case wxDF_FILENAME:
348 formats += "file:ALL";
349 break;
350 default:
351 break;
352 }
353
354 char *str = WXSTRINGCAST formats;
355
356 // TODO
357 }
358
359 void wxDropSource::UnregisterWindow(void)
360 {
361 if (!m_widget) return;
362
363 // TODO
364 }
365
366
367 #else // NEW_CODE
368
369
370
371 //-----------------------------------------------------------------------------
372 // "drop_data_available_event"
373 //-----------------------------------------------------------------------------
374
375 static void gtk_target_callback( GtkWidget *widget,
376 GdkEventDropDataAvailable *event,
377 wxDropTarget *target )
378 {
379 if (target)
380 {
381 int x = 0;
382 int y = 0;
383 gdk_window_get_pointer( widget->window, &x, &y, (GdkModifierType *) NULL );
384
385 printf( "Drop data is of type %s.\n", event->data_type );
386
387 target->OnDrop( x, y, (const void*)event->data, (size_t)event->data_numbytes );
388 }
389
390 /*
391 g_free (event->data);
392 g_free (event->data_type);
393 */
394 }
395
396 // ----------------------------------------------------------------------------
397 // wxDropTarget
398 // ----------------------------------------------------------------------------
399
400 wxDropTarget::wxDropTarget()
401 {
402 }
403
404 wxDropTarget::~wxDropTarget()
405 {
406 }
407
408 void wxDropTarget::UnregisterWidget( GtkWidget *widget )
409 {
410 if (!widget) return;
411
412 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
413 GTK_SIGNAL_FUNC(gtk_target_callback), (gpointer) this );
414
415 gtk_widget_dnd_drop_set( widget, FALSE, (gchar **) NULL, 0, FALSE );
416 }
417
418 void wxDropTarget::RegisterWidget( GtkWidget *widget )
419 {
420 wxString formats;
421 int valid = 0;
422
423 for ( size_t i = 0; i < GetFormatCount(); i++ )
424 {
425 wxDataFormat df = GetFormat( i );
426 switch (df)
427 {
428 case wxDF_TEXT:
429 if (i > 0) formats += ";";
430 formats += "text/plain";
431 valid++;
432 break;
433 case wxDF_FILENAME:
434 if (i > 0) formats += ";";
435 formats += "file:ALL";
436 valid++;
437 break;
438 default:
439 break;
440 }
441 }
442
443 char *str = WXSTRINGCAST formats;
444
445 gtk_widget_dnd_drop_set( widget, TRUE, &str, valid, FALSE );
446
447 gtk_signal_connect( GTK_OBJECT(widget), "drop_data_available_event",
448 GTK_SIGNAL_FUNC(gtk_target_callback), (gpointer) this );
449 }
450
451 // ----------------------------------------------------------------------------
452 // wxTextDropTarget
453 // ----------------------------------------------------------------------------
454
455 bool wxTextDropTarget::OnDrop( long x, long y, const void *data, size_t WXUNUSED(size) )
456 {
457 OnDropText( x, y, (const char*)data );
458 return TRUE;
459 }
460
461 bool wxTextDropTarget::OnDropText( long x, long y, const char *psz )
462 {
463 printf( "Got dropped text: %s.\n", psz );
464 printf( "At x: %d, y: %d.\n", (int)x, (int)y );
465 return TRUE;
466 }
467
468 size_t wxTextDropTarget::GetFormatCount() const
469 {
470 return 1;
471 }
472
473 wxDataFormat wxTextDropTarget::GetFormat(size_t WXUNUSED(n)) const
474 {
475 return wxDF_TEXT;
476 }
477
478 // ----------------------------------------------------------------------------
479 // wxFileDropTarget
480 // ----------------------------------------------------------------------------
481
482 bool wxFileDropTarget::OnDropFiles( long x, long y, size_t nFiles, const char * const aszFiles[] )
483 {
484 printf( "Got %d dropped files.\n", (int)nFiles );
485 printf( "At x: %d, y: %d.\n", (int)x, (int)y );
486 for (size_t i = 0; i < nFiles; i++)
487 {
488 printf( aszFiles[i] );
489 printf( "\n" );
490 }
491 return TRUE;
492 }
493
494 bool wxFileDropTarget::OnDrop(long x, long y, const void *data, size_t size )
495 {
496 size_t number = 0;
497 char *text = (char*) data;
498 for (size_t i = 0; i < size; i++)
499 if (text[i] == 0) number++;
500
501 if (number == 0) return TRUE;
502
503 char **files = new char*[number];
504
505 text = (char*) data;
506 for (size_t i = 0; i < number; i++)
507 {
508 files[i] = text;
509 int len = strlen( text );
510 text += len+1;
511 }
512
513 bool ret = OnDropFiles( x, y, 1, files );
514
515 free( files );
516
517 return ret;
518 }
519
520 size_t wxFileDropTarget::GetFormatCount() const
521 {
522 return 1;
523 }
524
525 wxDataFormat wxFileDropTarget::GetFormat(size_t WXUNUSED(n)) const
526 {
527 return wxDF_FILENAME;
528 }
529
530 //-------------------------------------------------------------------------
531 // wxDropSource
532 //-------------------------------------------------------------------------
533
534 //-----------------------------------------------------------------------------
535 // drag request
536
537 void gtk_drag_callback( GtkWidget *widget, GdkEvent *event, wxDropSource *source )
538 {
539 printf( "Data requested for dropping.\n" );
540
541 wxDataObject *data = source->m_data;
542
543 size_t size = data->GetDataSize();
544 char *ptr = new char[size];
545 data->GetDataHere( ptr );
546
547 gtk_widget_dnd_data_set( widget, event, ptr, size );
548
549 delete ptr;
550
551 source->m_retValue = wxDragCopy;
552 }
553
554 wxDropSource::wxDropSource( wxWindow *win )
555 {
556 g_blockEventsOnDrag = TRUE;
557
558 m_window = win;
559 m_widget = win->m_widget;
560 if (win->m_wxwindow) m_widget = win->m_wxwindow;
561
562 m_data = (wxDataObject *) NULL;
563 m_retValue = wxDragCancel;
564
565 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
566 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
567 }
568
569 wxDropSource::wxDropSource( wxDataObject &data, wxWindow *win )
570 {
571 g_blockEventsOnDrag = TRUE;
572
573 m_window = win;
574 m_widget = win->m_widget;
575 if (win->m_wxwindow) m_widget = win->m_wxwindow;
576 m_retValue = wxDragCancel;
577
578 m_data = &data;
579
580 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
581 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
582 }
583
584 void wxDropSource::SetData( wxDataObject &data )
585 {
586 m_data = &data;
587 }
588
589 wxDropSource::~wxDropSource(void)
590 {
591 // if (m_data) delete m_data;
592
593 g_blockEventsOnDrag = FALSE;
594 }
595
596 wxDragResult wxDropSource::DoDragDrop( bool WXUNUSED(bAllowMove) )
597 {
598 if (gdk_dnd.dnd_grabbed) return (wxDragResult) wxDragNone;
599 if (gdk_dnd.drag_really) return (wxDragResult) wxDragNone;
600
601 wxASSERT_MSG( m_data, "wxDragSource: no data" );
602
603 if (!m_data) return (wxDragResult) wxDragNone;
604 if (m_data->GetDataSize() == 0) return (wxDragResult) wxDragNone;
605
606 GdkWindowPrivate *wp = (GdkWindowPrivate*) m_widget->window;
607
608 RegisterWindow();
609
610 gdk_dnd.drag_perhaps = TRUE;
611
612 gdk_dnd.dnd_drag_start.x = 5;
613 gdk_dnd.dnd_drag_start.y = 5;
614 gdk_dnd.real_sw = wp;
615
616 if (gdk_dnd.drag_startwindows)
617 {
618 g_free( gdk_dnd.drag_startwindows );
619 gdk_dnd.drag_startwindows = (GdkWindow **) NULL;
620 }
621 gdk_dnd.drag_numwindows = gdk_dnd.drag_really = 0;
622
623 XWindowAttributes dnd_winattr;
624 XGetWindowAttributes( gdk_display, wp->xwindow, &dnd_winattr );
625 wp->dnd_drag_savedeventmask = dnd_winattr.your_event_mask;
626
627 gdk_dnd_drag_addwindow( m_widget->window );
628
629 GdkEventDragBegin ev;
630 ev.type = GDK_DRAG_BEGIN;
631 ev.window = m_widget->window;
632 ev.u.allflags = 0;
633 ev.u.flags.protocol_version = DND_PROTOCOL_VERSION;
634
635 gdk_event_put( (GdkEvent*)&ev );
636
637 XGrabPointer( gdk_display, wp->xwindow, False,
638 ButtonMotionMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
639 GrabModeAsync, GrabModeAsync, gdk_root_window, None, CurrentTime );
640
641 gdk_dnd_set_drag_cursors( m_defaultCursor.GetCursor(), m_goaheadCursor.GetCursor() );
642
643 gdk_dnd.dnd_grabbed = TRUE;
644 gdk_dnd.drag_really = 1;
645
646 int x = 0;
647 int y = 0;
648 gdk_window_get_pointer( m_widget->window, &x, &y, (GdkModifierType *) NULL );
649
650 gdk_dnd_display_drag_cursor( x, y, FALSE, TRUE );
651
652 while (gdk_dnd.drag_really || gdk_dnd.drag_perhaps) wxYield();
653
654 UnregisterWindow();
655
656 g_blockEventsOnDrag = FALSE;
657
658 return m_retValue;
659 }
660
661 void wxDropSource::RegisterWindow(void)
662 {
663 if (!m_data) return;
664
665 wxString formats;
666
667 wxDataFormat df = m_data->GetPreferredFormat();
668
669 switch (df)
670 {
671 case wxDF_TEXT:
672 formats += "text/plain";
673 break;
674 case wxDF_FILENAME:
675 formats += "file:ALL";
676 break;
677 default:
678 break;
679 }
680
681 char *str = WXSTRINGCAST formats;
682
683 gtk_widget_dnd_drag_set( m_widget, TRUE, &str, 1 );
684
685 gtk_signal_connect( GTK_OBJECT(m_widget), "drag_request_event",
686 GTK_SIGNAL_FUNC(gtk_drag_callback), (gpointer)this );
687 }
688
689 void wxDropSource::UnregisterWindow(void)
690 {
691 if (!m_widget) return;
692
693 gtk_widget_dnd_drag_set( m_widget, FALSE, (gchar **) NULL, 0 );
694
695 gtk_signal_disconnect_by_data( GTK_OBJECT(m_widget), (gpointer)this );
696 }
697
698 #endif
699 // NEW_GTK_DND_CODE
700