///////////////////////////////////////////////////////////////////////////// // Name: src/msw/clipbrd.cpp // Purpose: Clipboard functionality // Author: Julian Smart // Modified by: // Created: 04/01/98 // Copyright: (c) Julian Smart // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// // =========================================================================== // declarations // =========================================================================== // --------------------------------------------------------------------------- // headers // --------------------------------------------------------------------------- // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" #ifdef __BORLANDC__ #pragma hdrstop #endif #if wxUSE_CLIPBOARD #include "wx/clipbrd.h" #ifndef WX_PRECOMP #include "wx/object.h" #include "wx/event.h" #include "wx/app.h" #include "wx/frame.h" #include "wx/bitmap.h" #include "wx/utils.h" #include "wx/intl.h" #include "wx/log.h" #include "wx/dataobj.h" #include "wx/dcmemory.h" #endif #if wxUSE_METAFILE #include "wx/metafile.h" #endif #include #include "wx/msw/private.h" #include "wx/msw/ole/oleutils.h" #if wxUSE_WXDIB #include "wx/msw/dib.h" #endif #if wxUSE_OLE // use OLE clipboard #define wxUSE_OLE_CLIPBOARD 1 #else // !wxUSE_DATAOBJ // use Win clipboard API #define wxUSE_OLE_CLIPBOARD 0 #endif #if wxUSE_OLE_CLIPBOARD #include #endif // wxUSE_OLE_CLIPBOARD // =========================================================================== // implementation // =========================================================================== // --------------------------------------------------------------------------- // old-style clipboard functions using Windows API // --------------------------------------------------------------------------- static bool gs_wxClipboardIsOpen = false; static int gs_htmlcfid = 0; bool wxOpenClipboard() { wxCHECK_MSG( !gs_wxClipboardIsOpen, true, wxT("clipboard already opened.") ); wxWindow *win = wxTheApp->GetTopWindow(); if ( win ) { gs_wxClipboardIsOpen = ::OpenClipboard((HWND)win->GetHWND()) != 0; if ( !gs_wxClipboardIsOpen ) { wxLogSysError(_("Failed to open the clipboard.")); } return gs_wxClipboardIsOpen; } else { wxLogDebug(wxT("Cannot open clipboard without a main window.")); return false; } } bool wxCloseClipboard() { wxCHECK_MSG( gs_wxClipboardIsOpen, false, wxT("clipboard is not opened") ); gs_wxClipboardIsOpen = false; if ( ::CloseClipboard() == 0 ) { wxLogSysError(_("Failed to close the clipboard.")); return false; } return true; } bool wxEmptyClipboard() { if ( ::EmptyClipboard() == 0 ) { wxLogSysError(_("Failed to empty the clipboard.")); return false; } return true; } bool wxIsClipboardOpened() { return gs_wxClipboardIsOpen; } bool wxIsClipboardFormatAvailable(wxDataFormat dataFormat) { wxDataFormat::NativeFormat cf = dataFormat.GetFormatId(); if (cf == wxDF_HTML) cf = gs_htmlcfid; if ( ::IsClipboardFormatAvailable(cf) ) { // ok from the first try return true; } // for several standard formats, we can convert from some other ones too switch ( cf ) { // for bitmaps, DIBs will also do case CF_BITMAP: return ::IsClipboardFormatAvailable(CF_DIB) != 0; #if wxUSE_ENH_METAFILE case CF_METAFILEPICT: return ::IsClipboardFormatAvailable(CF_ENHMETAFILE) != 0; #endif // wxUSE_ENH_METAFILE default: return false; } } #if !wxUSE_OLE_CLIPBOARD bool wxSetClipboardData(wxDataFormat dataFormat, const void *data, int width, int height) { HANDLE handle = 0; // return value of SetClipboardData switch (dataFormat) { case wxDF_BITMAP: { wxBitmap *bitmap = (wxBitmap *)data; HDC hdcMem = CreateCompatibleDC((HDC) NULL); HDC hdcSrc = CreateCompatibleDC((HDC) NULL); HBITMAP old = (HBITMAP) ::SelectObject(hdcSrc, (HBITMAP)bitmap->GetHBITMAP()); HBITMAP hBitmap = CreateCompatibleBitmap(hdcSrc, bitmap->GetWidth(), bitmap->GetHeight()); if (!hBitmap) { SelectObject(hdcSrc, old); DeleteDC(hdcMem); DeleteDC(hdcSrc); return false; } HBITMAP old1 = (HBITMAP) SelectObject(hdcMem, hBitmap); BitBlt(hdcMem, 0, 0, bitmap->GetWidth(), bitmap->GetHeight(), hdcSrc, 0, 0, SRCCOPY); // Select new bitmap out of memory DC SelectObject(hdcMem, old1); // Set the data handle = ::SetClipboardData(CF_BITMAP, hBitmap); // Clean up SelectObject(hdcSrc, old); DeleteDC(hdcSrc); DeleteDC(hdcMem); break; } #if wxUSE_WXDIB case wxDF_DIB: { wxBitmap *bitmap = (wxBitmap *)data; if ( bitmap && bitmap->IsOk() ) { wxDIB dib(*bitmap); if ( dib.IsOk() ) { DIBSECTION ds; int n = ::GetObject(dib.GetHandle(), sizeof(DIBSECTION), &ds); wxASSERT( n == sizeof(DIBSECTION) && ds.dsBm.bmBits ); // Number of colours in the palette. int numColors; switch ( ds.dsBmih.biCompression ) { case BI_BITFIELDS: numColors = 3; break; case BI_RGB: numColors = ds.dsBmih.biClrUsed; if ( !numColors ) { numColors = ds.dsBmih.biBitCount <= 8 ? 1 << ds.dsBmih.biBitCount : 0; } break; default: numColors = 0; } unsigned long bmpSize = wxDIB::GetLineSize(ds.dsBmih.biWidth, ds.dsBmih.biBitCount) * abs(ds.dsBmih.biHeight); HANDLE hMem; hMem = ::GlobalAlloc(GHND, ds.dsBmih.biSize + numColors*sizeof(RGBQUAD) + bmpSize); if ( !hMem ) break; { GlobalPtrLock ptr(hMem); char* pDst = (char*)ptr.Get(); memcpy(pDst, &ds.dsBmih, ds.dsBmih.biSize); pDst += ds.dsBmih.biSize; if ( numColors > 0 ) { // Get colour table. MemoryHDC hDC; SelectInHDC sDC(hDC, dib.GetHandle()); ::GetDIBColorTable(hDC, 0, numColors, (RGBQUAD*)pDst); pDst += numColors*sizeof(RGBQUAD); } memcpy(pDst, dib.GetData(), bmpSize); } // unlock hMem handle = ::SetClipboardData(CF_DIB, hMem); } } break; } #endif // VZ: I'm told that this code works, but it doesn't seem to work for me // and, anyhow, I'd be highly surprised if it did. So I leave it here // but IMNSHO it is completely broken. #if wxUSE_METAFILE && !defined(wxMETAFILE_IS_ENH) case wxDF_METAFILE: { wxMetafile *wxMF = (wxMetafile *)data; HANDLE data = GlobalAlloc(GHND, sizeof(METAFILEPICT) + 1); { GlobalPtrLock ptr(data); METAFILEPICT *mf = (METAFILEPICT *)data.Get(); mf->mm = wxMF->GetWindowsMappingMode(); mf->xExt = width; mf->yExt = height; mf->hMF = (HMETAFILE) wxMF->GetHMETAFILE(); wxMF->SetHMETAFILE((WXHANDLE) NULL); } // unlock data handle = SetClipboardData(CF_METAFILEPICT, data); break; } #endif // wxUSE_METAFILE #if wxUSE_ENH_METAFILE case wxDF_ENHMETAFILE: { wxEnhMetaFile *emf = (wxEnhMetaFile *)data; wxEnhMetaFile emfCopy = *emf; handle = SetClipboardData(CF_ENHMETAFILE, (void *)emfCopy.GetHENHMETAFILE()); } break; #endif // wxUSE_ENH_METAFILE case CF_SYLK: case CF_DIF: case CF_TIFF: case CF_PALETTE: default: { wxLogError(_("Unsupported clipboard format.")); return false; } case wxDF_OEMTEXT: dataFormat = wxDF_TEXT; // fall through case wxDF_TEXT: { char *s = (char *)data; width = strlen(s) + 1; height = 1; DWORD l = (width * height); HANDLE hGlobalMemory = GlobalAlloc(GHND, l); if ( hGlobalMemory ) { memcpy(GlobalPtrLock(hGlobalMemory), s, l); } handle = SetClipboardData(dataFormat, hGlobalMemory); break; } case wxDF_UNICODETEXT: { LPWSTR s = (LPWSTR)data; DWORD size = sizeof(WCHAR) * (lstrlenW(s) + 1); HANDLE hGlobalMemory = ::GlobalAlloc(GHND, size); if ( hGlobalMemory ) { memcpy(GlobalPtrLock(hGlobalMemory), s, size); } handle = ::SetClipboardData(CF_UNICODETEXT, hGlobalMemory); } break; case wxDF_HTML: { char* html = (char *)data; // Create temporary buffer for HTML header... char *buf = new char [400 + strlen(html)]; if(!buf) return false; // Create a template string for the HTML header... strcpy(buf, "Version:0.9\r\n" "StartHTML:00000000\r\n" "EndHTML:00000000\r\n" "StartFragment:00000000\r\n" "EndFragment:00000000\r\n" "\r\n" "\r\n"); // Append the HTML... strcat(buf, html); strcat(buf, "\r\n"); // Finish up the HTML format... strcat(buf, "\r\n" "\r\n" ""); // Now go back, calculate all the lengths, and write out the // necessary header information. Note, wsprintf() truncates the // string when you overwrite it so you follow up with code to replace // the 0 appended at the end with a '\r'... char *ptr = strstr(buf, "StartHTML"); sprintf(ptr+10, "%08u", (unsigned)(strstr(buf, "") - buf)); *(ptr+10+8) = '\r'; ptr = strstr(buf, "EndHTML"); sprintf(ptr+8, "%08u", (unsigned)strlen(buf)); *(ptr+8+8) = '\r'; ptr = strstr(buf, "StartFragment"); sprintf(ptr+14, "%08u", (unsigned)(strstr(buf, "