]> git.saurik.com Git - wxWidgets.git/blame - src/gtk1/dnd.cpp
* Fixed a memory leak in wxThread
[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"
15#include "wx/window.h"
16#include "wx/app.h"
17#include "wx/gdicmn.h"
1a5a8367 18#include <wx/intl.h>
c801d85f
KB
19
20#include "gdk/gdkprivate.h"
21
22#include <X11/Xlib.h>
23
24// ----------------------------------------------------------------------------
25// global
26// ----------------------------------------------------------------------------
27
28extern bool g_blockEventsOnDrag;
29
f5368809
RR
30#ifdef NEW_GTK_DND_CODE
31
33a5bc52
RR
32#include "gtk/gtkdnd.h"
33#include "gtk/gtkselection.h"
34
35// ----------------------------------------------------------------------------
36// "drag_leave"
37// ----------------------------------------------------------------------------
38
39static 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
50static 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
65static 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
87static 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
f5368809
RR
112wxDropTarget::wxDropTarget()
113{
114}
115
116wxDropTarget::~wxDropTarget()
117{
118}
119
120void wxDropTarget::UnregisterWidget( GtkWidget *widget )
121{
33a5bc52 122 wxCHECK_RET( widget != NULL, "unregister widget is NULL" );
f5368809 123
33a5bc52
RR
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 );
f5368809
RR
141}
142
143void wxDropTarget::RegisterWidget( GtkWidget *widget )
144{
33a5bc52 145 wxCHECK_RET( widget != NULL, "register widget is NULL" );
f5368809 146
33a5bc52
RR
147 GtkTargetEntry format;
148 format.info = 0;
149 format.flags = 0;
f5368809 150
33a5bc52 151 int valid = 0;
f5368809
RR
152 for ( size_t i = 0; i < GetFormatCount(); i++ )
153 {
154 wxDataFormat df = GetFormat( i );
155 switch (df)
156 {
157 case wxDF_TEXT:
33a5bc52 158 format.target = "text/plain";
f5368809
RR
159 valid++;
160 break;
161 case wxDF_FILENAME:
33a5bc52 162 format.target = "file:ALL";
f5368809
RR
163 valid++;
164 break;
165 default:
166 break;
167 }
168 }
169
33a5bc52 170 wxASSERT_MSG( valid != 0, "No valid DnD format supported." );
f5368809 171
33a5bc52
RR
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 );
f5368809
RR
189}
190
191// ----------------------------------------------------------------------------
192// wxTextDropTarget
193// ----------------------------------------------------------------------------
194
195bool 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
201bool 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
208size_t wxTextDropTarget::GetFormatCount() const
209{
210 return 1;
211}
212
213wxDataFormat wxTextDropTarget::GetFormat(size_t WXUNUSED(n)) const
214{
215 return wxDF_TEXT;
216}
217
218// ----------------------------------------------------------------------------
219// wxFileDropTarget
220// ----------------------------------------------------------------------------
221
222bool 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
234bool 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
260size_t wxFileDropTarget::GetFormatCount() const
261{
262 return 1;
263}
264
265wxDataFormat wxFileDropTarget::GetFormat(size_t WXUNUSED(n)) const
266{
267 return wxDF_FILENAME;
268}
269
270//-------------------------------------------------------------------------
271// wxDropSource
272//-------------------------------------------------------------------------
273
274wxDropSource::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
289wxDropSource::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
304void wxDropSource::SetData( wxDataObject &data )
305{
306 m_data = &data;
307}
308
309wxDropSource::~wxDropSource(void)
310{
311// if (m_data) delete m_data;
312
313 g_blockEventsOnDrag = FALSE;
314}
315
316wxDragResult 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
334void 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
359void wxDropSource::UnregisterWindow(void)
360{
361 if (!m_widget) return;
362
363 // TODO
364}
365
33a5bc52
RR
366
367#else // NEW_CODE
368
369
370
371//-----------------------------------------------------------------------------
372// "drop_data_available_event"
373//-----------------------------------------------------------------------------
374
375static 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}
f5368809 395
c801d85f
KB
396// ----------------------------------------------------------------------------
397// wxDropTarget
398// ----------------------------------------------------------------------------
399
400wxDropTarget::wxDropTarget()
401{
ff7b1510 402}
c801d85f
KB
403
404wxDropTarget::~wxDropTarget()
405{
ff7b1510 406}
c801d85f 407
c801d85f
KB
408void wxDropTarget::UnregisterWidget( GtkWidget *widget )
409{
33a5bc52 410 if (!widget) return;
e3e65dac 411
33a5bc52
RR
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 );
ff7b1510 416}
c801d85f 417
e3e65dac
RR
418void wxDropTarget::RegisterWidget( GtkWidget *widget )
419{
33a5bc52
RR
420 wxString formats;
421 int valid = 0;
e3e65dac 422
33a5bc52 423 for ( size_t i = 0; i < GetFormatCount(); i++ )
e3e65dac 424 {
33a5bc52
RR
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 }
ff7b1510 441 }
e3e65dac 442
33a5bc52 443 char *str = WXSTRINGCAST formats;
e3e65dac 444
33a5bc52
RR
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 );
ff7b1510 449}
e3e65dac 450
c801d85f
KB
451// ----------------------------------------------------------------------------
452// wxTextDropTarget
453// ----------------------------------------------------------------------------
454
dc86cb34 455bool wxTextDropTarget::OnDrop( long x, long y, const void *data, size_t WXUNUSED(size) )
c801d85f 456{
33a5bc52
RR
457 OnDropText( x, y, (const char*)data );
458 return TRUE;
ff7b1510 459}
c801d85f
KB
460
461bool wxTextDropTarget::OnDropText( long x, long y, const char *psz )
462{
33a5bc52
RR
463 printf( "Got dropped text: %s.\n", psz );
464 printf( "At x: %d, y: %d.\n", (int)x, (int)y );
465 return TRUE;
ff7b1510 466}
c801d85f 467
e3e65dac 468size_t wxTextDropTarget::GetFormatCount() const
c801d85f 469{
33a5bc52 470 return 1;
e3e65dac
RR
471}
472
473wxDataFormat wxTextDropTarget::GetFormat(size_t WXUNUSED(n)) const
474{
33a5bc52 475 return wxDF_TEXT;
e3e65dac
RR
476}
477
478// ----------------------------------------------------------------------------
479// wxFileDropTarget
480// ----------------------------------------------------------------------------
481
e5403d7c 482bool wxFileDropTarget::OnDropFiles( long x, long y, size_t nFiles, const char * const aszFiles[] )
e3e65dac 483{
33a5bc52
RR
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;
e3e65dac
RR
492}
493
dc86cb34 494bool wxFileDropTarget::OnDrop(long x, long y, const void *data, size_t size )
e3e65dac 495{
33a5bc52
RR
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++;
e5403d7c 500
33a5bc52 501 if (number == 0) return TRUE;
e5403d7c 502
33a5bc52 503 char **files = new char*[number];
e5403d7c 504
33a5bc52
RR
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 }
e3e65dac 512
33a5bc52 513 bool ret = OnDropFiles( x, y, 1, files );
e5403d7c 514
33a5bc52 515 free( files );
e5403d7c 516
33a5bc52 517 return ret;
e3e65dac
RR
518}
519
520size_t wxFileDropTarget::GetFormatCount() const
521{
33a5bc52 522 return 1;
e3e65dac
RR
523}
524
525wxDataFormat wxFileDropTarget::GetFormat(size_t WXUNUSED(n)) const
526{
33a5bc52 527 return wxDF_FILENAME;
e3e65dac 528}
c801d85f
KB
529
530//-------------------------------------------------------------------------
e3e65dac 531// wxDropSource
c801d85f
KB
532//-------------------------------------------------------------------------
533
534//-----------------------------------------------------------------------------
535// drag request
536
b6af8d80 537void gtk_drag_callback( GtkWidget *widget, GdkEvent *event, wxDropSource *source )
c801d85f 538{
e3e65dac
RR
539 printf( "Data requested for dropping.\n" );
540
b6af8d80
RR
541 wxDataObject *data = source->m_data;
542
c86f1403 543 size_t size = data->GetDataSize();
e3e65dac
RR
544 char *ptr = new char[size];
545 data->GetDataHere( ptr );
546
547 gtk_widget_dnd_data_set( widget, event, ptr, size );
c801d85f 548
e3e65dac 549 delete ptr;
b6af8d80 550
46ccb510 551 source->m_retValue = wxDragCopy;
ff7b1510 552}
c801d85f 553
e3e65dac 554wxDropSource::wxDropSource( wxWindow *win )
c801d85f
KB
555{
556 g_blockEventsOnDrag = TRUE;
e3e65dac 557
c801d85f
KB
558 m_window = win;
559 m_widget = win->m_widget;
560 if (win->m_wxwindow) m_widget = win->m_wxwindow;
c801d85f 561
c67daf87 562 m_data = (wxDataObject *) NULL;
46ccb510 563 m_retValue = wxDragCancel;
e3e65dac 564
c801d85f
KB
565 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
566 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
ff7b1510 567}
c801d85f 568
e3e65dac 569wxDropSource::wxDropSource( wxDataObject &data, wxWindow *win )
c801d85f 570{
e3e65dac
RR
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;
46ccb510 576 m_retValue = wxDragCancel;
e3e65dac
RR
577
578 m_data = &data;
579
580 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
581 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
ff7b1510 582}
e3e65dac
RR
583
584void wxDropSource::SetData( wxDataObject &data )
c801d85f 585{
e3e65dac 586 m_data = &data;
ff7b1510 587}
c801d85f 588
e3e65dac 589wxDropSource::~wxDropSource(void)
c801d85f 590{
e3e65dac
RR
591// if (m_data) delete m_data;
592
593 g_blockEventsOnDrag = FALSE;
ff7b1510 594}
e3e65dac 595
46ccb510 596wxDragResult wxDropSource::DoDragDrop( bool WXUNUSED(bAllowMove) )
e3e65dac 597{
46ccb510
JS
598 if (gdk_dnd.dnd_grabbed) return (wxDragResult) wxDragNone;
599 if (gdk_dnd.drag_really) return (wxDragResult) wxDragNone;
e3e65dac 600
f6d53978 601 wxASSERT_MSG( m_data, "wxDragSource: no data" );
b6af8d80 602
46ccb510
JS
603 if (!m_data) return (wxDragResult) wxDragNone;
604 if (m_data->GetDataSize() == 0) return (wxDragResult) wxDragNone;
c801d85f
KB
605
606 GdkWindowPrivate *wp = (GdkWindowPrivate*) m_widget->window;
607
608 RegisterWindow();
c801d85f
KB
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 );
c67daf87 619 gdk_dnd.drag_startwindows = (GdkWindow **) NULL;
ff7b1510 620 }
c801d85f
KB
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;
e3e65dac
RR
645
646 int x = 0;
647 int y = 0;
c67daf87 648 gdk_window_get_pointer( m_widget->window, &x, &y, (GdkModifierType *) NULL );
e3e65dac 649
c801d85f
KB
650 gdk_dnd_display_drag_cursor( x, y, FALSE, TRUE );
651
652 while (gdk_dnd.drag_really || gdk_dnd.drag_perhaps) wxYield();
653
c801d85f 654 UnregisterWindow();
e3e65dac 655
30dea054
RR
656 g_blockEventsOnDrag = FALSE;
657
b6af8d80 658 return m_retValue;
ff7b1510 659}
c801d85f 660
e3e65dac 661void wxDropSource::RegisterWindow(void)
c801d85f 662{
e3e65dac 663 if (!m_data) return;
c801d85f 664
e3e65dac
RR
665 wxString formats;
666
667 wxDataFormat df = m_data->GetPreferredFormat();
c801d85f 668
e3e65dac
RR
669 switch (df)
670 {
671 case wxDF_TEXT:
672 formats += "text/plain";
673 break;
674 case wxDF_FILENAME:
61607c36 675 formats += "file:ALL";
e3e65dac
RR
676 break;
677 default:
678 break;
679 }
c801d85f 680
e3e65dac 681 char *str = WXSTRINGCAST formats;
c801d85f 682
e3e65dac 683 gtk_widget_dnd_drag_set( m_widget, TRUE, &str, 1 );
c801d85f 684
e3e65dac 685 gtk_signal_connect( GTK_OBJECT(m_widget), "drag_request_event",
b6af8d80 686 GTK_SIGNAL_FUNC(gtk_drag_callback), (gpointer)this );
ff7b1510 687}
c801d85f 688
e3e65dac 689void wxDropSource::UnregisterWindow(void)
c801d85f
KB
690{
691 if (!m_widget) return;
692
c67daf87 693 gtk_widget_dnd_drag_set( m_widget, FALSE, (gchar **) NULL, 0 );
e3e65dac 694
b6af8d80 695 gtk_signal_disconnect_by_data( GTK_OBJECT(m_widget), (gpointer)this );
ff7b1510 696}
f5368809
RR
697
698#endif
699 // NEW_GTK_DND_CODE
700