/* * tkMacOSXClipboard.c -- * * This file manages the clipboard for the Tk toolkit. * * Copyright (c) 1995-1997 Sun Microsystems, Inc. * Copyright 2001, Apple Computer, Inc. * Copyright (c) 2006-2007 Daniel A. Steffen * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * RCS: @(#) $Id: tkMacOSXClipboard.c,v 1.1.1.2 2009/03/24 10:20:28 duncan Exp $ */ #include "tkMacOSXPrivate.h" #include "tkSelect.h" /* *---------------------------------------------------------------------- * * TkSelGetSelection -- * * Retrieve the specified selection from another process. For * now, only fetching XA_STRING from CLIPBOARD is supported. * Eventually other types should be allowed. * * Results: * The return value is a standard Tcl return value. * If an error occurs (such as no selection exists) * then an error message is left in the interp's result. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TkSelGetSelection( Tcl_Interp *interp, /* Interpreter to use for reporting errors. */ Tk_Window tkwin, /* Window on whose behalf to retrieve the * selection (determines display from which to * retrieve). */ Atom selection, /* Selection to retrieve. */ Atom target, /* Desired form in which selection is to be * returned. */ Tk_GetSelProc *proc, /* Procedure to call to process the selection, * once it has been retrieved. */ ClientData clientData) /* Arbitrary value to pass to proc. */ { int result; OSStatus err; long length; ScrapRef scrapRef; char *buf; if ((selection == Tk_InternAtom(tkwin, "CLIPBOARD")) && (target == XA_STRING)) { /* * Get the scrap from the Macintosh global clipboard. */ err = ChkErr(GetCurrentScrap, &scrapRef); if (err != noErr) { Tcl_AppendResult(interp, Tk_GetAtomName(tkwin, selection), " GetCurrentScrap failed.", NULL); return TCL_ERROR; } /* * Try UNICODE first */ err = ChkErr(GetScrapFlavorSize, scrapRef, kScrapFlavorTypeUnicode, &length); if (err == noErr && length > 0) { Tcl_DString ds; char *data; buf = (char *) ckalloc(length + 2); buf[length] = 0; buf[length+1] = 0; /* 2-byte unicode null */ err = ChkErr(GetScrapFlavorData, scrapRef, kScrapFlavorTypeUnicode, &length, buf); if (err == noErr) { Tcl_DStringInit(&ds); Tcl_UniCharToUtfDString((Tcl_UniChar *)buf, Tcl_UniCharLen((Tcl_UniChar *)buf), &ds); for (data = Tcl_DStringValue(&ds); *data != '\0'; data++) { if (*data == '\r') { *data = '\n'; } } result = (*proc)(clientData, interp, Tcl_DStringValue(&ds)); Tcl_DStringFree(&ds); ckfree(buf); return result; } } err = ChkErr(GetScrapFlavorSize, scrapRef, 'TEXT', &length); if (err != noErr) { Tcl_AppendResult(interp, Tk_GetAtomName(tkwin, selection), " GetScrapFlavorSize failed.", NULL); return TCL_ERROR; } if (length > 0) { Tcl_DString encodedText; char *data; buf = (char *) ckalloc(length + 1); buf[length] = 0; err = ChkErr(GetScrapFlavorData, scrapRef, 'TEXT', &length, buf); if (err != noErr) { Tcl_AppendResult(interp, Tk_GetAtomName(tkwin, selection), " GetScrapFlavorData failed.", NULL); return TCL_ERROR; } /* * Tcl expects '\n' not '\r' as the line break character. */ for (data = buf; *data != '\0'; data++) { if (*data == '\r') { *data = '\n'; } } Tcl_ExternalToUtfDString(TkMacOSXCarbonEncoding, buf, length, &encodedText); result = (*proc)(clientData, interp, Tcl_DStringValue(&encodedText)); Tcl_DStringFree(&encodedText); ckfree(buf); return result; } } Tcl_AppendResult(interp, Tk_GetAtomName(tkwin, selection), " selection doesn't exist or form \"", Tk_GetAtomName(tkwin, target), "\" not defined", NULL); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TkSetSelectionOwner -- * * This function claims ownership of the specified selection. * If the selection is CLIPBOARD, then we empty the system * clipboard. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void XSetSelectionOwner( Display *display, /* X Display. */ Atom selection, /* What selection to own. */ Window owner, /* Window to be the owner. */ Time time) /* The current time? */ { Tk_Window tkwin; TkDisplay *dispPtr; /* * This is a gross hack because the Tk_InternAtom interface is broken. * It expects a Tk_Window, even though it only needs a Tk_Display. */ tkwin = (Tk_Window) TkGetMainInfoList()->winPtr; if (selection == Tk_InternAtom(tkwin, "CLIPBOARD")) { /* * Only claim and empty the clipboard if we aren't already the * owner of the clipboard. */ dispPtr = TkGetMainInfoList()->winPtr->dispPtr; if (dispPtr->clipboardActive) { return; } ClearCurrentScrap(); } } /* *---------------------------------------------------------------------- * * TkSelUpdateClipboard -- * * This function is called to force the clipboard to be updated * after new data is added. On the Mac we don't need to do * anything. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TkSelUpdateClipboard( TkWindow *winPtr, /* Window associated with clipboard. */ TkClipboardTarget *targetPtr) /* Info about the content. */ { } /* *-------------------------------------------------------------- * * TkSelEventProc -- * * This procedure is invoked whenever a selection-related * event occurs. * * Results: * None. * * Side effects: * Lots: depends on the type of event. * *-------------------------------------------------------------- */ void TkSelEventProc( Tk_Window tkwin, /* Window for which event was targeted. */ register XEvent *eventPtr) /* X event: either SelectionClear, * SelectionRequest, or SelectionNotify. */ { if (eventPtr->type == SelectionClear) { TkSelClearSelection(tkwin, eventPtr); } } /* *---------------------------------------------------------------------- * * TkSelPropProc -- * * This procedure is invoked when property-change events * occur on windows not known to the toolkit. This is a stub * function under Windows. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TkSelPropProc( register XEvent *eventPtr) /* X PropertyChange event. */ { } /* *---------------------------------------------------------------------- * * TkSuspendClipboard -- * * Handle clipboard conversion as required by the suppend event. * This function is also called on exit. * * Results: * None. * * Side effects: * The local scrap is moved to the global scrap. * *---------------------------------------------------------------------- */ void TkSuspendClipboard(void) { TkClipboardTarget *targetPtr; TkClipboardBuffer *cbPtr; TkDisplay *dispPtr; char *buffer, *p, *endPtr, *buffPtr; long length; ScrapRef scrapRef; dispPtr = TkGetDisplayList(); if ((dispPtr == NULL) || !dispPtr->clipboardActive) { return; } for (targetPtr = dispPtr->clipTargetPtr; targetPtr != NULL; targetPtr = targetPtr->nextPtr) { if (targetPtr->type == XA_STRING) { break; } } if (targetPtr != NULL) { Tcl_DString encodedText, unicodedText; length = 0; for (cbPtr = targetPtr->firstBufferPtr; cbPtr != NULL; cbPtr = cbPtr->nextPtr) { length += cbPtr->length; } buffer = ckalloc(length); buffPtr = buffer; for (cbPtr = targetPtr->firstBufferPtr; cbPtr != NULL; cbPtr = cbPtr->nextPtr) { for (p = cbPtr->buffer, endPtr = p + cbPtr->length; p < endPtr; p++) { if (*p == '\n') { *buffPtr++ = '\r'; } else { *buffPtr++ = *p; } } } ClearCurrentScrap(); GetCurrentScrap(&scrapRef); Tcl_UtfToExternalDString(TkMacOSXCarbonEncoding, buffer, length, &encodedText); PutScrapFlavor(scrapRef, 'TEXT', 0, Tcl_DStringLength(&encodedText), Tcl_DStringValue(&encodedText)); Tcl_DStringFree(&encodedText); /* * Also put unicode data on scrap. */ Tcl_DStringInit(&unicodedText); Tcl_UtfToUniCharDString(buffer, length, &unicodedText); PutScrapFlavor(scrapRef, kScrapFlavorTypeUnicode, 0, Tcl_DStringLength(&unicodedText), Tcl_DStringValue(&unicodedText)); Tcl_DStringFree(&unicodedText); ckfree(buffer); } /* * The system now owns the scrap. We tell Tk that it has * lost the selection so that it will look for it the next time * it needs it. (Window list NULL if quiting.) */ if (TkGetMainInfoList() != NULL) { Tk_ClearSelection((Tk_Window) TkGetMainInfoList()->winPtr, Tk_InternAtom((Tk_Window) TkGetMainInfoList()->winPtr, "CLIPBOARD")); } return; }