Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/solaris/classes/sun/awt/X11/XClipboard.java
32288 views
1
/*
2
* Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package sun.awt.X11;
27
28
import java.awt.datatransfer.Transferable;
29
import java.awt.datatransfer.DataFlavor;
30
import java.util.SortedMap;
31
import java.io.IOException;
32
import java.security.AccessController;
33
import java.util.HashMap;
34
import java.util.Map;
35
import sun.awt.UNIXToolkit;
36
import sun.awt.datatransfer.DataTransferer;
37
import sun.awt.datatransfer.SunClipboard;
38
import sun.awt.datatransfer.ClipboardTransferable;
39
import sun.security.action.GetIntegerAction;
40
41
/**
42
* A class which interfaces with the X11 selection service in order to support
43
* data transfer via Clipboard operations.
44
*/
45
public final class XClipboard extends SunClipboard implements OwnershipListener
46
{
47
private final XSelection selection;
48
// Time of calling XConvertSelection().
49
private long convertSelectionTime;
50
// The flag used not to call XConvertSelection() if the previous SelectionNotify
51
// has not been processed by checkChange().
52
private volatile boolean isSelectionNotifyProcessed;
53
// The property in which the owner should place requested targets
54
// when tracking changes of available data flavors (practically targets).
55
private volatile XAtom targetsPropertyAtom;
56
57
private static final Object classLock = new Object();
58
59
private static final int defaultPollInterval = 200;
60
61
private static int pollInterval;
62
63
private static Map<Long, XClipboard> targetsAtom2Clipboard;
64
65
/**
66
* Creates a system clipboard object.
67
*/
68
public XClipboard(String name, String selectionName) {
69
super(name);
70
selection = new XSelection(XAtom.get(selectionName));
71
selection.registerOwershipListener(this);
72
}
73
74
/*
75
* NOTE: This method may be called by privileged threads.
76
* DO NOT INVOKE CLIENT CODE ON THIS THREAD!
77
*/
78
public void ownershipChanged(final boolean isOwner) {
79
if (isOwner) {
80
checkChangeHere(contents);
81
} else {
82
lostOwnershipImpl();
83
}
84
}
85
86
protected synchronized void setContentsNative(Transferable contents) {
87
SortedMap<Long,DataFlavor> formatMap =
88
DataTransferer.getInstance().getFormatsForTransferable
89
(contents, DataTransferer.adaptFlavorMap(getDefaultFlavorTable()));
90
long[] formats = DataTransferer.keysToLongArray(formatMap);
91
92
if (!selection.setOwner(contents, formatMap, formats,
93
XToolkit.getCurrentServerTime())) {
94
this.owner = null;
95
this.contents = null;
96
}
97
}
98
99
public long getID() {
100
return selection.getSelectionAtom().getAtom();
101
}
102
103
@Override
104
public synchronized Transferable getContents(Object requestor) {
105
if (contents != null) {
106
return contents;
107
}
108
return new ClipboardTransferable(this);
109
}
110
111
/* Caller is synchronized on this. */
112
protected void clearNativeContext() {
113
selection.reset();
114
}
115
116
117
protected long[] getClipboardFormats() {
118
return selection.getTargets(XToolkit.getCurrentServerTime());
119
}
120
121
protected byte[] getClipboardData(long format) throws IOException {
122
return selection.getData(format, XToolkit.getCurrentServerTime());
123
}
124
125
private void checkChangeHere(Transferable contents) {
126
if (areFlavorListenersRegistered()) {
127
checkChange(DataTransferer.getInstance().
128
getFormatsForTransferableAsArray(contents, getDefaultFlavorTable()));
129
}
130
}
131
132
private static int getPollInterval() {
133
synchronized (XClipboard.classLock) {
134
if (pollInterval <= 0) {
135
pollInterval = AccessController.doPrivileged(
136
new GetIntegerAction("awt.datatransfer.clipboard.poll.interval",
137
defaultPollInterval));
138
if (pollInterval <= 0) {
139
pollInterval = defaultPollInterval;
140
}
141
}
142
return pollInterval;
143
}
144
}
145
146
private XAtom getTargetsPropertyAtom() {
147
if (null == targetsPropertyAtom) {
148
targetsPropertyAtom =
149
XAtom.get("XAWT_TARGETS_OF_SELECTION:" + selection.getSelectionAtom().getName());
150
}
151
return targetsPropertyAtom;
152
}
153
154
protected void registerClipboardViewerChecked() {
155
// for XConvertSelection() to be called for the first time in getTargetsDelayed()
156
isSelectionNotifyProcessed = true;
157
158
boolean mustSchedule = false;
159
XToolkit.awtLock();
160
try {
161
synchronized (XClipboard.classLock) {
162
try {
163
Thread.sleep(70);
164
} catch (InterruptedException e) {
165
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
166
}
167
if (targetsAtom2Clipboard == null) {
168
targetsAtom2Clipboard = new HashMap<Long, XClipboard>(2);
169
}
170
mustSchedule = targetsAtom2Clipboard.isEmpty();
171
targetsAtom2Clipboard.put(getTargetsPropertyAtom().getAtom(), this);
172
if (mustSchedule) {
173
XToolkit.addEventDispatcher(XWindow.getXAWTRootWindow().getWindow(),
174
new SelectionNotifyHandler());
175
}
176
}
177
if (mustSchedule) {
178
XToolkit.schedule(new CheckChangeTimerTask(), XClipboard.getPollInterval());
179
}
180
} finally {
181
XToolkit.awtUnlock();
182
}
183
}
184
185
private static class CheckChangeTimerTask implements Runnable {
186
public void run() {
187
for (XClipboard clpbrd : targetsAtom2Clipboard.values()) {
188
clpbrd.getTargetsDelayed();
189
}
190
synchronized (XClipboard.classLock) {
191
if (targetsAtom2Clipboard != null && !targetsAtom2Clipboard.isEmpty()) {
192
// The viewer is still registered, schedule next poll.
193
XToolkit.schedule(this, XClipboard.getPollInterval());
194
}
195
}
196
}
197
}
198
199
private static class SelectionNotifyHandler implements XEventDispatcher {
200
public void dispatchEvent(XEvent ev) {
201
if (ev.get_type() == XConstants.SelectionNotify) {
202
final XSelectionEvent xse = ev.get_xselection();
203
XClipboard clipboard = null;
204
synchronized (XClipboard.classLock) {
205
if (targetsAtom2Clipboard != null && targetsAtom2Clipboard.isEmpty()) {
206
// The viewer was unregistered, remove the dispatcher.
207
XToolkit.removeEventDispatcher(XWindow.getXAWTRootWindow().getWindow(), this);
208
return;
209
}
210
final long propertyAtom = xse.get_property();
211
clipboard = targetsAtom2Clipboard.get(propertyAtom);
212
}
213
if (null != clipboard) {
214
clipboard.checkChange(xse);
215
}
216
}
217
}
218
}
219
220
protected void unregisterClipboardViewerChecked() {
221
isSelectionNotifyProcessed = false;
222
synchronized (XClipboard.classLock) {
223
targetsAtom2Clipboard.remove(getTargetsPropertyAtom().getAtom());
224
}
225
}
226
227
// checkChange() will be called on SelectionNotify
228
private void getTargetsDelayed() {
229
XToolkit.awtLock();
230
try {
231
long curTime = System.currentTimeMillis();
232
if (isSelectionNotifyProcessed || curTime >= (convertSelectionTime + UNIXToolkit.getDatatransferTimeout()))
233
{
234
convertSelectionTime = curTime;
235
XlibWrapper.XConvertSelection(XToolkit.getDisplay(),
236
selection.getSelectionAtom().getAtom(),
237
XDataTransferer.TARGETS_ATOM.getAtom(),
238
getTargetsPropertyAtom().getAtom(),
239
XWindow.getXAWTRootWindow().getWindow(),
240
XConstants.CurrentTime);
241
isSelectionNotifyProcessed = false;
242
}
243
} finally {
244
XToolkit.awtUnlock();
245
}
246
}
247
248
/*
249
* Tracks changes of available formats.
250
* NOTE: This method may be called by privileged threads.
251
* DO NOT INVOKE CLIENT CODE ON THIS THREAD!
252
*/
253
private void checkChange(XSelectionEvent xse) {
254
final long propertyAtom = xse.get_property();
255
if (propertyAtom != getTargetsPropertyAtom().getAtom()) {
256
// wrong atom
257
return;
258
}
259
260
final XAtom selectionAtom = XAtom.get(xse.get_selection());
261
final XSelection changedSelection = XSelection.getSelection(selectionAtom);
262
263
if (null == changedSelection || changedSelection != selection) {
264
// unknown selection - do nothing
265
return;
266
}
267
268
isSelectionNotifyProcessed = true;
269
270
if (selection.isOwner()) {
271
// selection is owner - do not need formats
272
return;
273
}
274
275
long[] formats = null;
276
277
if (propertyAtom == XConstants.None) {
278
// We treat None property atom as "empty selection".
279
formats = new long[0];
280
} else {
281
WindowPropertyGetter targetsGetter =
282
new WindowPropertyGetter(XWindow.getXAWTRootWindow().getWindow(),
283
XAtom.get(propertyAtom), 0,
284
XSelection.MAX_LENGTH, true,
285
XConstants.AnyPropertyType);
286
try {
287
targetsGetter.execute();
288
formats = XSelection.getFormats(targetsGetter);
289
} finally {
290
targetsGetter.dispose();
291
}
292
}
293
294
XToolkit.awtUnlock();
295
try {
296
checkChange(formats);
297
} finally {
298
XToolkit.awtLock();
299
}
300
}
301
}
302
303