1/* 2 * tkWinClipboard.c -- 3 * 4 * This file contains functions for managing the clipboard. 5 * 6 * Copyright (c) 1995-1997 Sun Microsystems, Inc. 7 * Copyright (c) 1998-2000 by Scriptics Corporation. 8 * 9 * See the file "license.terms" for information on usage and redistribution of 10 * this file, and for a DISCLAIMER OF ALL WARRANTIES. 11 * 12 * RCS: @(#) $Id$ 13 */ 14 15#include "tkWinInt.h" 16#include "tkSelect.h" 17 18static void UpdateClipboard(HWND hwnd); 19 20/* 21 *---------------------------------------------------------------------- 22 * 23 * TkSelGetSelection -- 24 * 25 * Retrieve the specified selection from another process. For now, only 26 * fetching XA_STRING from CLIPBOARD is supported. Eventually other types 27 * should be allowed. 28 * 29 * Results: 30 * The return value is a standard Tcl return value. If an error occurs 31 * (such as no selection exists) then an error message is left in the 32 * interp's result. 33 * 34 * Side effects: 35 * None. 36 * 37 *---------------------------------------------------------------------- 38 */ 39 40int 41TkSelGetSelection( 42 Tcl_Interp *interp, /* Interpreter to use for reporting errors. */ 43 Tk_Window tkwin, /* Window on whose behalf to retrieve the 44 * selection (determines display from which to 45 * retrieve). */ 46 Atom selection, /* Selection to retrieve. */ 47 Atom target, /* Desired form in which selection is to be 48 * returned. */ 49 Tk_GetSelProc *proc, /* Procedure to call to process the selection, 50 * once it has been retrieved. */ 51 ClientData clientData) /* Arbitrary value to pass to proc. */ 52{ 53 char *data, *destPtr; 54 Tcl_DString ds; 55 HGLOBAL handle; 56 Tcl_Encoding encoding; 57 int result, locale; 58 59 if ((selection != Tk_InternAtom(tkwin, "CLIPBOARD")) 60 || (target != XA_STRING) 61 || !OpenClipboard(NULL)) { 62 goto error; 63 } 64 65 /* 66 * Attempt to get the data in Unicode form if available as this is less 67 * work that CF_TEXT. 68 */ 69 70 result = TCL_ERROR; 71 if (IsClipboardFormatAvailable(CF_UNICODETEXT)) { 72 handle = GetClipboardData(CF_UNICODETEXT); 73 if (!handle) { 74 CloseClipboard(); 75 goto error; 76 } 77 data = GlobalLock(handle); 78 Tcl_DStringInit(&ds); 79 Tcl_UniCharToUtfDString((Tcl_UniChar *)data, 80 Tcl_UniCharLen((Tcl_UniChar *)data), &ds); 81 GlobalUnlock(handle); 82 } else if (IsClipboardFormatAvailable(CF_TEXT)) { 83 /* 84 * Determine the encoding to use to convert this text. 85 */ 86 87 if (IsClipboardFormatAvailable(CF_LOCALE)) { 88 handle = GetClipboardData(CF_LOCALE); 89 if (!handle) { 90 CloseClipboard(); 91 goto error; 92 } 93 94 /* 95 * Get the locale identifier, determine the proper code page to 96 * use, and find the corresponding encoding. 97 */ 98 99 Tcl_DStringInit(&ds); 100 Tcl_DStringAppend(&ds, "cp######", -1); 101 data = GlobalLock(handle); 102 103 /* 104 * Even though the documentation claims that GetLocaleInfo expects 105 * an LCID, on Windows 9x it really seems to expect a LanguageID. 106 */ 107 108 locale = LANGIDFROMLCID(*((int*)data)); 109 GetLocaleInfo(locale, LOCALE_IDEFAULTANSICODEPAGE, 110 Tcl_DStringValue(&ds)+2, Tcl_DStringLength(&ds)-2); 111 GlobalUnlock(handle); 112 113 encoding = Tcl_GetEncoding(NULL, Tcl_DStringValue(&ds)); 114 Tcl_DStringFree(&ds); 115 } else { 116 encoding = NULL; 117 } 118 119 /* 120 * Fetch the text and convert it to UTF. 121 */ 122 123 handle = GetClipboardData(CF_TEXT); 124 if (!handle) { 125 if (encoding) { 126 Tcl_FreeEncoding(encoding); 127 } 128 CloseClipboard(); 129 goto error; 130 } 131 data = GlobalLock(handle); 132 Tcl_ExternalToUtfDString(encoding, data, -1, &ds); 133 GlobalUnlock(handle); 134 if (encoding) { 135 Tcl_FreeEncoding(encoding); 136 } 137 138 } else { 139 CloseClipboard(); 140 goto error; 141 } 142 143 /* 144 * Translate CR/LF to LF. 145 */ 146 147 data = destPtr = Tcl_DStringValue(&ds); 148 while (*data) { 149 if (data[0] == '\r' && data[1] == '\n') { 150 data++; 151 } else { 152 *destPtr++ = *data++; 153 } 154 } 155 *destPtr = '\0'; 156 157 /* 158 * Pass the data off to the selection procedure. 159 */ 160 161 result = (*proc)(clientData, interp, Tcl_DStringValue(&ds)); 162 Tcl_DStringFree(&ds); 163 CloseClipboard(); 164 return result; 165 166 error: 167 Tcl_AppendResult(interp, Tk_GetAtomName(tkwin, selection), 168 " selection doesn't exist or form \"", 169 Tk_GetAtomName(tkwin, target), "\" not defined", NULL); 170 return TCL_ERROR; 171} 172 173/* 174 *---------------------------------------------------------------------- 175 * 176 * TkSetSelectionOwner -- 177 * 178 * This function claims ownership of the specified selection. If the 179 * selection is CLIPBOARD, then we empty the system clipboard. 180 * 181 * Results: 182 * None. 183 * 184 * Side effects: 185 * Empties the system clipboard, and claims ownership. 186 * 187 *---------------------------------------------------------------------- 188 */ 189 190void 191XSetSelectionOwner( 192 Display *display, 193 Atom selection, 194 Window owner, 195 Time time) 196{ 197 HWND hwnd = owner ? TkWinGetHWND(owner) : NULL; 198 Tk_Window tkwin; 199 200 /* 201 * This is a gross hack because the Tk_InternAtom interface is broken. It 202 * expects a Tk_Window, even though it only needs a Tk_Display. 203 */ 204 205 tkwin = (Tk_Window) TkGetMainInfoList()->winPtr; 206 207 if (selection == Tk_InternAtom(tkwin, "CLIPBOARD")) { 208 /* 209 * Only claim and empty the clipboard if we aren't already the owner 210 * of the clipboard. 211 */ 212 213 if (GetClipboardOwner() != hwnd) { 214 UpdateClipboard(hwnd); 215 } 216 } 217} 218 219/* 220 *---------------------------------------------------------------------- 221 * 222 * TkWinClipboardRender -- 223 * 224 * This function supplies the contents of the clipboard in response to a 225 * WM_RENDERFORMAT message. 226 * 227 * Results: 228 * None. 229 * 230 * Side effects: 231 * Sets the contents of the clipboard. 232 * 233 *---------------------------------------------------------------------- 234 */ 235 236void 237TkWinClipboardRender( 238 TkDisplay *dispPtr, 239 UINT format) 240{ 241 TkClipboardTarget *targetPtr; 242 TkClipboardBuffer *cbPtr; 243 HGLOBAL handle; 244 char *buffer, *p, *rawText, *endPtr; 245 int length; 246 Tcl_DString ds; 247 248 for (targetPtr = dispPtr->clipTargetPtr; targetPtr != NULL; 249 targetPtr = targetPtr->nextPtr) { 250 if (targetPtr->type == XA_STRING) { 251 break; 252 } 253 } 254 255 /* 256 * Count the number of newlines so we can add space for them in the 257 * resulting string. 258 */ 259 260 length = 0; 261 if (targetPtr != NULL) { 262 for (cbPtr = targetPtr->firstBufferPtr; cbPtr != NULL; 263 cbPtr = cbPtr->nextPtr) { 264 length += cbPtr->length; 265 for (p = cbPtr->buffer, endPtr = p + cbPtr->length; 266 p < endPtr; p++) { 267 if (*p == '\n') { 268 length++; 269 } 270 } 271 } 272 } 273 274 /* 275 * Copy the data and change EOL characters. 276 */ 277 278 buffer = rawText = ckalloc((unsigned)length + 1); 279 if (targetPtr != NULL) { 280 for (cbPtr = targetPtr->firstBufferPtr; cbPtr != NULL; 281 cbPtr = cbPtr->nextPtr) { 282 for (p = cbPtr->buffer, endPtr = p + cbPtr->length; 283 p < endPtr; p++) { 284 if (*p == '\n') { 285 *buffer++ = '\r'; 286 } 287 *buffer++ = *p; 288 } 289 } 290 } 291 *buffer = '\0'; 292 293 /* 294 * Depending on the platform, turn the data into Unicode or the system 295 * encoding before placing it on the clipboard. 296 */ 297 298 if (TkWinGetPlatformId() == VER_PLATFORM_WIN32_NT) { 299 Tcl_DStringInit(&ds); 300 Tcl_UtfToUniCharDString(rawText, -1, &ds); 301 ckfree(rawText); 302 handle = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE, 303 (unsigned) Tcl_DStringLength(&ds) + 2); 304 if (!handle) { 305 Tcl_DStringFree(&ds); 306 return; 307 } 308 buffer = GlobalLock(handle); 309 memcpy(buffer, Tcl_DStringValue(&ds), 310 (unsigned) Tcl_DStringLength(&ds) + 2); 311 GlobalUnlock(handle); 312 Tcl_DStringFree(&ds); 313 SetClipboardData(CF_UNICODETEXT, handle); 314 } else { 315 Tcl_UtfToExternalDString(NULL, rawText, -1, &ds); 316 ckfree(rawText); 317 handle = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE, 318 (unsigned) Tcl_DStringLength(&ds) + 1); 319 if (!handle) { 320 Tcl_DStringFree(&ds); 321 return; 322 } 323 buffer = GlobalLock(handle); 324 memcpy(buffer, Tcl_DStringValue(&ds), 325 (unsigned) Tcl_DStringLength(&ds) + 1); 326 GlobalUnlock(handle); 327 Tcl_DStringFree(&ds); 328 SetClipboardData(CF_TEXT, handle); 329 } 330} 331 332/* 333 *---------------------------------------------------------------------- 334 * 335 * TkSelUpdateClipboard -- 336 * 337 * This function is called to force the clipboard to be updated after new 338 * data is added. 339 * 340 * Results: 341 * None. 342 * 343 * Side effects: 344 * Clears the current contents of the clipboard. 345 * 346 *---------------------------------------------------------------------- 347 */ 348 349void 350TkSelUpdateClipboard( 351 TkWindow *winPtr, 352 TkClipboardTarget *targetPtr) 353{ 354 HWND hwnd = TkWinGetHWND(winPtr->window); 355 UpdateClipboard(hwnd); 356} 357 358/* 359 *---------------------------------------------------------------------- 360 * 361 * UpdateClipboard -- 362 * 363 * Take ownership of the clipboard, clear it, and indicate to the system 364 * the supported formats. 365 * 366 * Results: 367 * None. 368 * 369 * Side effects: 370 * None. 371 * 372 *---------------------------------------------------------------------- 373 */ 374 375static void 376UpdateClipboard( 377 HWND hwnd) 378{ 379 TkWinUpdatingClipboard(TRUE); 380 OpenClipboard(hwnd); 381 EmptyClipboard(); 382 383 /* 384 * CF_UNICODETEXT is only supported on NT, but it it is prefered when 385 * possible. 386 */ 387 388 if (TkWinGetPlatformId() == VER_PLATFORM_WIN32_NT) { 389 SetClipboardData(CF_UNICODETEXT, NULL); 390 } else { 391 SetClipboardData(CF_TEXT, NULL); 392 } 393 CloseClipboard(); 394 TkWinUpdatingClipboard(FALSE); 395} 396 397/* 398 *-------------------------------------------------------------- 399 * 400 * TkSelEventProc -- 401 * 402 * This procedure is invoked whenever a selection-related event occurs. 403 * 404 * Results: 405 * None. 406 * 407 * Side effects: 408 * Lots: depends on the type of event. 409 * 410 *-------------------------------------------------------------- 411 */ 412 413void 414TkSelEventProc( 415 Tk_Window tkwin, /* Window for which event was targeted. */ 416 register XEvent *eventPtr) /* X event: either SelectionClear, 417 * SelectionRequest, or SelectionNotify. */ 418{ 419 if (eventPtr->type == SelectionClear) { 420 TkSelClearSelection(tkwin, eventPtr); 421 } 422} 423 424/* 425 *---------------------------------------------------------------------- 426 * 427 * TkSelPropProc -- 428 * 429 * This procedure is invoked when property-change events occur on windows 430 * not known to the toolkit. This is a stub function under Windows. 431 * 432 * Results: 433 * None. 434 * 435 * Side effects: 436 * None. 437 * 438 *---------------------------------------------------------------------- 439 */ 440 441void 442TkSelPropProc( 443 register XEvent *eventPtr) /* X PropertyChange event. */ 444{ 445} 446 447/* 448 * Local Variables: 449 * mode: c 450 * c-basic-offset: 4 451 * fill-column: 78 452 * End: 453 */ 454