]> git.saurik.com Git - wxWidgets.git/blame - src/msw/clipbrd.cpp
Fix duplicate wxContextMenuEvent generation in wxMSW.
[wxWidgets.git] / src / msw / clipbrd.cpp
CommitLineData
2bda0e17 1/////////////////////////////////////////////////////////////////////////////
e4db172a 2// Name: src/msw/clipbrd.cpp
2bda0e17
KB
3// Purpose: Clipboard functionality
4// Author: Julian Smart
5// Modified by:
6// Created: 04/01/98
7// RCS-ID: $Id$
6c9a19aa 8// Copyright: (c) Julian Smart
65571936 9// Licence: wxWindows licence
2bda0e17
KB
10/////////////////////////////////////////////////////////////////////////////
11
26f86486
VZ
12// ===========================================================================
13// declarations
14// ===========================================================================
15
16// ---------------------------------------------------------------------------
17// headers
18// ---------------------------------------------------------------------------
19
2bda0e17
KB
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
26f86486 24 #pragma hdrstop
2bda0e17
KB
25#endif
26
47d67540 27#if wxUSE_CLIPBOARD
2bda0e17 28
e4db172a
WS
29#include "wx/clipbrd.h"
30
2bda0e17 31#ifndef WX_PRECOMP
26f86486
VZ
32 #include "wx/object.h"
33 #include "wx/event.h"
34 #include "wx/app.h"
35 #include "wx/frame.h"
36 #include "wx/bitmap.h"
37 #include "wx/utils.h"
0c589ad0 38 #include "wx/intl.h"
e4db172a 39 #include "wx/log.h"
28f92d74 40 #include "wx/dataobj.h"
2bda0e17
KB
41#endif
42
06e43511 43#if wxUSE_METAFILE
26f86486 44 #include "wx/metafile.h"
06e43511
JS
45#endif
46
06e43511 47
3f480da3 48#include <string.h>
06e43511 49
2bda0e17 50#include "wx/msw/private.h"
794fe8cd 51#include "wx/msw/ole/oleutils.h"
8cb172b4 52
4676948b 53#if wxUSE_WXDIB
794fe8cd 54 #include "wx/msw/dib.h"
8cb172b4 55#endif
2bda0e17 56
d59ceba5
VZ
57// wxDataObject is tied to OLE/drag and drop implementation, therefore so are
58// the functions using wxDataObject in wxClipboard
1e6feb95 59//#define wxUSE_DATAOBJ wxUSE_DRAG_AND_DROP
d59ceba5 60
f07dc2e2 61#if wxUSE_OLE && !defined(__WXWINCE__)
b94e73ae
VZ
62 // use OLE clipboard
63 #define wxUSE_OLE_CLIPBOARD 1
d59ceba5
VZ
64#else // !wxUSE_DATAOBJ
65 // use Win clipboard API
66 #define wxUSE_OLE_CLIPBOARD 0
2bda0e17
KB
67#endif
68
d59ceba5
VZ
69#if wxUSE_OLE_CLIPBOARD
70 #include <ole2.h>
71#endif // wxUSE_OLE_CLIPBOARD
72
26f86486
VZ
73// ===========================================================================
74// implementation
75// ===========================================================================
76
77// ---------------------------------------------------------------------------
78// old-style clipboard functions using Windows API
79// ---------------------------------------------------------------------------
2bda0e17 80
02b7b6b0 81static bool gs_wxClipboardIsOpen = false;
b8acf11e 82static int gs_htmlcfid = 0;
26f86486
VZ
83
84bool wxOpenClipboard()
2bda0e17 85{
02b7b6b0 86 wxCHECK_MSG( !gs_wxClipboardIsOpen, true, wxT("clipboard already opened.") );
26f86486
VZ
87
88 wxWindow *win = wxTheApp->GetTopWindow();
89 if ( win )
90 {
91 gs_wxClipboardIsOpen = ::OpenClipboard((HWND)win->GetHWND()) != 0;
92
93 if ( !gs_wxClipboardIsOpen )
43b2d5e7 94 {
26f86486 95 wxLogSysError(_("Failed to open the clipboard."));
43b2d5e7 96 }
26f86486
VZ
97
98 return gs_wxClipboardIsOpen;
99 }
100 else
101 {
4c51a665 102 wxLogDebug(wxT("Cannot open clipboard without a main window."));
26f86486 103
02b7b6b0 104 return false;
26f86486 105 }
2bda0e17
KB
106}
107
26f86486 108bool wxCloseClipboard()
2bda0e17 109{
02b7b6b0 110 wxCHECK_MSG( gs_wxClipboardIsOpen, false, wxT("clipboard is not opened") );
26f86486 111
02b7b6b0 112 gs_wxClipboardIsOpen = false;
26f86486
VZ
113
114 if ( ::CloseClipboard() == 0 )
115 {
116 wxLogSysError(_("Failed to close the clipboard."));
117
02b7b6b0 118 return false;
26f86486
VZ
119 }
120
02b7b6b0 121 return true;
2bda0e17
KB
122}
123
26f86486 124bool wxEmptyClipboard()
2bda0e17 125{
26f86486
VZ
126 if ( ::EmptyClipboard() == 0 )
127 {
128 wxLogSysError(_("Failed to empty the clipboard."));
129
02b7b6b0 130 return false;
26f86486
VZ
131 }
132
02b7b6b0 133 return true;
2bda0e17
KB
134}
135
26f86486 136bool wxIsClipboardOpened()
2bda0e17 137{
26f86486 138 return gs_wxClipboardIsOpen;
2bda0e17
KB
139}
140
06e43511 141bool wxIsClipboardFormatAvailable(wxDataFormat dataFormat)
2bda0e17 142{
b8acf11e
RD
143 wxDataFormat::NativeFormat cf = dataFormat.GetFormatId();
144 if (cf == wxDF_HTML)
145 cf = gs_htmlcfid;
6c29712c
JS
146
147 if ( ::IsClipboardFormatAvailable(cf) )
d9317fd4
VZ
148 {
149 // ok from the first try
02b7b6b0 150 return true;
d9317fd4
VZ
151 }
152
153 // for several standard formats, we can convert from some other ones too
6c29712c 154 switch ( cf )
d9317fd4
VZ
155 {
156 // for bitmaps, DIBs will also do
157 case CF_BITMAP:
158 return ::IsClipboardFormatAvailable(CF_DIB) != 0;
159
3a5bcc4d 160#if wxUSE_ENH_METAFILE && !defined(__WXWINCE__)
d9317fd4
VZ
161 case CF_METAFILEPICT:
162 return ::IsClipboardFormatAvailable(CF_ENHMETAFILE) != 0;
163#endif // wxUSE_ENH_METAFILE
164
165 default:
02b7b6b0 166 return false;
d9317fd4 167 }
2bda0e17
KB
168}
169
e9196d9c 170
26f86486
VZ
171bool wxSetClipboardData(wxDataFormat dataFormat,
172 const void *data,
173 int width, int height)
2bda0e17 174{
26f86486
VZ
175 HANDLE handle = 0; // return value of SetClipboardData
176
177 switch (dataFormat)
2bda0e17 178 {
26f86486
VZ
179 case wxDF_BITMAP:
180 {
181 wxBitmap *bitmap = (wxBitmap *)data;
182
183 HDC hdcMem = CreateCompatibleDC((HDC) NULL);
184 HDC hdcSrc = CreateCompatibleDC((HDC) NULL);
185 HBITMAP old = (HBITMAP)
186 ::SelectObject(hdcSrc, (HBITMAP)bitmap->GetHBITMAP());
187 HBITMAP hBitmap = CreateCompatibleBitmap(hdcSrc,
188 bitmap->GetWidth(),
189 bitmap->GetHeight());
190 if (!hBitmap)
191 {
192 SelectObject(hdcSrc, old);
193 DeleteDC(hdcMem);
194 DeleteDC(hdcSrc);
02b7b6b0 195 return false;
26f86486
VZ
196 }
197
198 HBITMAP old1 = (HBITMAP) SelectObject(hdcMem, hBitmap);
199 BitBlt(hdcMem, 0, 0, bitmap->GetWidth(), bitmap->GetHeight(),
200 hdcSrc, 0, 0, SRCCOPY);
201
202 // Select new bitmap out of memory DC
203 SelectObject(hdcMem, old1);
204
205 // Set the data
206 handle = ::SetClipboardData(CF_BITMAP, hBitmap);
207
208 // Clean up
209 SelectObject(hdcSrc, old);
210 DeleteDC(hdcSrc);
211 DeleteDC(hdcMem);
212 break;
213 }
214
4676948b 215#if wxUSE_WXDIB
26f86486
VZ
216 case wxDF_DIB:
217 {
26f86486 218 wxBitmap *bitmap = (wxBitmap *)data;
2b254edf 219
a1b806b9 220 if ( bitmap && bitmap->IsOk() )
2b254edf 221 {
c2517b52
VZ
222 wxDIB dib(*bitmap);
223 if ( dib.IsOk() )
224 {
225 handle = ::SetClipboardData(CF_DIB, dib.Detach());
226 }
2b254edf 227 }
26f86486
VZ
228 break;
229 }
4676948b 230#endif
26f86486 231
d9317fd4 232 // VZ: I'm told that this code works, but it doesn't seem to work for me
4676948b 233 // and, anyhow, I'd be highly surprised if it did. So I leave it here
d9317fd4 234 // but IMNSHO it is completely broken.
4676948b 235#if wxUSE_METAFILE && !defined(wxMETAFILE_IS_ENH) && !defined(__WXWINCE__)
26f86486
VZ
236 case wxDF_METAFILE:
237 {
238 wxMetafile *wxMF = (wxMetafile *)data;
239 HANDLE data = GlobalAlloc(GHND, sizeof(METAFILEPICT) + 1);
26f86486 240 METAFILEPICT *mf = (METAFILEPICT *)GlobalLock(data);
2bda0e17 241
26f86486
VZ
242 mf->mm = wxMF->GetWindowsMappingMode();
243 mf->xExt = width;
244 mf->yExt = height;
245 mf->hMF = (HMETAFILE) wxMF->GetHMETAFILE();
246 GlobalUnlock(data);
247 wxMF->SetHMETAFILE((WXHANDLE) NULL);
2bda0e17 248
26f86486
VZ
249 handle = SetClipboardData(CF_METAFILEPICT, data);
250 break;
251 }
d9317fd4
VZ
252#endif // wxUSE_METAFILE
253
3a5bcc4d 254#if wxUSE_ENH_METAFILE && !defined(__WXWINCE__)
d9317fd4
VZ
255 case wxDF_ENHMETAFILE:
256 {
257 wxEnhMetaFile *emf = (wxEnhMetaFile *)data;
258 wxEnhMetaFile emfCopy = *emf;
259
260 handle = SetClipboardData(CF_ENHMETAFILE,
261 (void *)emfCopy.GetHENHMETAFILE());
262 }
263 break;
264#endif // wxUSE_ENH_METAFILE
265
26f86486
VZ
266 case CF_SYLK:
267 case CF_DIF:
268 case CF_TIFF:
269 case CF_PALETTE:
270 default:
271 {
272 wxLogError(_("Unsupported clipboard format."));
02b7b6b0 273 return false;
26f86486 274 }
2bda0e17 275
26f86486
VZ
276 case wxDF_OEMTEXT:
277 dataFormat = wxDF_TEXT;
278 // fall through
2bda0e17 279
26f86486
VZ
280 case wxDF_TEXT:
281 {
282 char *s = (char *)data;
283
284 width = strlen(s) + 1;
285 height = 1;
286 DWORD l = (width * height);
287 HANDLE hGlobalMemory = GlobalAlloc(GHND, l);
288 if ( hGlobalMemory )
289 {
26f86486 290 LPSTR lpGlobalMemory = (LPSTR)GlobalLock(hGlobalMemory);
2bda0e17 291
26f86486 292 memcpy(lpGlobalMemory, s, l);
2bda0e17 293
26f86486
VZ
294 GlobalUnlock(hGlobalMemory);
295 }
2bda0e17 296
26f86486
VZ
297 handle = SetClipboardData(dataFormat, hGlobalMemory);
298 break;
299 }
6270539b
JS
300 // Only tested with Visual C++ 6.0 so far
301#if defined(__VISUALC__)
387ebd3e
JS
302 case wxDF_HTML:
303 {
304 char* html = (char *)data;
02b7b6b0 305
387ebd3e
JS
306 // Create temporary buffer for HTML header...
307 char *buf = new char [400 + strlen(html)];
02b7b6b0
WS
308 if(!buf) return false;
309
387ebd3e
JS
310 // Create a template string for the HTML header...
311 strcpy(buf,
312 "Version:0.9\r\n"
313 "StartHTML:00000000\r\n"
314 "EndHTML:00000000\r\n"
315 "StartFragment:00000000\r\n"
316 "EndFragment:00000000\r\n"
317 "<html><body>\r\n"
318 "<!--StartFragment -->\r\n");
02b7b6b0 319
387ebd3e
JS
320 // Append the HTML...
321 strcat(buf, html);
322 strcat(buf, "\r\n");
323 // Finish up the HTML format...
324 strcat(buf,
325 "<!--EndFragment-->\r\n"
326 "</body>\r\n"
327 "</html>");
02b7b6b0 328
387ebd3e
JS
329 // Now go back, calculate all the lengths, and write out the
330 // necessary header information. Note, wsprintf() truncates the
331 // string when you overwrite it so you follow up with code to replace
332 // the 0 appended at the end with a '\r'...
333 char *ptr = strstr(buf, "StartHTML");
fbf9fe29 334 sprintf(ptr+10, "%08u", (unsigned)(strstr(buf, "<html>") - buf));
387ebd3e 335 *(ptr+10+8) = '\r';
02b7b6b0 336
387ebd3e 337 ptr = strstr(buf, "EndHTML");
fbf9fe29 338 sprintf(ptr+8, "%08u", (unsigned)strlen(buf));
387ebd3e 339 *(ptr+8+8) = '\r';
02b7b6b0 340
387ebd3e 341 ptr = strstr(buf, "StartFragment");
fbf9fe29 342 sprintf(ptr+14, "%08u", (unsigned)(strstr(buf, "<!--StartFrag") - buf));
387ebd3e 343 *(ptr+14+8) = '\r';
02b7b6b0 344
387ebd3e 345 ptr = strstr(buf, "EndFragment");
fbf9fe29 346 sprintf(ptr+12, "%08u", (unsigned)(strstr(buf, "<!--EndFrag") - buf));
387ebd3e 347 *(ptr+12+8) = '\r';
02b7b6b0 348
387ebd3e
JS
349 // Now you have everything in place ready to put on the
350 // clipboard.
02b7b6b0 351
387ebd3e
JS
352 // Allocate global memory for transfer...
353 HGLOBAL hText = GlobalAlloc(GMEM_MOVEABLE |GMEM_DDESHARE, strlen(buf)+4);
02b7b6b0 354
387ebd3e
JS
355 // Put your string in the global memory...
356 ptr = (char *)GlobalLock(hText);
357 strcpy(ptr, buf);
358 GlobalUnlock(hText);
02b7b6b0 359
b8acf11e 360 handle = ::SetClipboardData(gs_htmlcfid, hText);
02b7b6b0 361
387ebd3e
JS
362 // Free memory...
363 GlobalFree(hText);
02b7b6b0 364
387ebd3e
JS
365 // Clean up...
366 delete [] buf;
367 break;
368 }
369#endif
2bda0e17 370 }
26f86486
VZ
371
372 if ( handle == 0 )
2bda0e17 373 {
26f86486
VZ
374 wxLogSysError(_("Failed to set clipboard data."));
375
02b7b6b0 376 return false;
2bda0e17 377 }
26f86486 378
02b7b6b0 379 return true;
26f86486
VZ
380}
381
382void *wxGetClipboardData(wxDataFormat dataFormat, long *len)
383{
384 void *retval = NULL;
385
386 switch ( dataFormat )
2bda0e17 387 {
4676948b 388#ifndef __WXWINCE__
26f86486
VZ
389 case wxDF_BITMAP:
390 {
391 BITMAP bm;
392 HBITMAP hBitmap = (HBITMAP) GetClipboardData(CF_BITMAP);
393 if (!hBitmap)
394 break;
395
396 HDC hdcMem = CreateCompatibleDC((HDC) NULL);
397 HDC hdcSrc = CreateCompatibleDC((HDC) NULL);
398
399 HBITMAP old = (HBITMAP) ::SelectObject(hdcSrc, hBitmap);
400 GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&bm);
401
402 HBITMAP hNewBitmap = CreateBitmapIndirect(&bm);
403
404 if (!hNewBitmap)
405 {
406 SelectObject(hdcSrc, old);
407 DeleteDC(hdcMem);
408 DeleteDC(hdcSrc);
409 break;
410 }
411
412 HBITMAP old1 = (HBITMAP) SelectObject(hdcMem, hNewBitmap);
413 BitBlt(hdcMem, 0, 0, bm.bmWidth, bm.bmHeight,
414 hdcSrc, 0, 0, SRCCOPY);
415
416 // Select new bitmap out of memory DC
417 SelectObject(hdcMem, old1);
418
419 // Clean up
420 SelectObject(hdcSrc, old);
421 DeleteDC(hdcSrc);
422 DeleteDC(hdcMem);
423
424 // Create and return a new wxBitmap
425 wxBitmap *wxBM = new wxBitmap;
426 wxBM->SetHBITMAP((WXHBITMAP) hNewBitmap);
427 wxBM->SetWidth(bm.bmWidth);
428 wxBM->SetHeight(bm.bmHeight);
429 wxBM->SetDepth(bm.bmPlanes);
26f86486
VZ
430 retval = wxBM;
431 break;
432 }
4676948b 433#endif
26f86486
VZ
434 case wxDF_METAFILE:
435 case CF_SYLK:
436 case CF_DIF:
437 case CF_TIFF:
438 case CF_PALETTE:
439 case wxDF_DIB:
f7f50f49
VZ
440 wxLogError(_("Unsupported clipboard format."));
441 return NULL;
26f86486
VZ
442
443 case wxDF_OEMTEXT:
444 dataFormat = wxDF_TEXT;
445 // fall through
446
447 case wxDF_TEXT:
448 {
449 HANDLE hGlobalMemory = ::GetClipboardData(dataFormat);
450 if (!hGlobalMemory)
451 break;
2bda0e17 452
26f86486
VZ
453 DWORD hsize = ::GlobalSize(hGlobalMemory);
454 if (len)
455 *len = hsize;
2bda0e17 456
26f86486
VZ
457 char *s = new char[hsize];
458 if (!s)
459 break;
2bda0e17 460
4676948b 461 LPSTR lpGlobalMemory = (LPSTR) GlobalLock(hGlobalMemory);
2bda0e17 462
26f86486 463 memcpy(s, lpGlobalMemory, hsize);
2bda0e17 464
4676948b 465 GlobalUnlock(hGlobalMemory);
26f86486
VZ
466
467 retval = s;
468 break;
469 }
3f480da3
VZ
470
471 default:
472 {
473 HANDLE hGlobalMemory = ::GetClipboardData(dataFormat);
474 if ( !hGlobalMemory )
475 break;
476
477 DWORD size = ::GlobalSize(hGlobalMemory);
478 if ( len )
479 *len = size;
480
481 void *buf = malloc(size);
482 if ( !buf )
483 break;
484
4676948b 485 LPSTR lpGlobalMemory = (LPSTR) GlobalLock(hGlobalMemory);
3f480da3
VZ
486
487 memcpy(buf, lpGlobalMemory, size);
488
4676948b 489 GlobalUnlock(hGlobalMemory);
3f480da3
VZ
490
491 retval = buf;
492 break;
493 }
26f86486 494 }
2bda0e17 495
26f86486
VZ
496 if ( !retval )
497 {
498 wxLogSysError(_("Failed to retrieve data from the clipboard."));
2bda0e17 499 }
26f86486
VZ
500
501 return retval;
2bda0e17
KB
502}
503
3f480da3 504wxDataFormat wxEnumClipboardFormats(wxDataFormat dataFormat)
2bda0e17 505{
33ac7e6f 506 return (wxDataFormat::NativeFormat)::EnumClipboardFormats(dataFormat);
2bda0e17
KB
507}
508
837e5743 509int wxRegisterClipboardFormat(wxChar *formatName)
2bda0e17
KB
510{
511 return ::RegisterClipboardFormat(formatName);
512}
513
26f86486 514bool wxGetClipboardFormatName(wxDataFormat dataFormat,
837e5743 515 wxChar *formatName,
26f86486 516 int maxCount)
2bda0e17 517{
26f86486 518 return ::GetClipboardFormatName((int)dataFormat, formatName, maxCount) > 0;
2bda0e17
KB
519}
520
26f86486 521// ---------------------------------------------------------------------------
06e43511 522// wxClipboard
26f86486 523// ---------------------------------------------------------------------------
2bda0e17 524
26f86486 525IMPLEMENT_DYNAMIC_CLASS(wxClipboard, wxObject)
2bda0e17
KB
526
527wxClipboard::wxClipboard()
528{
794fe8cd
VZ
529#if wxUSE_OLE_CLIPBOARD
530 wxOleInitialize();
531#endif
532
c039fef5 533 m_lastDataObject = NULL;
02b7b6b0 534 m_isOpened = false;
2bda0e17
KB
535}
536
537wxClipboard::~wxClipboard()
538{
c039fef5 539 if ( m_lastDataObject )
d59ceba5 540 {
0edfdd96 541 Clear();
d59ceba5 542 }
794fe8cd
VZ
543
544#if wxUSE_OLE_CLIPBOARD
545 wxOleUninitialize();
546#endif
2bda0e17
KB
547}
548
06e43511 549void wxClipboard::Clear()
2bda0e17 550{
9005f2ed
VZ
551 if ( IsUsingPrimarySelection() )
552 return;
553
d59ceba5 554#if wxUSE_OLE_CLIPBOARD
c039fef5
VZ
555 if (m_lastDataObject)
556 {
557 // don't touch data set by other applications
558 HRESULT hr = OleIsCurrentClipboard(m_lastDataObject);
559 if (S_OK == hr)
560 {
561 hr = OleSetClipboard(NULL);
164e8d41
PC
562 if ( FAILED(hr) )
563 {
564 wxLogApiError(wxT("OleSetClipboard(NULL)"), hr);
565 }
c039fef5
VZ
566 }
567 m_lastDataObject = NULL;
568 }
110a0fea 569#endif // wxUSE_OLE_CLIPBOARD
d59ceba5
VZ
570}
571
572bool wxClipboard::Flush()
573{
7ffdaf81 574#if wxUSE_OLE_CLIPBOARD
c039fef5
VZ
575 if (m_lastDataObject)
576 {
577 // don't touch data set by other applications
578 HRESULT hr = OleIsCurrentClipboard(m_lastDataObject);
579 m_lastDataObject = NULL;
580 if (S_OK == hr)
581 {
582 hr = OleFlushClipboard();
164e8d41
PC
583 if ( FAILED(hr) )
584 {
585 wxLogApiError(wxT("OleFlushClipboard"), hr);
d59ceba5 586
164e8d41
PC
587 return false;
588 }
589 return true;
590 }
c039fef5
VZ
591 }
592 return false;
7ffdaf81 593#else // !wxUSE_OLE_CLIPBOARD
02b7b6b0 594 return false;
7ffdaf81 595#endif // wxUSE_OLE_CLIPBOARD/!wxUSE_OLE_CLIPBOARD
2bda0e17
KB
596}
597
06e43511 598bool wxClipboard::Open()
2bda0e17 599{
b8acf11e
RD
600 // Get clipboard id for HTML format...
601 if(!gs_htmlcfid)
602 gs_htmlcfid = RegisterClipboardFormat(wxT("HTML Format"));
603
d59ceba5 604 // OLE opens clipboard for us
02b7b6b0 605 m_isOpened = true;
d59ceba5 606#if wxUSE_OLE_CLIPBOARD
02b7b6b0 607 return true;
d59ceba5 608#else
06e43511 609 return wxOpenClipboard();
d59ceba5 610#endif
2bda0e17
KB
611}
612
f536e0f2
VZ
613bool wxClipboard::IsOpened() const
614{
615#if wxUSE_OLE_CLIPBOARD
a36d790a 616 return m_isOpened;
f536e0f2
VZ
617#else
618 return wxIsClipboardOpened();
619#endif
620}
621
06e43511 622bool wxClipboard::SetData( wxDataObject *data )
2bda0e17 623{
9005f2ed
VZ
624 if ( IsUsingPrimarySelection() )
625 return false;
626
51edda6a 627#if !wxUSE_OLE_CLIPBOARD
26f86486 628 (void)wxEmptyClipboard();
51edda6a 629#endif // wxUSE_OLE_CLIPBOARD
26f86486
VZ
630
631 if ( data )
632 return AddData(data);
633 else
02b7b6b0 634 return true;
26f86486
VZ
635}
636
637bool wxClipboard::AddData( wxDataObject *data )
638{
9005f2ed
VZ
639 if ( IsUsingPrimarySelection() )
640 return false;
641
02b7b6b0 642 wxCHECK_MSG( data, false, wxT("data is invalid") );
06e43511 643
d59ceba5
VZ
644#if wxUSE_OLE_CLIPBOARD
645 HRESULT hr = OleSetClipboard(data->GetInterface());
646 if ( FAILED(hr) )
647 {
648 wxLogSysError(hr, _("Failed to put data on the clipboard"));
649
650 // don't free anything in this case
651
02b7b6b0 652 return false;
d59ceba5
VZ
653 }
654
c039fef5
VZ
655 // we have to call either OleSetClipboard(NULL) or OleFlushClipboard() when
656 // using OLE clipboard when the app terminates - by default, we call
657 // OleSetClipboard(NULL) which won't waste RAM, but the app can call
658 // wxClipboard::Flush() to change this
659 m_lastDataObject = data->GetInterface();
660
d59ceba5
VZ
661 // we have a problem here because we should delete wxDataObject, but we
662 // can't do it because IDataObject which we just gave to the clipboard
663 // would try to use it when it will need the data. IDataObject is ref
664 // counted and so doesn't suffer from such problem, so we release it now
665 // and tell it to delete wxDataObject when it is deleted itself.
666 data->SetAutoDelete();
667
02b7b6b0 668 return true;
d59ceba5 669#elif wxUSE_DATAOBJ
02b7b6b0 670 wxCHECK_MSG( wxIsClipboardOpened(), false, wxT("clipboard not open") );
26f86486 671
7fc0bd1c 672 wxDataFormat format = data->GetPreferredFormat();
26f86486
VZ
673
674 switch ( format )
06e43511
JS
675 {
676 case wxDF_TEXT:
677 case wxDF_OEMTEXT:
678 {
679 wxTextDataObject* textDataObject = (wxTextDataObject*) data;
680 wxString str(textDataObject->GetText());
26f86486 681 return wxSetClipboardData(format, str.c_str());
06e43511 682 }
26f86486 683
06e43511
JS
684 case wxDF_BITMAP:
685 case wxDF_DIB:
686 {
687 wxBitmapDataObject* bitmapDataObject = (wxBitmapDataObject*) data;
688 wxBitmap bitmap(bitmapDataObject->GetBitmap());
7fc0bd1c 689 return wxSetClipboardData(data->GetPreferredFormat(), &bitmap);
06e43511 690 }
26f86486 691
06e43511
JS
692#if wxUSE_METAFILE
693 case wxDF_METAFILE:
694 {
7fc0bd1c
JS
695#if 1
696 // TODO
0b4f47a3 697 wxLogError(wxT("Not implemented because wxMetafileDataObject does not contain width and height values."));
02b7b6b0 698 return false;
7fc0bd1c 699#else
33ac7e6f 700 wxMetafileDataObject* metaFileDataObject =
26f86486 701 (wxMetafileDataObject*) data;
06e43511 702 wxMetafile metaFile = metaFileDataObject->GetMetafile();
26f86486
VZ
703 return wxSetClipboardData(wxDF_METAFILE, &metaFile,
704 metaFileDataObject->GetWidth(),
705 metaFileDataObject->GetHeight());
7fc0bd1c 706#endif
06e43511 707 }
26f86486
VZ
708#endif // wxUSE_METAFILE
709
06e43511 710 default:
7fc0bd1c
JS
711 {
712// This didn't compile, of course
713// return wxSetClipboardData(data);
714 // TODO
f07dc2e2 715 wxLogError(wxT("Not implemented."));
02b7b6b0 716 return false;
7fc0bd1c 717 }
06e43511 718 }
d59ceba5 719#else // !wxUSE_DATAOBJ
02b7b6b0 720 return false;
d59ceba5 721#endif // wxUSE_DATAOBJ/!wxUSE_DATAOBJ
2bda0e17
KB
722}
723
06e43511 724void wxClipboard::Close()
2bda0e17 725{
02b7b6b0 726 m_isOpened = false;
d59ceba5
VZ
727 // OLE closes clipboard for us
728#if !wxUSE_OLE_CLIPBOARD
06e43511 729 wxCloseClipboard();
d59ceba5 730#endif
2bda0e17
KB
731}
732
2af18715 733bool wxClipboard::IsSupported( const wxDataFormat& format )
2bda0e17 734{
9005f2ed 735 return !IsUsingPrimarySelection() && wxIsClipboardFormatAvailable(format);
2bda0e17
KB
736}
737
1e8335b0 738bool wxClipboard::GetData( wxDataObject& data )
2bda0e17 739{
9005f2ed
VZ
740 if ( IsUsingPrimarySelection() )
741 return false;
742
d59ceba5
VZ
743#if wxUSE_OLE_CLIPBOARD
744 IDataObject *pDataObject = NULL;
745 HRESULT hr = OleGetClipboard(&pDataObject);
746 if ( FAILED(hr) || !pDataObject )
747 {
748 wxLogSysError(hr, _("Failed to get data from the clipboard"));
749
02b7b6b0 750 return false;
d59ceba5
VZ
751 }
752
753 // build the list of supported formats
1e8335b0 754 size_t nFormats = data.GetFormatCount(wxDataObject::Set);
33ac7e6f 755 wxDataFormat format;
c5639a87 756 wxDataFormat *formats;
d59ceba5
VZ
757 if ( nFormats == 1 )
758 {
759 // the most common case
760 formats = &format;
761 }
762 else
763 {
764 // bad luck, need to alloc mem
765 formats = new wxDataFormat[nFormats];
766 }
767
1e8335b0 768 data.GetAllFormats(formats, wxDataObject::Set);
d59ceba5 769
6c29712c
JS
770 // get the data for the given formats
771 FORMATETC formatEtc;
772 CLIPFORMAT cf;
02b7b6b0 773 bool result = false;
6c29712c
JS
774
775 // enumerate all explicit formats on the clipboard.
776 // note that this does not include implicit / synthetic (automatically
777 // converted) formats.
4b6a582b 778#if wxDEBUG_LEVEL >= 2
6c29712c 779 // get the format enumerator
d59ceba5
VZ
780 IEnumFORMATETC *pEnumFormatEtc = NULL;
781 hr = pDataObject->EnumFormatEtc(DATADIR_GET, &pEnumFormatEtc);
782 if ( FAILED(hr) || !pEnumFormatEtc )
783 {
784 wxLogSysError(hr,
785 _("Failed to retrieve the supported clipboard formats"));
786 }
787 else
788 {
789 // ask for the supported formats and see if there are any we support
d59ceba5
VZ
790 for ( ;; )
791 {
792 ULONG nCount;
793 hr = pEnumFormatEtc->Next(1, &formatEtc, &nCount);
794
795 // don't use FAILED() because S_FALSE would pass it
796 if ( hr != S_OK )
797 {
798 // no more formats
799 break;
800 }
801
6c29712c 802 cf = formatEtc.cfFormat;
d59ceba5 803
d59ceba5
VZ
804 wxLogTrace(wxTRACE_OleCalls,
805 wxT("Object on the clipboard supports format %s."),
806 wxDataObject::GetFormatName(cf));
d59ceba5
VZ
807 }
808
809 pEnumFormatEtc->Release();
810 }
4b6a582b 811#endif // wxDEBUG_LEVEL >= 2
d59ceba5 812
6c29712c
JS
813 STGMEDIUM medium;
814 // stop at the first valid format found on the clipboard
815 for ( size_t n = 0; !result && (n < nFormats); n++ )
d59ceba5 816 {
6c29712c
JS
817 // convert to NativeFormat Id
818 cf = formats[n].GetFormatId();
02b7b6b0 819
b8acf11e
RD
820 if (cf == wxDF_HTML)
821 cf = gs_htmlcfid;
6c29712c
JS
822 // if the format is not available, try the next one
823 // this test includes implicit / sythetic formats
824 if ( !::IsClipboardFormatAvailable(cf) )
825 continue;
02b7b6b0 826
6c29712c 827 formatEtc.cfFormat = cf;
d59ceba5
VZ
828 formatEtc.ptd = NULL;
829 formatEtc.dwAspect = DVASPECT_CONTENT;
830 formatEtc.lindex = -1;
d59ceba5 831
6c29712c
JS
832 // use the appropriate tymed
833 switch ( formatEtc.cfFormat )
d59ceba5 834 {
6c29712c
JS
835 case CF_BITMAP:
836 formatEtc.tymed = TYMED_GDI;
837 break;
d59ceba5 838
4676948b 839#ifndef __WXWINCE__
6c29712c
JS
840 case CF_METAFILEPICT:
841 formatEtc.tymed = TYMED_MFPICT;
842 break;
265b0c07 843
6c29712c
JS
844 case CF_ENHMETAFILE:
845 formatEtc.tymed = TYMED_ENHMF;
846 break;
4676948b 847#endif
265b0c07 848
6c29712c
JS
849 default:
850 formatEtc.tymed = TYMED_HGLOBAL;
851 }
852
853 // try to get data
854 hr = pDataObject->GetData(&formatEtc, &medium);
855 if ( FAILED(hr) )
856 {
857 // try other tymed for GDI objects
858 if ( formatEtc.cfFormat == CF_BITMAP )
d59ceba5 859 {
6c29712c
JS
860 formatEtc.tymed = TYMED_HGLOBAL;
861 hr = pDataObject->GetData(&formatEtc, &medium);
d59ceba5 862 }
6c29712c 863 }
d59ceba5 864
6c29712c
JS
865 if ( SUCCEEDED(hr) )
866 {
867 // pass the data to the data object
02b7b6b0 868 hr = data.GetInterface()->SetData(&formatEtc, &medium, true);
6c29712c 869 if ( FAILED(hr) )
d59ceba5 870 {
6c29712c 871 wxLogDebug(wxT("Failed to set data in wxIDataObject"));
d59ceba5 872
6c29712c
JS
873 // IDataObject only takes the ownership of data if it
874 // successfully got it - which is not the case here
875 ReleaseStgMedium(&medium);
876 }
877 else
878 {
02b7b6b0 879 result = true;
d59ceba5 880 }
d59ceba5 881 }
6c29712c 882 //else: unsupported tymed?
d59ceba5 883 }
6c29712c
JS
884
885 if ( formats != &format )
886 {
887 delete [] formats;
888 }
889 //else: we didn't allocate any memory
d59ceba5
VZ
890
891 // clean up and return
892 pDataObject->Release();
893
894 return result;
895#elif wxUSE_DATAOBJ
02b7b6b0 896 wxCHECK_MSG( wxIsClipboardOpened(), false, wxT("clipboard not open") );
26f86486 897
7fc0bd1c 898 wxDataFormat format = data.GetPreferredFormat();
26f86486 899 switch ( format )
06e43511
JS
900 {
901 case wxDF_TEXT:
902 case wxDF_OEMTEXT:
903 {
1e8335b0
VZ
904 wxTextDataObject& textDataObject = (wxTextDataObject &)data;
905 char* s = (char*)wxGetClipboardData(format);
906 if ( !s )
02b7b6b0 907 return false;
1e8335b0 908
f07dc2e2 909 textDataObject.SetText(wxString::FromAscii(s));
1e8335b0
VZ
910 delete [] s;
911
02b7b6b0 912 return true;
06e43511 913 }
26f86486 914
06e43511
JS
915 case wxDF_BITMAP:
916 case wxDF_DIB:
917 {
1e8335b0 918 wxBitmapDataObject& bitmapDataObject = (wxBitmapDataObject &)data;
7fc0bd1c 919 wxBitmap* bitmap = (wxBitmap *)wxGetClipboardData(data.GetPreferredFormat());
1e8335b0 920 if ( !bitmap )
02b7b6b0 921 return false;
1e8335b0
VZ
922
923 bitmapDataObject.SetBitmap(*bitmap);
924 delete bitmap;
925
02b7b6b0 926 return true;
06e43511
JS
927 }
928#if wxUSE_METAFILE
929 case wxDF_METAFILE:
930 {
1e8335b0 931 wxMetafileDataObject& metaFileDataObject = (wxMetafileDataObject &)data;
26f86486 932 wxMetafile* metaFile = (wxMetafile *)wxGetClipboardData(wxDF_METAFILE);
1e8335b0 933 if ( !metaFile )
02b7b6b0 934 return false;
3f480da3 935
1e8335b0
VZ
936 metaFileDataObject.SetMetafile(*metaFile);
937 delete metaFile;
26f86486 938
02b7b6b0 939 return true;
1e8335b0
VZ
940 }
941#endif // wxUSE_METAFILE
06e43511 942 }
02b7b6b0 943 return false;
d59ceba5 944#else // !wxUSE_DATAOBJ
1e8335b0 945 wxFAIL_MSG( wxT("no clipboard implementation") );
02b7b6b0 946 return false;
3897b707 947#endif // wxUSE_OLE_CLIPBOARD/wxUSE_DATAOBJ
2bda0e17
KB
948}
949
47d67540 950#endif // wxUSE_CLIPBOARD