diff options
Diffstat (limited to 'win')
-rw-r--r-- | win/tkWinClipboard.c | 240 |
1 files changed, 193 insertions, 47 deletions
diff --git a/win/tkWinClipboard.c b/win/tkWinClipboard.c index de0b40c..cb7d1a8 100644 --- a/win/tkWinClipboard.c +++ b/win/tkWinClipboard.c @@ -8,12 +8,13 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkWinClipboard.c,v 1.3 1999/04/16 01:51:49 stanton Exp $ + * RCS: @(#) $Id: tkWinClipboard.c,v 1.4 1999/05/22 01:59:22 stanton Exp $ */ #include "tkWinInt.h" #include "tkSelect.h" +static void UpdateClipboard _ANSI_ARGS_((HWND hwnd)); /* *---------------------------------------------------------------------- @@ -49,43 +50,123 @@ TkSelGetSelection(interp, tkwin, selection, target, proc, clientData) * selection, once it has been retrieved. */ ClientData clientData; /* Arbitrary value to pass to proc. */ { - char *data, *buffer, *destPtr; + char *data, *destPtr; Tcl_DString ds; HGLOBAL handle; - int result, length; - - if ((selection == Tk_InternAtom(tkwin, "CLIPBOARD")) - && (target == XA_STRING)) { - if (OpenClipboard(NULL)) { - handle = GetClipboardData(CF_TEXT); - if (handle != NULL) { - data = GlobalLock(handle); - length = strlen(data); - buffer = ckalloc(length+1); - destPtr = buffer; - while (*data != '\0') { - if (*data != '\r') { - *destPtr = *data; - destPtr++; - } - data++; - } - *destPtr = '\0'; - GlobalUnlock(handle); - CloseClipboard(); - Tcl_ExternalToUtfDString(NULL, buffer, -1, &ds); - ckfree(buffer); - result = (*proc)(clientData, interp, Tcl_DStringValue(&ds)); - Tcl_DStringFree(&ds); - return result; - } + Tcl_Encoding encoding; + int result, locale; + + if ((selection != Tk_InternAtom(tkwin, "CLIPBOARD")) + || (target != XA_STRING) + || !OpenClipboard(NULL)) { + goto error; + } + + /* + * Attempt to get the data in Unicode form if available as this is + * less work that CF_TEXT. + */ + + result = TCL_ERROR; + if (IsClipboardFormatAvailable(CF_UNICODETEXT)) { + handle = GetClipboardData(CF_UNICODETEXT); + if (!handle) { CloseClipboard(); + goto error; + } + data = GlobalLock(handle); + Tcl_DStringInit(&ds); + Tcl_UniCharToUtfDString((Tcl_UniChar *)data, + Tcl_UniCharLen((Tcl_UniChar *)data), &ds); + GlobalUnlock(handle); + } else if (IsClipboardFormatAvailable(CF_TEXT) + && IsClipboardFormatAvailable(CF_LOCALE)) { + /* + * Determine the encoding to use to convert this text. + */ + + handle = GetClipboardData(CF_LOCALE); + if (!handle) { + CloseClipboard(); + goto error; + } + + /* + * Get the locale identifier, determine the proper code page to use, + * and find the corresponding encoding. + */ + + Tcl_DStringInit(&ds); + Tcl_DStringAppend(&ds, "cp######", -1); + data = GlobalLock(handle); + + + /* + * Even though the documentation claims that GetLocaleInfo expects an + * LCID, on Windows 9x it really seems to expect a LanguageID. + */ + + locale = LANGIDFROMLCID(*((int*)data)); + GetLocaleInfo(locale, LOCALE_IDEFAULTANSICODEPAGE, + Tcl_DStringValue(&ds)+2, Tcl_DStringLength(&ds)-2); + GlobalUnlock(handle); + + encoding = Tcl_GetEncoding(NULL, Tcl_DStringValue(&ds)); + Tcl_DStringFree(&ds); + + if (!encoding) { + CloseClipboard(); + goto error; + } + + /* + * Fetch the text and convert it to UTF. + */ + + handle = GetClipboardData(CF_TEXT); + if (!handle) { + Tcl_FreeEncoding(encoding); + CloseClipboard(); + goto error; + } + data = GlobalLock(handle); + Tcl_ExternalToUtfDString(encoding, data, -1, &ds); + GlobalUnlock(handle); + Tcl_FreeEncoding(encoding); + + } else { + CloseClipboard(); + goto error; + } + + /* + * Translate CR/LF to LF. + */ + + data = destPtr = Tcl_DStringValue(&ds); + while (*data) { + if (data[0] == '\r' && data[1] == '\n') { + data++; + } else { + *destPtr++ = *data++; } } + *destPtr = '\0'; + + /* + * Pass the data off to the selection procedure. + */ + result = (*proc)(clientData, interp, Tcl_DStringValue(&ds)); + Tcl_DStringFree(&ds); + CloseClipboard(); + return result; + +error: Tcl_AppendResult(interp, Tk_GetAtomName(tkwin, selection), - " selection doesn't exist or form \"", Tk_GetAtomName(tkwin, target), - "\" not defined", (char *) NULL); + " selection doesn't exist or form \"", + Tk_GetAtomName(tkwin, target), + "\" not defined", (char *) NULL); return TCL_ERROR; } @@ -132,10 +213,7 @@ XSetSelectionOwner(display, selection, owner, time) */ if (GetClipboardOwner() != hwnd) { - OpenClipboard(hwnd); - EmptyClipboard(); - SetClipboardData(CF_TEXT, NULL); - CloseClipboard(); + UpdateClipboard(hwnd); } } } @@ -174,6 +252,12 @@ TkWinClipboardRender(dispPtr, format) if (targetPtr->type == XA_STRING) break; } + + /* + * Count the number of newlines so we can add space for them in + * the resulting string. + */ + length = 0; if (targetPtr != NULL) { for (cbPtr = targetPtr->firstBufferPtr; cbPtr != NULL; @@ -187,6 +271,11 @@ TkWinClipboardRender(dispPtr, format) } } } + + /* + * Copy the data and change EOL characters. + */ + buffer = rawText = ckalloc(length + 1); if (targetPtr != NULL) { for (cbPtr = targetPtr->firstBufferPtr; cbPtr != NULL; @@ -201,19 +290,43 @@ TkWinClipboardRender(dispPtr, format) } } *buffer = '\0'; - Tcl_UtfToExternalDString(NULL, rawText, -1, &ds); - ckfree(rawText); - handle = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE, - Tcl_DStringLength(&ds)+1); - if (!handle) { + + /* + * Depending on the platform, turn the data into Unicode or the + * system encoding before placing it on the clipboard. + */ + + if (TkWinGetPlatformId() == VER_PLATFORM_WIN32_NT) { + Tcl_DStringInit(&ds); + Tcl_UtfToUniCharDString(rawText, -1, &ds); + ckfree(rawText); + handle = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE, + Tcl_DStringLength(&ds)+2); + if (!handle) { + Tcl_DStringFree(&ds); + return; + } + buffer = GlobalLock(handle); + memcpy(buffer, Tcl_DStringValue(&ds), Tcl_DStringLength(&ds) + 2); + GlobalUnlock(handle); Tcl_DStringFree(&ds); - return; + SetClipboardData(CF_UNICODETEXT, handle); + } else { + Tcl_UtfToExternalDString(NULL, rawText, -1, &ds); + ckfree(rawText); + handle = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE, + Tcl_DStringLength(&ds)+1); + if (!handle) { + Tcl_DStringFree(&ds); + return; + } + buffer = GlobalLock(handle); + memcpy(buffer, Tcl_DStringValue(&ds), Tcl_DStringLength(&ds) + 1); + GlobalUnlock(handle); + Tcl_DStringFree(&ds); + SetClipboardData(CF_TEXT, handle); } - buffer = GlobalLock(handle); - memcpy(buffer, Tcl_DStringValue(&ds), Tcl_DStringLength(&ds) + 1); - GlobalUnlock(handle); - Tcl_DStringFree(&ds); - SetClipboardData(CF_TEXT, handle); + return; } @@ -240,10 +353,43 @@ TkSelUpdateClipboard(winPtr, targetPtr) TkClipboardTarget *targetPtr; { HWND hwnd = TkWinGetHWND(winPtr->window); + UpdateClipboard(hwnd); +} + +/* + *---------------------------------------------------------------------- + * + * UpdateClipboard -- + * + * Take ownership of the clipboard, clear it, and indicate to the + * system the supported formats. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ +static void +UpdateClipboard(hwnd) + HWND hwnd; +{ OpenClipboard(hwnd); EmptyClipboard(); - SetClipboardData(CF_TEXT, NULL); + + /* + * CF_UNICODETEXT is only supported on NT, but it it is preffered + * when possible. + */ + + if (TkWinGetPlatformId() == VER_PLATFORM_WIN32_NT) { + SetClipboardData(CF_UNICODETEXT, NULL); + } else { + SetClipboardData(CF_TEXT, NULL); + } CloseClipboard(); } |