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