#include "CtrlCore.h" #include NAMESPACE_UPP #ifdef PLATFORM_WIN32 #define LLOG(x) // LOG(x) VectorMap& sClipMap() { static VectorMap x; return x; } extern HWND utilityHWND; int GetClipboardFormatCode(const char *format_id) { int x = (int)(intptr_t)format_id; if(x >= 0 && x < 65535) return x; String fmt = format_id; if(fmt == "text") return CF_TEXT; if(fmt == "wtext") return CF_UNICODETEXT; if(fmt == "dib") return CF_DIB; if(fmt == "files") return CF_HDROP; static StaticMutex m; Mutex::Lock __(m); static VectorMap format_map; int f = format_map.Find(format_id); if(f < 0) { f = format_map.GetCount(); format_map.Add(format_id, #ifdef PLATFORM_WINCE ::RegisterClipboardFormat(ToSystemCharset(format_id)) #else ::RegisterClipboardFormat(format_id) #endif ); } return format_map[f]; } void ClearClipboard() { sClipMap().Clear(); if(OpenClipboard(utilityHWND)) { EmptyClipboard(); CloseClipboard(); } } void SetClipboardRaw(int format, const byte *data, int length) { HANDLE handle = NULL; if(data) { handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, length + 2); byte *ptr; if(!handle) return; if(!(ptr = (byte *)GlobalLock(handle))) { GlobalFree(handle); return; } memcpy(ptr, data, length); ptr[length] = 0; ptr[length + 1] = 0; GlobalUnlock(handle); } if(!SetClipboardData(format, handle)) { LLOG("SetClipboardData error: " << GetLastErrorMessage()); GlobalFree(handle); } } void AppendClipboard(int format, const byte *data, int length) { if(OpenClipboard(utilityHWND)) { SetClipboardRaw(format, data, length); CloseClipboard(); } } void AppendClipboard(const char *format, const byte *data, int length) { Vector f = Split(format, ';'); for(int i = 0; i < f.GetCount(); i++) AppendClipboard(GetClipboardFormatCode(f[i]), data, length); } void AppendClipboard(const char *format, const String& data) { AppendClipboard(format, data, data.GetLength()); } void AppendClipboard(const char *format, const Value& data, String (*render)(const Value&)) { Vector f = Split(format, ';'); for(int i = 0; i < f.GetCount(); i++) { int c = GetClipboardFormatCode(f[i]); sClipMap().GetAdd(c) = ClipData(data, render); AppendClipboard(c, NULL, 0); } } void Ctrl::RenderFormat(int format) { int q = sClipMap().Find(format); if(q >= 0) { String s = sClipMap()[q].Render(); SetClipboardRaw(format, s, s.GetLength()); } } void Ctrl::RenderAllFormats() { if(sClipMap().GetCount() && OpenClipboard(utilityHWND)) { for(int i = 0; i < sClipMap().GetCount(); i++) RenderFormat(sClipMap().GetKey(i)); CloseClipboard(); } } void Ctrl::DestroyClipboard() { sClipMap().Clear(); } String ReadClipboard(const char *format) { if(!OpenClipboard(NULL)) return Null; HGLOBAL hmem = GetClipboardData(GetClipboardFormatCode(format)); if(hmem == 0) { CloseClipboard(); return Null; } const byte *src = (const byte *)GlobalLock(hmem); ASSERT(src); int length = (int)GlobalSize(hmem); if(length < 0) { CloseClipboard(); return Null; } String out(src, length); GlobalUnlock(hmem); CloseClipboard(); return out; } void AppendClipboardText(const String& s) { #ifdef PLATFORM_WINCE AppendClipboardUnicodeText(s.ToWString()); #else AppendClipboard("text", ToSystemCharset(s)); #endif } void AppendClipboardUnicodeText(const WString& s) { #ifndef PLATFORM_WINCE AppendClipboardText(s.ToString()); #endif AppendClipboard("wtext", (byte *)~s, 2 * s.GetLength()); } const char *ClipFmtsText() { return "wtext;text"; } String GetString(PasteClip& clip) { if(clip.Accept("wtext")) { String s = ~clip; return WString((const wchar *)~s, wstrlen((const wchar *)~s)).ToString(); } if(clip.IsAvailable("text")) return ~clip; return Null; } WString GetWString(PasteClip& clip) { if(clip.Accept("wtext")) { String s = ~clip; return WString((const wchar *)~s, wstrlen((const wchar *)~s)); } if(clip.IsAvailable("text")) return (~clip).ToWString(); return Null; } bool AcceptText(PasteClip& clip) { return clip.Accept(ClipFmtsText()); } static String sText(const Value& data) { return data; } static String sWText(const Value& data) { return Unicode__(WString(data)); } void Append(VectorMap& data, const String& text) { data.GetAdd("text", ClipData(text, sText)); data.GetAdd("wtext", ClipData(text, sWText)); } void Append(VectorMap& data, const WString& text) { data.GetAdd("text", ClipData(text, sText)); data.GetAdd("wtext", ClipData(text, sWText)); } String GetTextClip(const WString& text, const String& fmt) { if(fmt == "text") return text.ToString(); if(fmt == "wtext") return Unicode__(text); return Null; } String GetTextClip(const String& text, const String& fmt) { if(fmt == "text") return text; if(fmt == "wtext") return Unicode__(text.ToWString()); return Null; } String ReadClipboardText() { #ifdef PLATFORM_WINCE return ReadClipboardUnicodeText().ToString(); #else String s = ReadClipboard((const char *)CF_TEXT); return String(s, (int)strlen(~s)); #endif } WString ReadClipboardUnicodeText() { String s = ReadClipboard((const char *)CF_UNICODETEXT); return WString((const wchar *)~s, wstrlen((const wchar *)~s)); } bool IsClipboardAvailable(const char *id) { return ::IsClipboardFormatAvailable(GetClipboardFormatCode(id)); } bool IsClipboardAvailableText() { return IsClipboardAvailable((const char *)CF_TEXT); } const char *ClipFmtsImage() { static const char *q; ONCELOCK { static String s = "dib;" + ClipFmt(); q = s; } return q; } bool AcceptImage(PasteClip& clip) { return clip.Accept(ClipFmtsImage()); } Image GetImage(PasteClip& clip) { Image m; if(Accept(clip)) { LoadFromString(m, ~clip); if(!m.IsEmpty()) return m; } if(clip.Accept("dib")) { String data = ~clip; if(data.GetCount() < sizeof(BITMAPINFO)) return Null; BITMAPINFO *lpBI = (BITMAPINFO *)~data; BITMAPINFOHEADER& hdr = lpBI->bmiHeader; byte *bits = (byte *)lpBI + hdr.biSize; if(hdr.biBitCount <= 8) bits += (hdr.biClrUsed ? hdr.biClrUsed : 1 << hdr.biBitCount) * sizeof(RGBQUAD); if(hdr.biBitCount >= 16 || hdr.biBitCount == 32) { if(hdr.biCompression == 3) bits += 12; if(hdr.biClrUsed != 0) bits += hdr.biClrUsed * sizeof(RGBQUAD); } int h = abs((int)hdr.biHeight); ImageDraw iw(hdr.biWidth, h); ::StretchDIBits(iw.GetHandle(), 0, 0, hdr.biWidth, h, 0, 0, hdr.biWidth, h, bits, lpBI, DIB_RGB_COLORS, SRCCOPY); return iw; } return Null; } Image ReadClipboardImage() { PasteClip d = Ctrl::Clipboard(); return GetImage(d); } String sDib(const Value& image) { Image img = image; BITMAPINFOHEADER header; Zero(header); header.biSize = sizeof(header); header.biWidth = img.GetWidth(); header.biHeight = -img.GetHeight(); header.biBitCount = 32; header.biPlanes = 1; header.biCompression = BI_RGB; StringBuffer b(sizeof(header) + 4 * img.GetLength()); byte *p = (byte *)~b; memcpy(p, &header, sizeof(header)); memcpy(p + sizeof(header), ~img, 4 * img.GetLength()); return b; } String sImage(const Value& image) { Image img = image; return StoreAsString(const_cast(img)); } String GetImageClip(const Image& img, const String& fmt) { if(img.IsEmpty()) return Null; if(fmt == "dib") return sDib(img); if(fmt == ClipFmt()) return sImage(img); return Null; } void AppendClipboardImage(const Image& img) { if(img.IsEmpty()) return; AppendClipboard(ClipFmt(), img, sImage); AppendClipboard("dib", img, sDib); } bool AcceptFiles(PasteClip& clip) { if(clip.Accept("files")) { clip.SetAction(DND_COPY); return true; } return false; } struct sDROPFILES { DWORD offset; POINT dummy; BOOL dummy2; BOOL unicode; }; Vector GetFiles(PasteClip& clip) { Vector f; String data = clip; if(data.GetCount() < sizeof(sDROPFILES) + 2) return f; const sDROPFILES *df = (const sDROPFILES *)~data; const char *s = ((const char *)df + df->offset); if(df->unicode) { const wchar *ws = (wchar *)s; while(*ws) { WString fn; while(*ws) fn.Cat(*ws++); f.Add(fn.ToString()); ws++; } } else while(*s) { String fn; while(*s) fn.Cat(*s++); f.Add(fn.ToString()); s++; } return f; } #endif END_UPP_NAMESPACE