OSDN Git Service

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