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