Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.desktop/unix/classes/sun/awt/X11/XClipboard.java
41159 views
1
/*
2
* Copyright (c) 2003, 2021, 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
@SuppressWarnings("removal")
133
private static int getPollInterval() {
134
synchronized (XClipboard.classLock) {
135
if (pollInterval <= 0) {
136
pollInterval = AccessController.doPrivileged(
137
new GetIntegerAction("awt.datatransfer.clipboard.poll.interval",
138
defaultPollInterval));
139
if (pollInterval <= 0) {
140
pollInterval = defaultPollInterval;
141
}
142
}
143
return pollInterval;
144
}
145
}
146
147
private XAtom getTargetsPropertyAtom() {
148
if (null == targetsPropertyAtom) {
149
targetsPropertyAtom =
150
XAtom.get("XAWT_TARGETS_OF_SELECTION:" + selection.getSelectionAtom().getName());
151
}
152
return targetsPropertyAtom;
153
}
154
155
protected void registerClipboardViewerChecked() {
156
// for XConvertSelection() to be called for the first time in getTargetsDelayed()
157
isSelectionNotifyProcessed = true;
158
159
boolean mustSchedule = false;
160
XToolkit.awtLock();
161
try {
162
synchronized (XClipboard.classLock) {
163
if (targetsAtom2Clipboard == null) {
164
targetsAtom2Clipboard = new HashMap<Long, XClipboard>(2);
165
}
166
mustSchedule = targetsAtom2Clipboard.isEmpty();
167
targetsAtom2Clipboard.put(getTargetsPropertyAtom().getAtom(), this);
168
if (mustSchedule) {
169
XToolkit.addEventDispatcher(XWindow.getXAWTRootWindow().getWindow(),
170
new SelectionNotifyHandler());
171
}
172
}
173
if (mustSchedule) {
174
XToolkit.schedule(new CheckChangeTimerTask(), XClipboard.getPollInterval());
175
}
176
} finally {
177
XToolkit.awtUnlock();
178
}
179
}
180
181
private static class CheckChangeTimerTask implements Runnable {
182
public void run() {
183
for (XClipboard clpbrd : targetsAtom2Clipboard.values()) {
184
clpbrd.getTargetsDelayed();
185
}
186
synchronized (XClipboard.classLock) {
187
if (targetsAtom2Clipboard != null && !targetsAtom2Clipboard.isEmpty()) {
188
// The viewer is still registered, schedule next poll.
189
XToolkit.schedule(this, XClipboard.getPollInterval());
190
}
191
}
192
}
193
}
194
195
private static class SelectionNotifyHandler implements XEventDispatcher {
196
public void dispatchEvent(XEvent ev) {
197
if (ev.get_type() == XConstants.SelectionNotify) {
198
final XSelectionEvent xse = ev.get_xselection();
199
XClipboard clipboard = null;
200
synchronized (XClipboard.classLock) {
201
if (targetsAtom2Clipboard != null && targetsAtom2Clipboard.isEmpty()) {
202
// The viewer was unregistered, remove the dispatcher.
203
XToolkit.removeEventDispatcher(XWindow.getXAWTRootWindow().getWindow(), this);
204
return;
205
}
206
final long propertyAtom = xse.get_property();
207
clipboard = targetsAtom2Clipboard.get(propertyAtom);
208
}
209
if (null != clipboard) {
210
clipboard.checkChange(xse);
211
}
212
}
213
}
214
}
215
216
protected void unregisterClipboardViewerChecked() {
217
isSelectionNotifyProcessed = false;
218
synchronized (XClipboard.classLock) {
219
targetsAtom2Clipboard.remove(getTargetsPropertyAtom().getAtom());
220
}
221
}
222
223
// checkChange() will be called on SelectionNotify
224
private void getTargetsDelayed() {
225
XToolkit.awtLock();
226
try {
227
long curTime = System.currentTimeMillis();
228
if (isSelectionNotifyProcessed || curTime >= (convertSelectionTime + UNIXToolkit.getDatatransferTimeout()))
229
{
230
convertSelectionTime = curTime;
231
XlibWrapper.XConvertSelection(XToolkit.getDisplay(),
232
selection.getSelectionAtom().getAtom(),
233
XDataTransferer.TARGETS_ATOM.getAtom(),
234
getTargetsPropertyAtom().getAtom(),
235
XWindow.getXAWTRootWindow().getWindow(),
236
XConstants.CurrentTime);
237
isSelectionNotifyProcessed = false;
238
}
239
} finally {
240
XToolkit.awtUnlock();
241
}
242
}
243
244
/*
245
* Tracks changes of available formats.
246
* NOTE: This method may be called by privileged threads.
247
* DO NOT INVOKE CLIENT CODE ON THIS THREAD!
248
*/
249
private void checkChange(XSelectionEvent xse) {
250
final long propertyAtom = xse.get_property();
251
if (propertyAtom != getTargetsPropertyAtom().getAtom()) {
252
// wrong atom
253
return;
254
}
255
256
final XAtom selectionAtom = XAtom.get(xse.get_selection());
257
final XSelection changedSelection = XSelection.getSelection(selectionAtom);
258
259
if (null == changedSelection || changedSelection != selection) {
260
// unknown selection - do nothing
261
return;
262
}
263
264
isSelectionNotifyProcessed = true;
265
266
if (selection.isOwner()) {
267
// selection is owner - do not need formats
268
return;
269
}
270
271
long[] formats = null;
272
273
if (propertyAtom == XConstants.None) {
274
// We treat None property atom as "empty selection".
275
formats = new long[0];
276
} else {
277
WindowPropertyGetter targetsGetter =
278
new WindowPropertyGetter(XWindow.getXAWTRootWindow().getWindow(),
279
XAtom.get(propertyAtom), 0,
280
XSelection.MAX_LENGTH, true,
281
XConstants.AnyPropertyType);
282
try {
283
targetsGetter.execute();
284
formats = XSelection.getFormats(targetsGetter);
285
} finally {
286
targetsGetter.dispose();
287
}
288
}
289
290
XToolkit.awtUnlock();
291
try {
292
checkChange(formats);
293
} finally {
294
XToolkit.awtLock();
295
}
296
}
297
}
298
299