]>
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 | } | |
8b53e5a2 | 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 | { | |
034be888 RR |
181 | if (selection_data->type != GDK_SELECTION_TYPE_BITMAP) |
182 | { | |
183 | clipboard->m_waiting = FALSE; | |
184 | return; | |
185 | } | |
8b53e5a2 RR |
186 | |
187 | break; | |
188 | } | |
189 | ||
190 | case wxDF_PRIVATE: | |
191 | { | |
034be888 RR |
192 | if (selection_data->type != GDK_SELECTION_TYPE_STRING) |
193 | { | |
194 | clipboard->m_waiting = FALSE; | |
195 | return; | |
196 | } | |
8b53e5a2 RR |
197 | |
198 | wxPrivateDataObject *private_object = (wxPrivateDataObject *) data_object; | |
199 | ||
200 | private_object->SetData( (const char*) selection_data->data, (size_t) selection_data->length ); | |
201 | ||
202 | break; | |
203 | } | |
204 | ||
205 | default: | |
206 | { | |
034be888 | 207 | clipboard->m_waiting = FALSE; |
8b53e5a2 RR |
208 | return; |
209 | } | |
210 | } | |
211 | ||
212 | wxTheClipboard->m_formatSupported = TRUE; | |
034be888 | 213 | clipboard->m_waiting = FALSE; |
dc86cb34 | 214 | } |
fd0eed64 RR |
215 | |
216 | //----------------------------------------------------------------------------- | |
217 | // "selection_clear" | |
218 | //----------------------------------------------------------------------------- | |
219 | ||
220 | static gint | |
aeeb6a44 | 221 | selection_clear_clip( GtkWidget *WXUNUSED(widget), GdkEventSelection *event ) |
fd0eed64 | 222 | { |
8b53e5a2 | 223 | if (!wxTheClipboard) return TRUE; |
2830bf19 | 224 | |
aeeb6a44 RR |
225 | if (event->selection == GDK_SELECTION_PRIMARY) |
226 | { | |
227 | wxTheClipboard->m_ownsPrimarySelection = FALSE; | |
228 | } | |
229 | else | |
230 | if (event->selection == g_clipboardAtom) | |
231 | { | |
232 | wxTheClipboard->m_ownsClipboard = FALSE; | |
233 | } | |
234 | else | |
235 | { | |
e5ea3f7a | 236 | wxTheClipboard->m_waiting = FALSE; |
aeeb6a44 RR |
237 | return FALSE; |
238 | } | |
239 | ||
240 | if ((!wxTheClipboard->m_ownsPrimarySelection) && | |
241 | (!wxTheClipboard->m_ownsClipboard)) | |
242 | { | |
db2d879a | 243 | /* the clipboard is no longer in our hands. we can the delete clipboard data. */ |
0d2a2b60 RR |
244 | if (wxTheClipboard->m_dataBroker) |
245 | { | |
246 | delete wxTheClipboard->m_dataBroker; | |
247 | wxTheClipboard->m_dataBroker = (wxDataBroker*) NULL; | |
248 | } | |
aeeb6a44 | 249 | } |
fd0eed64 | 250 | |
e5ea3f7a | 251 | wxTheClipboard->m_waiting = FALSE; |
8b53e5a2 | 252 | return TRUE; |
fd0eed64 RR |
253 | } |
254 | ||
255 | //----------------------------------------------------------------------------- | |
256 | // selection handler for supplying data | |
257 | //----------------------------------------------------------------------------- | |
258 | ||
259 | static void | |
260 | selection_handler( GtkWidget *WXUNUSED(widget), GtkSelectionData *selection_data, gpointer WXUNUSED(data) ) | |
261 | { | |
8b53e5a2 | 262 | if (!wxTheClipboard) return; |
fd0eed64 | 263 | |
0d2a2b60 RR |
264 | if (!wxTheClipboard->m_dataBroker) return; |
265 | ||
266 | wxNode *node = wxTheClipboard->m_dataBroker->m_dataObjects.First(); | |
8b53e5a2 RR |
267 | |
268 | while (node) | |
269 | { | |
270 | wxDataObject *data_object = (wxDataObject *)node->Data(); | |
271 | ||
0d2a2b60 | 272 | if (data_object->GetFormat().GetAtom() != selection_data->target) |
8b53e5a2 RR |
273 | { |
274 | node = node->Next(); | |
3874d10d | 275 | continue; |
8b53e5a2 RR |
276 | } |
277 | ||
0d2a2b60 | 278 | switch (data_object->GetFormat().GetType()) |
8b53e5a2 RR |
279 | { |
280 | case wxDF_TEXT: | |
281 | { | |
282 | wxTextDataObject *text_object = (wxTextDataObject*) data_object; | |
283 | ||
284 | wxString text = text_object->GetText(); | |
285 | ||
93c5dd39 OK |
286 | #if wxUSE_UNICODE |
287 | const wxWX2MBbuf s = text.mbc_str(); | |
288 | int len = strlen(s); | |
289 | #else // more efficient in non-Unicode | |
290 | const char *s = text.c_str(); | |
8b53e5a2 | 291 | int len = (int) text.Length(); |
93c5dd39 | 292 | #endif |
8b53e5a2 RR |
293 | |
294 | gtk_selection_data_set( | |
295 | selection_data, | |
296 | GDK_SELECTION_TYPE_STRING, | |
297 | 8*sizeof(gchar), | |
93c5dd39 | 298 | (unsigned char*) (const char*) s, |
8b53e5a2 RR |
299 | len ); |
300 | ||
301 | break; | |
302 | } | |
303 | ||
304 | case wxDF_BITMAP: | |
305 | { | |
306 | // wxBitmapDataObject *private_object = (wxBitmapDataObject*) data_object; | |
307 | ||
308 | // how do we do that ? | |
309 | ||
310 | break; | |
311 | } | |
312 | ||
313 | case wxDF_PRIVATE: | |
314 | { | |
315 | wxPrivateDataObject *private_object = (wxPrivateDataObject*) data_object; | |
316 | ||
0d2a2b60 | 317 | if (private_object->GetSize() == 0) return; |
8b53e5a2 RR |
318 | |
319 | gtk_selection_data_set( | |
320 | selection_data, | |
321 | GDK_SELECTION_TYPE_STRING, | |
322 | 8*sizeof(gchar), | |
323 | (unsigned char*) private_object->GetData(), | |
0d2a2b60 | 324 | (int) private_object->GetSize() ); |
8b53e5a2 RR |
325 | } |
326 | ||
327 | default: | |
328 | break; | |
329 | } | |
330 | ||
331 | node = node->Next(); | |
332 | } | |
fd0eed64 | 333 | } |
dc86cb34 RR |
334 | |
335 | //----------------------------------------------------------------------------- | |
336 | // wxClipboard | |
337 | //----------------------------------------------------------------------------- | |
338 | ||
339 | IMPLEMENT_DYNAMIC_CLASS(wxClipboard,wxObject) | |
340 | ||
341 | wxClipboard::wxClipboard() | |
342 | { | |
8b53e5a2 RR |
343 | m_open = FALSE; |
344 | ||
aeeb6a44 RR |
345 | m_ownsClipboard = FALSE; |
346 | m_ownsPrimarySelection = FALSE; | |
347 | ||
0d2a2b60 | 348 | m_dataBroker = (wxDataBroker*) NULL; |
fd0eed64 | 349 | |
8b53e5a2 | 350 | m_receivedData = (wxDataObject*) NULL; |
99c67c77 | 351 | |
034be888 RR |
352 | /* we use m_targetsWidget to query what formats are available */ |
353 | ||
354 | m_targetsWidget = gtk_window_new( GTK_WINDOW_POPUP ); | |
355 | gtk_widget_realize( m_targetsWidget ); | |
356 | ||
357 | gtk_signal_connect( GTK_OBJECT(m_targetsWidget), | |
358 | "selection_received", | |
359 | GTK_SIGNAL_FUNC( targets_selection_received ), | |
360 | (gpointer) this ); | |
361 | ||
362 | /* we use m_clipboardWidget to get and to offer data */ | |
363 | ||
8b53e5a2 RR |
364 | m_clipboardWidget = gtk_window_new( GTK_WINDOW_POPUP ); |
365 | gtk_widget_realize( m_clipboardWidget ); | |
366 | ||
034be888 RR |
367 | gtk_signal_connect( GTK_OBJECT(m_clipboardWidget), |
368 | "selection_received", | |
369 | GTK_SIGNAL_FUNC( selection_received ), | |
370 | (gpointer) this ); | |
371 | ||
8b53e5a2 RR |
372 | gtk_signal_connect( GTK_OBJECT(m_clipboardWidget), |
373 | "selection_clear_event", | |
aeeb6a44 | 374 | GTK_SIGNAL_FUNC( selection_clear_clip ), |
8b53e5a2 | 375 | (gpointer) NULL ); |
fd0eed64 | 376 | |
8b53e5a2 | 377 | if (!g_clipboardAtom) g_clipboardAtom = gdk_atom_intern( "CLIPBOARD", FALSE ); |
8b53e5a2 RR |
378 | if (!g_targetsAtom) g_targetsAtom = gdk_atom_intern ("TARGETS", FALSE); |
379 | ||
380 | m_formatSupported = FALSE; | |
381 | m_targetRequested = 0; | |
7e2c43b8 RR |
382 | |
383 | m_usePrimary = FALSE; | |
dc86cb34 RR |
384 | } |
385 | ||
386 | wxClipboard::~wxClipboard() | |
b527aac5 | 387 | { |
8b53e5a2 | 388 | Clear(); |
b527aac5 | 389 | |
8b53e5a2 | 390 | if (m_clipboardWidget) gtk_widget_destroy( m_clipboardWidget ); |
034be888 | 391 | if (m_targetsWidget) gtk_widget_destroy( m_targetsWidget ); |
b527aac5 RR |
392 | } |
393 | ||
394 | void wxClipboard::Clear() | |
dc86cb34 | 395 | { |
0d2a2b60 | 396 | if (m_dataBroker) |
8b53e5a2 | 397 | { |
b453e1b2 RR |
398 | #if wxUSE_THREADS |
399 | /* disable GUI threads */ | |
400 | wxapp_uninstall_thread_wakeup(); | |
401 | #endif | |
402 | ||
8b53e5a2 RR |
403 | /* As we have data we also own the clipboard. Once we no longer own |
404 | it, clear_selection is called which will set m_data to zero */ | |
aeeb6a44 | 405 | if (gdk_selection_owner_get( g_clipboardAtom ) == m_clipboardWidget->window) |
8b53e5a2 | 406 | { |
e5ea3f7a RR |
407 | m_waiting = TRUE; |
408 | ||
8b53e5a2 | 409 | gtk_selection_owner_set( (GtkWidget*) NULL, g_clipboardAtom, GDK_CURRENT_TIME ); |
e5ea3f7a RR |
410 | |
411 | while (m_waiting) gtk_main_iteration(); | |
8b53e5a2 | 412 | } |
db1b4961 | 413 | |
aeeb6a44 RR |
414 | if (gdk_selection_owner_get( GDK_SELECTION_PRIMARY ) == m_clipboardWidget->window) |
415 | { | |
e5ea3f7a RR |
416 | m_waiting = TRUE; |
417 | ||
aeeb6a44 | 418 | gtk_selection_owner_set( (GtkWidget*) NULL, GDK_SELECTION_PRIMARY, GDK_CURRENT_TIME ); |
e5ea3f7a RR |
419 | |
420 | while (m_waiting) gtk_main_iteration(); | |
aeeb6a44 RR |
421 | } |
422 | ||
0d2a2b60 RR |
423 | if (m_dataBroker) |
424 | { | |
425 | delete m_dataBroker; | |
426 | m_dataBroker = (wxDataBroker*) NULL; | |
427 | } | |
b453e1b2 RR |
428 | |
429 | #if wxUSE_THREADS | |
430 | /* re-enable GUI threads */ | |
431 | wxapp_install_thread_wakeup(); | |
432 | #endif | |
8b53e5a2 | 433 | } |
b527aac5 | 434 | |
8b53e5a2 | 435 | m_targetRequested = 0; |
b527aac5 | 436 | |
8b53e5a2 RR |
437 | m_formatSupported = FALSE; |
438 | } | |
439 | ||
440 | bool wxClipboard::Open() | |
441 | { | |
93c5dd39 | 442 | wxCHECK_MSG( !m_open, FALSE, _T("clipboard already open") ); |
b527aac5 | 443 | |
8b53e5a2 | 444 | m_open = TRUE; |
cee6127e | 445 | |
8b53e5a2 | 446 | return TRUE; |
dc86cb34 RR |
447 | } |
448 | ||
75ce0581 | 449 | bool wxClipboard::SetData( wxDataObject *data ) |
dc86cb34 | 450 | { |
93c5dd39 | 451 | wxCHECK_MSG( m_open, FALSE, _T("clipboard not open") ); |
75ce0581 | 452 | |
93c5dd39 | 453 | wxCHECK_MSG( data, FALSE, _T("data is invalid") ); |
db1b4961 | 454 | |
0d2a2b60 | 455 | Clear(); |
75ce0581 RR |
456 | |
457 | return AddData( data ); | |
458 | } | |
459 | ||
460 | bool wxClipboard::AddData( wxDataObject *data ) | |
461 | { | |
93c5dd39 | 462 | wxCHECK_MSG( m_open, FALSE, _T("clipboard not open") ); |
0d2a2b60 | 463 | |
93c5dd39 | 464 | wxCHECK_MSG( data, FALSE, _T("data is invalid") ); |
2830bf19 | 465 | |
75ce0581 | 466 | /* if clipboard has been cleared before, create new data broker */ |
75ce0581 | 467 | if (!m_dataBroker) m_dataBroker = new wxDataBroker(); |
8b53e5a2 | 468 | |
75ce0581 | 469 | /* add new data to list of offered data objects */ |
75ce0581 RR |
470 | m_dataBroker->Add( data ); |
471 | ||
472 | /* get native format id of new data object */ | |
75ce0581 | 473 | GdkAtom format = data->GetFormat().GetAtom(); |
8b53e5a2 | 474 | |
93c5dd39 | 475 | wxCHECK_MSG( format, FALSE, _T("data has invalid format") ); |
75ce0581 RR |
476 | |
477 | /* This should happen automatically, but to be on the safe side */ | |
75ce0581 RR |
478 | m_ownsClipboard = FALSE; |
479 | m_ownsPrimarySelection = FALSE; | |
aeeb6a44 | 480 | |
75ce0581 | 481 | /* Add handlers if someone requests data */ |
d345e841 RR |
482 | |
483 | #if (GTK_MINOR_VERSION > 0) | |
484 | ||
485 | gtk_selection_add_target( GTK_WIDGET(m_clipboardWidget), | |
486 | GDK_SELECTION_PRIMARY, | |
487 | format, | |
488 | 0 ); /* what is info ? */ | |
489 | ||
490 | gtk_selection_add_target( GTK_WIDGET(m_clipboardWidget), | |
491 | g_clipboardAtom, | |
492 | format, | |
493 | 0 ); /* what is info ? */ | |
494 | ||
495 | gtk_signal_connect( GTK_OBJECT(m_clipboardWidget), | |
496 | "selection_get", | |
497 | GTK_SIGNAL_FUNC(selection_handler), | |
498 | (gpointer) NULL ); | |
499 | ||
500 | #else | |
501 | ||
75ce0581 | 502 | gtk_selection_add_handler( m_clipboardWidget, |
8b53e5a2 | 503 | g_clipboardAtom, |
0d2a2b60 | 504 | format, |
8b53e5a2 | 505 | selection_handler, |
0d2a2b60 | 506 | (gpointer) NULL ); |
8b53e5a2 | 507 | |
75ce0581 | 508 | gtk_selection_add_handler( m_clipboardWidget, |
aeeb6a44 | 509 | GDK_SELECTION_PRIMARY, |
0d2a2b60 | 510 | format, |
aeeb6a44 | 511 | selection_handler, |
0d2a2b60 | 512 | (gpointer) NULL ); |
d345e841 | 513 | #endif |
db2d879a | 514 | |
b453e1b2 RR |
515 | #if wxUSE_THREADS |
516 | /* disable GUI threads */ | |
517 | wxapp_uninstall_thread_wakeup(); | |
518 | #endif | |
519 | ||
75ce0581 | 520 | /* Tell the world we offer clipboard data */ |
75ce0581 | 521 | if (!gtk_selection_owner_set( m_clipboardWidget, |
8b53e5a2 RR |
522 | g_clipboardAtom, |
523 | GDK_CURRENT_TIME )) | |
75ce0581 | 524 | { |
b453e1b2 RR |
525 | #if wxUSE_THREADS |
526 | /* re-enable GUI threads */ | |
527 | wxapp_install_thread_wakeup(); | |
528 | #endif | |
75ce0581 RR |
529 | return FALSE; |
530 | } | |
531 | m_ownsClipboard = TRUE; | |
aeeb6a44 | 532 | |
75ce0581 | 533 | if (!gtk_selection_owner_set( m_clipboardWidget, |
aeeb6a44 RR |
534 | GDK_SELECTION_PRIMARY, |
535 | GDK_CURRENT_TIME )) | |
75ce0581 | 536 | { |
b453e1b2 RR |
537 | #if wxUSE_THREADS |
538 | /* re-enable GUI threads */ | |
539 | wxapp_install_thread_wakeup(); | |
540 | #endif | |
75ce0581 | 541 | return FALSE; |
aeeb6a44 | 542 | } |
75ce0581 | 543 | m_ownsPrimarySelection = TRUE; |
b453e1b2 RR |
544 | |
545 | #if wxUSE_THREADS | |
546 | /* re-enable GUI threads */ | |
547 | wxapp_install_thread_wakeup(); | |
548 | #endif | |
75ce0581 | 549 | |
8b53e5a2 RR |
550 | return TRUE; |
551 | } | |
db1b4961 | 552 | |
8b53e5a2 RR |
553 | void wxClipboard::Close() |
554 | { | |
93c5dd39 | 555 | wxCHECK_RET( m_open, _T("clipboard not open") ); |
8b53e5a2 RR |
556 | |
557 | m_open = FALSE; | |
dc86cb34 RR |
558 | } |
559 | ||
5f699c22 | 560 | bool wxClipboard::IsSupported( wxDataFormat format ) |
b527aac5 | 561 | { |
93c5dd39 | 562 | wxCHECK_MSG( m_open, FALSE, _T("clipboard not open") ); |
0d2a2b60 | 563 | |
75ce0581 | 564 | /* store requested format to be asked for by callbacks */ |
0d2a2b60 | 565 | |
5f699c22 | 566 | m_targetRequested = format.GetAtom(); |
b527aac5 | 567 | |
93c5dd39 | 568 | wxCHECK_MSG( m_targetRequested, FALSE, _T("invalid clipboard format") ); |
0d2a2b60 | 569 | |
8b53e5a2 | 570 | m_formatSupported = FALSE; |
b527aac5 | 571 | |
0d2a2b60 | 572 | /* perform query. this will set m_formatSupported to |
034be888 RR |
573 | TRUE if m_targetRequested is supported. |
574 | alsom we have to wait for the "answer" from the | |
575 | clipboard owner which is an asynchronous process. | |
576 | therefore we set m_waiting = TRUE here and wait | |
577 | until the callback "targets_selection_received" | |
578 | sets it to FALSE */ | |
579 | ||
580 | m_waiting = TRUE; | |
ca35e608 | 581 | |
034be888 | 582 | gtk_selection_convert( m_targetsWidget, |
cee6127e | 583 | m_usePrimary?GDK_SELECTION_PRIMARY:g_clipboardAtom, |
8b53e5a2 RR |
584 | g_targetsAtom, |
585 | GDK_CURRENT_TIME ); | |
ca35e608 | 586 | |
034be888 RR |
587 | while (m_waiting) gtk_main_iteration(); |
588 | ||
8b53e5a2 | 589 | if (!m_formatSupported) return FALSE; |
75ce0581 RR |
590 | |
591 | return TRUE; | |
592 | } | |
593 | ||
5f699c22 | 594 | bool wxClipboard::GetData( wxDataObject *data ) |
75ce0581 | 595 | { |
93c5dd39 | 596 | wxCHECK_MSG( m_open, FALSE, _T("clipboard not open") ); |
75ce0581 RR |
597 | |
598 | /* is data supported by clipboard ? */ | |
599 | ||
5f699c22 | 600 | if (!IsSupported( data->GetFormat() )) return FALSE; |
75ce0581 RR |
601 | |
602 | /* store pointer to data object to be filled up by callbacks */ | |
603 | ||
5f699c22 | 604 | m_receivedData = data; |
75ce0581 RR |
605 | |
606 | /* store requested format to be asked for by callbacks */ | |
607 | ||
5f699c22 | 608 | m_targetRequested = data->GetFormat().GetAtom(); |
b527aac5 | 609 | |
93c5dd39 | 610 | wxCHECK_MSG( m_targetRequested, FALSE, _T("invalid clipboard format") ); |
75ce0581 RR |
611 | |
612 | /* start query */ | |
8b53e5a2 | 613 | |
8b53e5a2 | 614 | m_formatSupported = FALSE; |
b527aac5 | 615 | |
034be888 RR |
616 | /* ask for clipboard contents. this will set |
617 | m_formatSupported to TRUE if m_targetRequested | |
618 | is supported. | |
619 | also, we have to wait for the "answer" from the | |
620 | clipboard owner which is an asynchronous process. | |
621 | therefore we set m_waiting = TRUE here and wait | |
622 | until the callback "targets_selection_received" | |
623 | sets it to FALSE */ | |
b527aac5 | 624 | |
034be888 | 625 | m_waiting = TRUE; |
75ce0581 | 626 | |
8b53e5a2 | 627 | gtk_selection_convert( m_clipboardWidget, |
cee6127e | 628 | m_usePrimary?GDK_SELECTION_PRIMARY:g_clipboardAtom, |
8b53e5a2 RR |
629 | m_targetRequested, |
630 | GDK_CURRENT_TIME ); | |
b527aac5 | 631 | |
034be888 | 632 | while (m_waiting) gtk_main_iteration(); |
b527aac5 | 633 | |
0d2a2b60 RR |
634 | /* this is a true error as we checked for the presence of such data before */ |
635 | ||
93c5dd39 | 636 | wxCHECK_MSG( m_formatSupported, FALSE, _T("error retrieving data from clipboard") ); |
8b53e5a2 RR |
637 | |
638 | return TRUE; | |
b527aac5 RR |
639 | } |
640 | ||
b527aac5 RR |
641 | //----------------------------------------------------------------------------- |
642 | // wxClipboardModule | |
643 | //----------------------------------------------------------------------------- | |
644 | ||
645 | IMPLEMENT_DYNAMIC_CLASS(wxClipboardModule,wxModule) | |
646 | ||
647 | bool wxClipboardModule::OnInit() | |
648 | { | |
8b53e5a2 | 649 | wxTheClipboard = new wxClipboard(); |
b527aac5 | 650 | |
8b53e5a2 | 651 | return TRUE; |
b527aac5 RR |
652 | } |
653 | ||
654 | void wxClipboardModule::OnExit() | |
dc86cb34 | 655 | { |
8b53e5a2 RR |
656 | if (wxTheClipboard) delete wxTheClipboard; |
657 | wxTheClipboard = (wxClipboard*) NULL; | |
dc86cb34 | 658 | } |
ac57418f RR |
659 | |
660 | #endif | |
661 | ||
662 | // wxUSE_CLIPBOARD | |
663 |