]>
Commit | Line | Data |
---|---|---|
dc86cb34 RR |
1 | ///////////////////////////////////////////////////////////////////////////// |
2 | // Name: clipbrd.cpp | |
3 | // Purpose: | |
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 "clipbrd.h" | |
12 | #endif | |
13 | ||
14 | #include "wx/clipbrd.h" | |
15 | ||
06cfab17 | 16 | #if wxUSE_CLIPBOARD |
ac57418f | 17 | |
034be888 RR |
18 | #include "wx/utils.h" |
19 | ||
83624f79 RR |
20 | #include "glib.h" |
21 | #include "gdk/gdk.h" | |
22 | #include "gtk/gtk.h" | |
23 | ||
b453e1b2 RR |
24 | //----------------------------------------------------------------------------- |
25 | // thread system | |
26 | //----------------------------------------------------------------------------- | |
27 | ||
28 | #if wxUSE_THREADS | |
29 | extern void wxapp_install_thread_wakeup(); | |
30 | extern void wxapp_uninstall_thread_wakeup(); | |
31 | #endif | |
32 | ||
dc86cb34 RR |
33 | //----------------------------------------------------------------------------- |
34 | // data | |
35 | //----------------------------------------------------------------------------- | |
36 | ||
37 | wxClipboard *wxTheClipboard = (wxClipboard*) NULL; | |
38 | ||
fd0eed64 | 39 | GdkAtom g_clipboardAtom = 0; |
b527aac5 | 40 | GdkAtom g_targetsAtom = 0; |
fd0eed64 | 41 | |
dc86cb34 | 42 | //----------------------------------------------------------------------------- |
b527aac5 | 43 | // reminder |
dc86cb34 RR |
44 | //----------------------------------------------------------------------------- |
45 | ||
b527aac5 RR |
46 | /* The contents of a selection are returned in a GtkSelectionData |
47 | structure. selection/target identify the request. | |
48 | type specifies the type of the return; if length < 0, and | |
49 | the data should be ignored. This structure has object semantics - | |
50 | no fields should be modified directly, they should not be created | |
51 | directly, and pointers to them should not be stored beyond the duration of | |
52 | a callback. (If the last is changed, we'll need to add reference | |
53 | counting) | |
54 | ||
55 | struct _GtkSelectionData | |
dc86cb34 | 56 | { |
b527aac5 RR |
57 | GdkAtom selection; |
58 | GdkAtom target; | |
59 | GdkAtom type; | |
60 | gint format; | |
61 | guchar *data; | |
62 | gint length; | |
63 | }; | |
64 | ||
65 | */ | |
dc86cb34 | 66 | |
b527aac5 RR |
67 | //----------------------------------------------------------------------------- |
68 | // "selection_received" for targets | |
69 | //----------------------------------------------------------------------------- | |
70 | ||
71 | static void | |
72 | targets_selection_received( GtkWidget *WXUNUSED(widget), | |
73 | GtkSelectionData *selection_data, | |
034be888 RR |
74 | #if (GTK_MINOR_VERSION > 0) |
75 | guint32 WXUNUSED(time), | |
76 | #endif | |
b527aac5 | 77 | wxClipboard *clipboard ) |
dc86cb34 | 78 | { |
034be888 RR |
79 | if (!wxTheClipboard) |
80 | { | |
81 | clipboard->m_waiting = FALSE; | |
82 | return; | |
83 | } | |
b527aac5 | 84 | |
034be888 RR |
85 | if (selection_data->length <= 0) |
86 | { | |
87 | clipboard->m_waiting = FALSE; | |
88 | return; | |
89 | } | |
90 | ||
91 | /* make sure we got the data in the correct form */ | |
92 | if (selection_data->type != GDK_SELECTION_TYPE_ATOM) | |
93 | { | |
94 | clipboard->m_waiting = FALSE; | |
95 | return; | |
96 | } | |
b527aac5 | 97 | |
8b53e5a2 RR |
98 | // the atoms we received, holding a list of targets (= formats) |
99 | GdkAtom *atoms = (GdkAtom *)selection_data->data; | |
b527aac5 | 100 | |
8b53e5a2 RR |
101 | for (unsigned int i=0; i<selection_data->length/sizeof(GdkAtom); i++) |
102 | { | |
7e2c43b8 | 103 | /* char *name = gdk_atom_name (atoms[i]); |
ca35e608 | 104 | if (name) printf( "Format available: %s.\n", name ); */ |
3c1b65a4 | 105 | |
8b53e5a2 RR |
106 | if (atoms[i] == clipboard->m_targetRequested) |
107 | { | |
034be888 | 108 | clipboard->m_waiting = FALSE; |
8b53e5a2 RR |
109 | clipboard->m_formatSupported = TRUE; |
110 | return; | |
111 | } | |
112 | } | |
b527aac5 | 113 | |
034be888 | 114 | clipboard->m_waiting = FALSE; |
8b53e5a2 | 115 | return; |
dc86cb34 RR |
116 | } |
117 | ||
118 | //----------------------------------------------------------------------------- | |
b527aac5 | 119 | // "selection_received" for the actual data |
dc86cb34 RR |
120 | //----------------------------------------------------------------------------- |
121 | ||
fd0eed64 | 122 | static void |
b527aac5 RR |
123 | selection_received( GtkWidget *WXUNUSED(widget), |
124 | GtkSelectionData *selection_data, | |
034be888 RR |
125 | #if (GTK_MINOR_VERSION > 0) |
126 | guint32 WXUNUSED(time), | |
127 | #endif | |
b527aac5 | 128 | wxClipboard *clipboard ) |
dc86cb34 | 129 | { |
034be888 RR |
130 | if (!wxTheClipboard) |
131 | { | |
132 | clipboard->m_waiting = FALSE; | |
133 | return; | |
134 | } | |
b527aac5 | 135 | |
8b53e5a2 RR |
136 | wxDataObject *data_object = clipboard->m_receivedData; |
137 | ||
034be888 RR |
138 | if (!data_object) |
139 | { | |
140 | clipboard->m_waiting = FALSE; | |
141 | return; | |
142 | } | |
8b53e5a2 | 143 | |
034be888 RR |
144 | if (selection_data->length <= 0) |
145 | { | |
146 | clipboard->m_waiting = FALSE; | |
147 | return; | |
148 | } | |
b527aac5 | 149 | |
034be888 RR |
150 | /* make sure we got the data in the correct format */ |
151 | if (data_object->GetFormat().GetAtom() != selection_data->target) | |
152 | { | |
153 | clipboard->m_waiting = FALSE; | |
154 | return; | |
155 | } | |
e2acb9ae | 156 | |
034be888 RR |
157 | /* make sure we got the data in the correct form (selection type). |
158 | if so, copy data to target object */ | |
8b53e5a2 | 159 | |
0d2a2b60 | 160 | switch (data_object->GetFormat().GetType()) |
8b53e5a2 RR |
161 | { |
162 | case wxDF_TEXT: | |
163 | { | |
034be888 RR |
164 | if (selection_data->type != GDK_SELECTION_TYPE_STRING) |
165 | { | |
166 | clipboard->m_waiting = FALSE; | |
167 | return; | |
168 | } | |
8b53e5a2 RR |
169 | |
170 | wxTextDataObject *text_object = (wxTextDataObject *) data_object; | |
171 | ||
172 | wxString text = (const char*) selection_data->data; | |
173 | ||
174 | text_object->SetText( text ); | |
175 | ||
176 | break; | |
177 | } | |
178 | ||
179 | case wxDF_BITMAP: | |
180 | { | |
e2acb9ae | 181 | if (selection_data->type != GDK_SELECTION_TYPE_STRING) |
034be888 RR |
182 | { |
183 | clipboard->m_waiting = FALSE; | |
184 | return; | |
185 | } | |
8b53e5a2 | 186 | |
e2acb9ae RR |
187 | wxBitmapDataObject *bitmap_object = (wxBitmapDataObject *) data_object; |
188 | ||
189 | bitmap_object->SetPngData( (const char*) selection_data->data, (size_t) selection_data->length ); | |
190 | ||
8b53e5a2 RR |
191 | break; |
192 | } | |
193 | ||
194 | case wxDF_PRIVATE: | |
195 | { | |
034be888 RR |
196 | if (selection_data->type != GDK_SELECTION_TYPE_STRING) |
197 | { | |
198 | clipboard->m_waiting = FALSE; | |
199 | return; | |
200 | } | |
8b53e5a2 RR |
201 | |
202 | wxPrivateDataObject *private_object = (wxPrivateDataObject *) data_object; | |
203 | ||
204 | private_object->SetData( (const char*) selection_data->data, (size_t) selection_data->length ); | |
205 | ||
206 | break; | |
207 | } | |
208 | ||
209 | default: | |
210 | { | |
034be888 | 211 | clipboard->m_waiting = FALSE; |
8b53e5a2 RR |
212 | return; |
213 | } | |
214 | } | |
215 | ||
216 | wxTheClipboard->m_formatSupported = TRUE; | |
034be888 | 217 | clipboard->m_waiting = FALSE; |
dc86cb34 | 218 | } |
fd0eed64 RR |
219 | |
220 | //----------------------------------------------------------------------------- | |
221 | // "selection_clear" | |
222 | //----------------------------------------------------------------------------- | |
223 | ||
224 | static gint | |
aeeb6a44 | 225 | selection_clear_clip( GtkWidget *WXUNUSED(widget), GdkEventSelection *event ) |
fd0eed64 | 226 | { |
8b53e5a2 | 227 | if (!wxTheClipboard) return TRUE; |
2830bf19 | 228 | |
aeeb6a44 RR |
229 | if (event->selection == GDK_SELECTION_PRIMARY) |
230 | { | |
231 | wxTheClipboard->m_ownsPrimarySelection = FALSE; | |
232 | } | |
233 | else | |
234 | if (event->selection == g_clipboardAtom) | |
235 | { | |
236 | wxTheClipboard->m_ownsClipboard = FALSE; | |
237 | } | |
238 | else | |
239 | { | |
e5ea3f7a | 240 | wxTheClipboard->m_waiting = FALSE; |
aeeb6a44 RR |
241 | return FALSE; |
242 | } | |
243 | ||
244 | if ((!wxTheClipboard->m_ownsPrimarySelection) && | |
245 | (!wxTheClipboard->m_ownsClipboard)) | |
246 | { | |
db2d879a | 247 | /* the clipboard is no longer in our hands. we can the delete clipboard data. */ |
0d2a2b60 RR |
248 | if (wxTheClipboard->m_dataBroker) |
249 | { | |
250 | delete wxTheClipboard->m_dataBroker; | |
251 | wxTheClipboard->m_dataBroker = (wxDataBroker*) NULL; | |
252 | } | |
aeeb6a44 | 253 | } |
fd0eed64 | 254 | |
e5ea3f7a | 255 | wxTheClipboard->m_waiting = FALSE; |
8b53e5a2 | 256 | return TRUE; |
fd0eed64 RR |
257 | } |
258 | ||
259 | //----------------------------------------------------------------------------- | |
260 | // selection handler for supplying data | |
261 | //----------------------------------------------------------------------------- | |
262 | ||
263 | static void | |
264 | selection_handler( GtkWidget *WXUNUSED(widget), GtkSelectionData *selection_data, gpointer WXUNUSED(data) ) | |
265 | { | |
8b53e5a2 | 266 | if (!wxTheClipboard) return; |
fd0eed64 | 267 | |
0d2a2b60 RR |
268 | if (!wxTheClipboard->m_dataBroker) return; |
269 | ||
270 | wxNode *node = wxTheClipboard->m_dataBroker->m_dataObjects.First(); | |
8b53e5a2 RR |
271 | |
272 | while (node) | |
273 | { | |
274 | wxDataObject *data_object = (wxDataObject *)node->Data(); | |
e2acb9ae | 275 | |
0d2a2b60 | 276 | if (data_object->GetFormat().GetAtom() != selection_data->target) |
8b53e5a2 RR |
277 | { |
278 | node = node->Next(); | |
3874d10d | 279 | continue; |
8b53e5a2 RR |
280 | } |
281 | ||
0d2a2b60 | 282 | switch (data_object->GetFormat().GetType()) |
8b53e5a2 RR |
283 | { |
284 | case wxDF_TEXT: | |
285 | { | |
286 | wxTextDataObject *text_object = (wxTextDataObject*) data_object; | |
287 | ||
288 | wxString text = text_object->GetText(); | |
289 | ||
93c5dd39 OK |
290 | #if wxUSE_UNICODE |
291 | const wxWX2MBbuf s = text.mbc_str(); | |
292 | int len = strlen(s); | |
293 | #else // more efficient in non-Unicode | |
294 | const char *s = text.c_str(); | |
8b53e5a2 | 295 | int len = (int) text.Length(); |
93c5dd39 | 296 | #endif |
8b53e5a2 RR |
297 | |
298 | gtk_selection_data_set( | |
299 | selection_data, | |
300 | GDK_SELECTION_TYPE_STRING, | |
301 | 8*sizeof(gchar), | |
93c5dd39 | 302 | (unsigned char*) (const char*) s, |
8b53e5a2 RR |
303 | len ); |
304 | ||
305 | break; | |
306 | } | |
307 | ||
308 | case wxDF_BITMAP: | |
309 | { | |
e2acb9ae | 310 | wxBitmapDataObject *bitmap_object = (wxBitmapDataObject*) data_object; |
8b53e5a2 | 311 | |
e2acb9ae RR |
312 | if (bitmap_object->GetSize() == 0) return; |
313 | ||
314 | gtk_selection_data_set( | |
315 | selection_data, | |
316 | GDK_SELECTION_TYPE_STRING, | |
317 | 8*sizeof(gchar), | |
318 | (unsigned char*) bitmap_object->GetData(), | |
319 | (int) bitmap_object->GetSize() ); | |
320 | ||
8b53e5a2 RR |
321 | break; |
322 | } | |
323 | ||
324 | case wxDF_PRIVATE: | |
325 | { | |
326 | wxPrivateDataObject *private_object = (wxPrivateDataObject*) data_object; | |
327 | ||
0d2a2b60 | 328 | if (private_object->GetSize() == 0) return; |
8b53e5a2 RR |
329 | |
330 | gtk_selection_data_set( | |
331 | selection_data, | |
332 | GDK_SELECTION_TYPE_STRING, | |
333 | 8*sizeof(gchar), | |
334 | (unsigned char*) private_object->GetData(), | |
0d2a2b60 | 335 | (int) private_object->GetSize() ); |
8b53e5a2 RR |
336 | } |
337 | ||
338 | default: | |
339 | break; | |
340 | } | |
341 | ||
342 | node = node->Next(); | |
343 | } | |
fd0eed64 | 344 | } |
dc86cb34 RR |
345 | |
346 | //----------------------------------------------------------------------------- | |
347 | // wxClipboard | |
348 | //----------------------------------------------------------------------------- | |
349 | ||
350 | IMPLEMENT_DYNAMIC_CLASS(wxClipboard,wxObject) | |
351 | ||
352 | wxClipboard::wxClipboard() | |
353 | { | |
8b53e5a2 RR |
354 | m_open = FALSE; |
355 | ||
aeeb6a44 RR |
356 | m_ownsClipboard = FALSE; |
357 | m_ownsPrimarySelection = FALSE; | |
358 | ||
0d2a2b60 | 359 | m_dataBroker = (wxDataBroker*) NULL; |
fd0eed64 | 360 | |
8b53e5a2 | 361 | m_receivedData = (wxDataObject*) NULL; |
99c67c77 | 362 | |
034be888 RR |
363 | /* we use m_targetsWidget to query what formats are available */ |
364 | ||
365 | m_targetsWidget = gtk_window_new( GTK_WINDOW_POPUP ); | |
366 | gtk_widget_realize( m_targetsWidget ); | |
367 | ||
368 | gtk_signal_connect( GTK_OBJECT(m_targetsWidget), | |
369 | "selection_received", | |
370 | GTK_SIGNAL_FUNC( targets_selection_received ), | |
371 | (gpointer) this ); | |
372 | ||
373 | /* we use m_clipboardWidget to get and to offer data */ | |
374 | ||
8b53e5a2 RR |
375 | m_clipboardWidget = gtk_window_new( GTK_WINDOW_POPUP ); |
376 | gtk_widget_realize( m_clipboardWidget ); | |
377 | ||
034be888 RR |
378 | gtk_signal_connect( GTK_OBJECT(m_clipboardWidget), |
379 | "selection_received", | |
380 | GTK_SIGNAL_FUNC( selection_received ), | |
381 | (gpointer) this ); | |
382 | ||
8b53e5a2 RR |
383 | gtk_signal_connect( GTK_OBJECT(m_clipboardWidget), |
384 | "selection_clear_event", | |
aeeb6a44 | 385 | GTK_SIGNAL_FUNC( selection_clear_clip ), |
8b53e5a2 | 386 | (gpointer) NULL ); |
fd0eed64 | 387 | |
8b53e5a2 | 388 | if (!g_clipboardAtom) g_clipboardAtom = gdk_atom_intern( "CLIPBOARD", FALSE ); |
8b53e5a2 RR |
389 | if (!g_targetsAtom) g_targetsAtom = gdk_atom_intern ("TARGETS", FALSE); |
390 | ||
391 | m_formatSupported = FALSE; | |
392 | m_targetRequested = 0; | |
7e2c43b8 RR |
393 | |
394 | m_usePrimary = FALSE; | |
dc86cb34 RR |
395 | } |
396 | ||
397 | wxClipboard::~wxClipboard() | |
b527aac5 | 398 | { |
8b53e5a2 | 399 | Clear(); |
b527aac5 | 400 | |
8b53e5a2 | 401 | if (m_clipboardWidget) gtk_widget_destroy( m_clipboardWidget ); |
034be888 | 402 | if (m_targetsWidget) gtk_widget_destroy( m_targetsWidget ); |
b527aac5 RR |
403 | } |
404 | ||
405 | void wxClipboard::Clear() | |
dc86cb34 | 406 | { |
0d2a2b60 | 407 | if (m_dataBroker) |
8b53e5a2 | 408 | { |
b453e1b2 RR |
409 | #if wxUSE_THREADS |
410 | /* disable GUI threads */ | |
411 | wxapp_uninstall_thread_wakeup(); | |
412 | #endif | |
413 | ||
8b53e5a2 RR |
414 | /* As we have data we also own the clipboard. Once we no longer own |
415 | it, clear_selection is called which will set m_data to zero */ | |
aeeb6a44 | 416 | if (gdk_selection_owner_get( g_clipboardAtom ) == m_clipboardWidget->window) |
8b53e5a2 | 417 | { |
e5ea3f7a RR |
418 | m_waiting = TRUE; |
419 | ||
8b53e5a2 | 420 | gtk_selection_owner_set( (GtkWidget*) NULL, g_clipboardAtom, GDK_CURRENT_TIME ); |
e5ea3f7a RR |
421 | |
422 | while (m_waiting) gtk_main_iteration(); | |
8b53e5a2 | 423 | } |
db1b4961 | 424 | |
aeeb6a44 RR |
425 | if (gdk_selection_owner_get( GDK_SELECTION_PRIMARY ) == m_clipboardWidget->window) |
426 | { | |
e5ea3f7a RR |
427 | m_waiting = TRUE; |
428 | ||
aeeb6a44 | 429 | gtk_selection_owner_set( (GtkWidget*) NULL, GDK_SELECTION_PRIMARY, GDK_CURRENT_TIME ); |
e5ea3f7a RR |
430 | |
431 | while (m_waiting) gtk_main_iteration(); | |
aeeb6a44 RR |
432 | } |
433 | ||
0d2a2b60 RR |
434 | if (m_dataBroker) |
435 | { | |
436 | delete m_dataBroker; | |
437 | m_dataBroker = (wxDataBroker*) NULL; | |
438 | } | |
b453e1b2 RR |
439 | |
440 | #if wxUSE_THREADS | |
441 | /* re-enable GUI threads */ | |
442 | wxapp_install_thread_wakeup(); | |
443 | #endif | |
8b53e5a2 | 444 | } |
b527aac5 | 445 | |
8b53e5a2 | 446 | m_targetRequested = 0; |
b527aac5 | 447 | |
8b53e5a2 RR |
448 | m_formatSupported = FALSE; |
449 | } | |
450 | ||
451 | bool wxClipboard::Open() | |
452 | { | |
e90c1d2a | 453 | wxCHECK_MSG( !m_open, FALSE, T("clipboard already open") ); |
b527aac5 | 454 | |
8b53e5a2 | 455 | m_open = TRUE; |
cee6127e | 456 | |
8b53e5a2 | 457 | return TRUE; |
dc86cb34 RR |
458 | } |
459 | ||
75ce0581 | 460 | bool wxClipboard::SetData( wxDataObject *data ) |
dc86cb34 | 461 | { |
e90c1d2a | 462 | wxCHECK_MSG( m_open, FALSE, T("clipboard not open") ); |
75ce0581 | 463 | |
e90c1d2a | 464 | wxCHECK_MSG( data, FALSE, T("data is invalid") ); |
db1b4961 | 465 | |
0d2a2b60 | 466 | Clear(); |
75ce0581 RR |
467 | |
468 | return AddData( data ); | |
469 | } | |
470 | ||
471 | bool wxClipboard::AddData( wxDataObject *data ) | |
472 | { | |
e90c1d2a | 473 | wxCHECK_MSG( m_open, FALSE, T("clipboard not open") ); |
0d2a2b60 | 474 | |
e90c1d2a | 475 | wxCHECK_MSG( data, FALSE, T("data is invalid") ); |
2830bf19 | 476 | |
75ce0581 | 477 | /* if clipboard has been cleared before, create new data broker */ |
75ce0581 | 478 | if (!m_dataBroker) m_dataBroker = new wxDataBroker(); |
8b53e5a2 | 479 | |
75ce0581 | 480 | /* add new data to list of offered data objects */ |
75ce0581 RR |
481 | m_dataBroker->Add( data ); |
482 | ||
483 | /* get native format id of new data object */ | |
75ce0581 | 484 | GdkAtom format = data->GetFormat().GetAtom(); |
8b53e5a2 | 485 | |
e90c1d2a | 486 | wxCHECK_MSG( format, FALSE, T("data has invalid format") ); |
75ce0581 RR |
487 | |
488 | /* This should happen automatically, but to be on the safe side */ | |
75ce0581 RR |
489 | m_ownsClipboard = FALSE; |
490 | m_ownsPrimarySelection = FALSE; | |
aeeb6a44 | 491 | |
75ce0581 | 492 | /* Add handlers if someone requests data */ |
d345e841 RR |
493 | |
494 | #if (GTK_MINOR_VERSION > 0) | |
495 | ||
496 | gtk_selection_add_target( GTK_WIDGET(m_clipboardWidget), | |
497 | GDK_SELECTION_PRIMARY, | |
498 | format, | |
499 | 0 ); /* what is info ? */ | |
500 | ||
501 | gtk_selection_add_target( GTK_WIDGET(m_clipboardWidget), | |
502 | g_clipboardAtom, | |
503 | format, | |
504 | 0 ); /* what is info ? */ | |
505 | ||
506 | gtk_signal_connect( GTK_OBJECT(m_clipboardWidget), | |
507 | "selection_get", | |
508 | GTK_SIGNAL_FUNC(selection_handler), | |
509 | (gpointer) NULL ); | |
510 | ||
511 | #else | |
512 | ||
75ce0581 | 513 | gtk_selection_add_handler( m_clipboardWidget, |
8b53e5a2 | 514 | g_clipboardAtom, |
0d2a2b60 | 515 | format, |
8b53e5a2 | 516 | selection_handler, |
0d2a2b60 | 517 | (gpointer) NULL ); |
8b53e5a2 | 518 | |
75ce0581 | 519 | gtk_selection_add_handler( m_clipboardWidget, |
aeeb6a44 | 520 | GDK_SELECTION_PRIMARY, |
0d2a2b60 | 521 | format, |
aeeb6a44 | 522 | selection_handler, |
0d2a2b60 | 523 | (gpointer) NULL ); |
d345e841 | 524 | #endif |
db2d879a | 525 | |
b453e1b2 RR |
526 | #if wxUSE_THREADS |
527 | /* disable GUI threads */ | |
528 | wxapp_uninstall_thread_wakeup(); | |
529 | #endif | |
530 | ||
75ce0581 | 531 | /* Tell the world we offer clipboard data */ |
75ce0581 | 532 | if (!gtk_selection_owner_set( m_clipboardWidget, |
8b53e5a2 RR |
533 | g_clipboardAtom, |
534 | GDK_CURRENT_TIME )) | |
75ce0581 | 535 | { |
b453e1b2 RR |
536 | #if wxUSE_THREADS |
537 | /* re-enable GUI threads */ | |
538 | wxapp_install_thread_wakeup(); | |
539 | #endif | |
75ce0581 RR |
540 | return FALSE; |
541 | } | |
542 | m_ownsClipboard = TRUE; | |
aeeb6a44 | 543 | |
75ce0581 | 544 | if (!gtk_selection_owner_set( m_clipboardWidget, |
aeeb6a44 RR |
545 | GDK_SELECTION_PRIMARY, |
546 | GDK_CURRENT_TIME )) | |
75ce0581 | 547 | { |
b453e1b2 RR |
548 | #if wxUSE_THREADS |
549 | /* re-enable GUI threads */ | |
550 | wxapp_install_thread_wakeup(); | |
551 | #endif | |
75ce0581 | 552 | return FALSE; |
aeeb6a44 | 553 | } |
75ce0581 | 554 | m_ownsPrimarySelection = TRUE; |
b453e1b2 RR |
555 | |
556 | #if wxUSE_THREADS | |
557 | /* re-enable GUI threads */ | |
558 | wxapp_install_thread_wakeup(); | |
559 | #endif | |
75ce0581 | 560 | |
8b53e5a2 RR |
561 | return TRUE; |
562 | } | |
db1b4961 | 563 | |
8b53e5a2 RR |
564 | void wxClipboard::Close() |
565 | { | |
e90c1d2a | 566 | wxCHECK_RET( m_open, T("clipboard not open") ); |
8b53e5a2 RR |
567 | |
568 | m_open = FALSE; | |
dc86cb34 RR |
569 | } |
570 | ||
5f699c22 | 571 | bool wxClipboard::IsSupported( wxDataFormat format ) |
b527aac5 | 572 | { |
e90c1d2a | 573 | wxCHECK_MSG( m_open, FALSE, T("clipboard not open") ); |
0d2a2b60 | 574 | |
75ce0581 | 575 | /* store requested format to be asked for by callbacks */ |
0d2a2b60 | 576 | |
5f699c22 | 577 | m_targetRequested = format.GetAtom(); |
b527aac5 | 578 | |
e90c1d2a | 579 | wxCHECK_MSG( m_targetRequested, FALSE, T("invalid clipboard format") ); |
0d2a2b60 | 580 | |
8b53e5a2 | 581 | m_formatSupported = FALSE; |
b527aac5 | 582 | |
0d2a2b60 | 583 | /* perform query. this will set m_formatSupported to |
034be888 RR |
584 | TRUE if m_targetRequested is supported. |
585 | alsom we have to wait for the "answer" from the | |
586 | clipboard owner which is an asynchronous process. | |
587 | therefore we set m_waiting = TRUE here and wait | |
588 | until the callback "targets_selection_received" | |
589 | sets it to FALSE */ | |
590 | ||
591 | m_waiting = TRUE; | |
ca35e608 | 592 | |
034be888 | 593 | gtk_selection_convert( m_targetsWidget, |
cee6127e | 594 | m_usePrimary?GDK_SELECTION_PRIMARY:g_clipboardAtom, |
8b53e5a2 RR |
595 | g_targetsAtom, |
596 | GDK_CURRENT_TIME ); | |
ca35e608 | 597 | |
034be888 RR |
598 | while (m_waiting) gtk_main_iteration(); |
599 | ||
8b53e5a2 | 600 | if (!m_formatSupported) return FALSE; |
75ce0581 RR |
601 | |
602 | return TRUE; | |
603 | } | |
604 | ||
5f699c22 | 605 | bool wxClipboard::GetData( wxDataObject *data ) |
75ce0581 | 606 | { |
e90c1d2a | 607 | wxCHECK_MSG( m_open, FALSE, T("clipboard not open") ); |
75ce0581 RR |
608 | |
609 | /* is data supported by clipboard ? */ | |
610 | ||
5f699c22 | 611 | if (!IsSupported( data->GetFormat() )) return FALSE; |
75ce0581 RR |
612 | |
613 | /* store pointer to data object to be filled up by callbacks */ | |
614 | ||
5f699c22 | 615 | m_receivedData = data; |
75ce0581 RR |
616 | |
617 | /* store requested format to be asked for by callbacks */ | |
618 | ||
5f699c22 | 619 | m_targetRequested = data->GetFormat().GetAtom(); |
b527aac5 | 620 | |
e90c1d2a | 621 | wxCHECK_MSG( m_targetRequested, FALSE, T("invalid clipboard format") ); |
75ce0581 RR |
622 | |
623 | /* start query */ | |
8b53e5a2 | 624 | |
8b53e5a2 | 625 | m_formatSupported = FALSE; |
b527aac5 | 626 | |
034be888 RR |
627 | /* ask for clipboard contents. this will set |
628 | m_formatSupported to TRUE if m_targetRequested | |
629 | is supported. | |
630 | also, we have to wait for the "answer" from the | |
631 | clipboard owner which is an asynchronous process. | |
632 | therefore we set m_waiting = TRUE here and wait | |
633 | until the callback "targets_selection_received" | |
634 | sets it to FALSE */ | |
b527aac5 | 635 | |
034be888 | 636 | m_waiting = TRUE; |
75ce0581 | 637 | |
8b53e5a2 | 638 | gtk_selection_convert( m_clipboardWidget, |
cee6127e | 639 | m_usePrimary?GDK_SELECTION_PRIMARY:g_clipboardAtom, |
8b53e5a2 RR |
640 | m_targetRequested, |
641 | GDK_CURRENT_TIME ); | |
b527aac5 | 642 | |
034be888 | 643 | while (m_waiting) gtk_main_iteration(); |
b527aac5 | 644 | |
0d2a2b60 RR |
645 | /* this is a true error as we checked for the presence of such data before */ |
646 | ||
e90c1d2a | 647 | wxCHECK_MSG( m_formatSupported, FALSE, T("error retrieving data from clipboard") ); |
8b53e5a2 RR |
648 | |
649 | return TRUE; | |
b527aac5 RR |
650 | } |
651 | ||
b527aac5 RR |
652 | //----------------------------------------------------------------------------- |
653 | // wxClipboardModule | |
654 | //----------------------------------------------------------------------------- | |
655 | ||
656 | IMPLEMENT_DYNAMIC_CLASS(wxClipboardModule,wxModule) | |
657 | ||
658 | bool wxClipboardModule::OnInit() | |
659 | { | |
8b53e5a2 | 660 | wxTheClipboard = new wxClipboard(); |
b527aac5 | 661 | |
8b53e5a2 | 662 | return TRUE; |
b527aac5 RR |
663 | } |
664 | ||
665 | void wxClipboardModule::OnExit() | |
dc86cb34 | 666 | { |
8b53e5a2 RR |
667 | if (wxTheClipboard) delete wxTheClipboard; |
668 | wxTheClipboard = (wxClipboard*) NULL; | |
dc86cb34 | 669 | } |
ac57418f RR |
670 | |
671 | #endif | |
672 | ||
673 | // wxUSE_CLIPBOARD | |
674 |