1/* 2 * tkMacOSXClipboard.c -- 3 * 4 * This file manages the clipboard for the Tk toolkit. 5 * 6 * Copyright (c) 1995-1997 Sun Microsystems, Inc. 7 * Copyright 2001-2009, Apple Inc. 8 * Copyright (c) 2006-2009 Daniel A. Steffen <das@users.sourceforge.net> 9 * 10 * See the file "license.terms" for information on usage and redistribution 11 * of this file, and for a DISCLAIMER OF ALL WARRANTIES. 12 * 13 * RCS: @(#) $Id$ 14 */ 15 16#include "tkMacOSXPrivate.h" 17#include "tkSelect.h" 18 19static NSInteger changeCount = -1; 20static Tk_Window clipboardOwner = NULL; 21 22#pragma mark TKApplication(TKClipboard) 23 24@implementation TKApplication(TKClipboard) 25- (void)tkProvidePasteboard:(TkDisplay *)dispPtr 26 pasteboard:(NSPasteboard *)sender provideDataForType:(NSString *)type { 27 NSMutableString *string = [NSMutableString new]; 28 29 if (dispPtr && dispPtr->clipboardActive && 30 [type isEqualToString:NSStringPboardType]) { 31 for (TkClipboardTarget *targetPtr = dispPtr->clipTargetPtr; targetPtr; 32 targetPtr = targetPtr->nextPtr) { 33 if (targetPtr->type == XA_STRING || 34 targetPtr->type == dispPtr->utf8Atom) { 35 for (TkClipboardBuffer *cbPtr = targetPtr->firstBufferPtr; 36 cbPtr; cbPtr = cbPtr->nextPtr) { 37 NSString *s = [[NSString alloc] initWithBytesNoCopy: 38 cbPtr->buffer length:cbPtr->length 39 encoding:NSUTF8StringEncoding freeWhenDone:NO]; 40 [string appendString:s]; 41 [s release]; 42 } 43 break; 44 } 45 } 46 } 47 [sender setString:string forType:type]; 48 [string release]; 49} 50- (void)tkProvidePasteboard:(TkDisplay *)dispPtr { 51 if (dispPtr && dispPtr->clipboardActive) { 52 [self tkProvidePasteboard:dispPtr 53 pasteboard:[NSPasteboard generalPasteboard] 54 provideDataForType:NSStringPboardType]; 55 } 56} 57- (void)pasteboard:(NSPasteboard *)sender provideDataForType:(NSString *)type { 58 [self tkProvidePasteboard:TkGetDisplayList() pasteboard:sender 59 provideDataForType:type]; 60} 61- (void)tkCheckPasteboard { 62 if (clipboardOwner && [[NSPasteboard generalPasteboard] changeCount] != 63 changeCount) { 64 TkDisplay *dispPtr = TkGetDisplayList(); 65 66 if (dispPtr) { 67 XEvent event; 68 69 event.xany.type = SelectionClear; 70 event.xany.serial = NextRequest(Tk_Display(clipboardOwner)); 71 event.xany.send_event = False; 72 event.xany.window = Tk_WindowId(clipboardOwner); 73 event.xany.display = Tk_Display(clipboardOwner); 74 event.xselectionclear.selection = dispPtr->clipboardAtom; 75 Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); 76 } 77 clipboardOwner = NULL; 78 } 79} 80@end 81 82#pragma mark - 83 84/* 85 *---------------------------------------------------------------------- 86 * 87 * TkSelGetSelection -- 88 * 89 * Retrieve the specified selection from another process. For now, only 90 * fetching XA_STRING from CLIPBOARD is supported. Eventually other types 91 * should be allowed. 92 * 93 * Results: 94 * The return value is a standard Tcl return value. If an error occurs 95 * (such as no selection exists) then an error message is left in the 96 * interp's result. 97 * 98 * Side effects: 99 * None. 100 * 101 *---------------------------------------------------------------------- 102 */ 103 104int 105TkSelGetSelection( 106 Tcl_Interp *interp, /* Interpreter to use for reporting errors. */ 107 Tk_Window tkwin, /* Window on whose behalf to retrieve the 108 * selection (determines display from which to 109 * retrieve). */ 110 Atom selection, /* Selection to retrieve. */ 111 Atom target, /* Desired form in which selection is to be 112 * returned. */ 113 Tk_GetSelProc *proc, /* Procedure to call to process the selection, 114 * once it has been retrieved. */ 115 ClientData clientData) /* Arbitrary value to pass to proc. */ 116{ 117 int result = TCL_ERROR; 118 TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr; 119 120 if (dispPtr && selection == dispPtr->clipboardAtom && (target == XA_STRING 121 || target == dispPtr->utf8Atom)) { 122 NSString *string = nil; 123 NSPasteboard *pb = [NSPasteboard generalPasteboard]; 124 NSString *type = [pb availableTypeFromArray:[NSArray arrayWithObject: 125 NSStringPboardType]]; 126 127 if (type) { 128 string = [pb stringForType:type]; 129 } 130 result = proc(clientData, interp, string ? (char*)[string UTF8String] 131 : ""); 132 } else { 133 Tcl_AppendResult(interp, Tk_GetAtomName(tkwin, selection), 134 " selection doesn't exist or form \"", 135 Tk_GetAtomName(tkwin, target), "\" not defined", NULL); 136 } 137 return result; 138} 139 140/* 141 *---------------------------------------------------------------------- 142 * 143 * XSetSelectionOwner -- 144 * 145 * This function claims ownership of the specified selection. If the 146 * selection is CLIPBOARD, then we empty the system clipboard. 147 * 148 * Results: 149 * None. 150 * 151 * Side effects: 152 * None. 153 * 154 *---------------------------------------------------------------------- 155 */ 156 157void 158XSetSelectionOwner( 159 Display *display, /* X Display. */ 160 Atom selection, /* What selection to own. */ 161 Window owner, /* Window to be the owner. */ 162 Time time) /* The current time? */ 163{ 164 TkDisplay *dispPtr = TkGetDisplayList(); 165 166 if (dispPtr && selection == dispPtr->clipboardAtom) { 167 clipboardOwner = owner ? Tk_IdToWindow(display, owner) : NULL; 168 if (!dispPtr->clipboardActive) { 169 NSPasteboard *pb = [NSPasteboard generalPasteboard]; 170 changeCount = [pb declareTypes:[NSArray array] owner:NSApp]; 171 } 172 } 173} 174 175/* 176 *---------------------------------------------------------------------- 177 * 178 * TkMacOSXSelDeadWindow -- 179 * 180 * This function is invoked just before a TkWindow is deleted. It 181 * performs selection-related cleanup. 182 * 183 * Results: 184 * None. 185 * 186 * Side effects: 187 * clipboardOwner is cleared. 188 * 189 *---------------------------------------------------------------------- 190 */ 191 192void 193TkMacOSXSelDeadWindow( 194 TkWindow *winPtr) 195{ 196 if (winPtr && winPtr == (TkWindow *)clipboardOwner) { 197 clipboardOwner = NULL; 198 } 199} 200 201/* 202 *---------------------------------------------------------------------- 203 * 204 * TkSelUpdateClipboard -- 205 * 206 * This function is called to force the clipboard to be updated after new 207 * data is added. 208 * 209 * Results: 210 * None. 211 * 212 * Side effects: 213 * None. 214 * 215 *---------------------------------------------------------------------- 216 */ 217 218void 219TkSelUpdateClipboard( 220 TkWindow *winPtr, /* Window associated with clipboard. */ 221 TkClipboardTarget *targetPtr) 222 /* Info about the content. */ 223{ 224 NSPasteboard *pb = [NSPasteboard generalPasteboard]; 225 changeCount = [pb addTypes:[NSArray arrayWithObject:NSStringPboardType] 226 owner:NSApp]; 227} 228 229/* 230 *-------------------------------------------------------------- 231 * 232 * TkSelEventProc -- 233 * 234 * This procedure is invoked whenever a selection-related event occurs. 235 * 236 * Results: 237 * None. 238 * 239 * Side effects: 240 * Lots: depends on the type of event. 241 * 242 *-------------------------------------------------------------- 243 */ 244 245void 246TkSelEventProc( 247 Tk_Window tkwin, /* Window for which event was targeted. */ 248 register XEvent *eventPtr) /* X event: either SelectionClear, 249 * SelectionRequest, or SelectionNotify. */ 250{ 251 if (eventPtr->type == SelectionClear) { 252 clipboardOwner = NULL; 253 TkSelClearSelection(tkwin, eventPtr); 254 } 255} 256 257/* 258 *---------------------------------------------------------------------- 259 * 260 * TkSelPropProc -- 261 * 262 * This procedure is invoked when property-change events occur on windows 263 * not known to the toolkit. This is a stub function under Windows. 264 * 265 * Results: 266 * None. 267 * 268 * Side effects: 269 * None. 270 * 271 *---------------------------------------------------------------------- 272 */ 273 274void 275TkSelPropProc( 276 register XEvent *eventPtr) /* X PropertyChange event. */ 277{ 278} 279 280/* 281 *---------------------------------------------------------------------- 282 * 283 * TkSuspendClipboard -- 284 * 285 * Handle clipboard conversion as required by the suppend event. 286 * 287 * Results: 288 * None. 289 * 290 * Side effects: 291 * The local scrap is moved to the global scrap. 292 * 293 *---------------------------------------------------------------------- 294 */ 295 296void 297TkSuspendClipboard(void) 298{ 299 changeCount = [[NSPasteboard generalPasteboard] changeCount]; 300} 301 302/* 303 * Local Variables: 304 * mode: c 305 * c-basic-offset: 4 306 * fill-column: 79 307 * coding: utf-8 308 * End: 309 */ 310