Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/solaris/classes/sun/awt/X11/XClipboard.java
32288 views
/*1* Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.awt.X11;2627import java.awt.datatransfer.Transferable;28import java.awt.datatransfer.DataFlavor;29import java.util.SortedMap;30import java.io.IOException;31import java.security.AccessController;32import java.util.HashMap;33import java.util.Map;34import sun.awt.UNIXToolkit;35import sun.awt.datatransfer.DataTransferer;36import sun.awt.datatransfer.SunClipboard;37import sun.awt.datatransfer.ClipboardTransferable;38import sun.security.action.GetIntegerAction;3940/**41* A class which interfaces with the X11 selection service in order to support42* data transfer via Clipboard operations.43*/44public final class XClipboard extends SunClipboard implements OwnershipListener45{46private final XSelection selection;47// Time of calling XConvertSelection().48private long convertSelectionTime;49// The flag used not to call XConvertSelection() if the previous SelectionNotify50// has not been processed by checkChange().51private volatile boolean isSelectionNotifyProcessed;52// The property in which the owner should place requested targets53// when tracking changes of available data flavors (practically targets).54private volatile XAtom targetsPropertyAtom;5556private static final Object classLock = new Object();5758private static final int defaultPollInterval = 200;5960private static int pollInterval;6162private static Map<Long, XClipboard> targetsAtom2Clipboard;6364/**65* Creates a system clipboard object.66*/67public XClipboard(String name, String selectionName) {68super(name);69selection = new XSelection(XAtom.get(selectionName));70selection.registerOwershipListener(this);71}7273/*74* NOTE: This method may be called by privileged threads.75* DO NOT INVOKE CLIENT CODE ON THIS THREAD!76*/77public void ownershipChanged(final boolean isOwner) {78if (isOwner) {79checkChangeHere(contents);80} else {81lostOwnershipImpl();82}83}8485protected synchronized void setContentsNative(Transferable contents) {86SortedMap<Long,DataFlavor> formatMap =87DataTransferer.getInstance().getFormatsForTransferable88(contents, DataTransferer.adaptFlavorMap(getDefaultFlavorTable()));89long[] formats = DataTransferer.keysToLongArray(formatMap);9091if (!selection.setOwner(contents, formatMap, formats,92XToolkit.getCurrentServerTime())) {93this.owner = null;94this.contents = null;95}96}9798public long getID() {99return selection.getSelectionAtom().getAtom();100}101102@Override103public synchronized Transferable getContents(Object requestor) {104if (contents != null) {105return contents;106}107return new ClipboardTransferable(this);108}109110/* Caller is synchronized on this. */111protected void clearNativeContext() {112selection.reset();113}114115116protected long[] getClipboardFormats() {117return selection.getTargets(XToolkit.getCurrentServerTime());118}119120protected byte[] getClipboardData(long format) throws IOException {121return selection.getData(format, XToolkit.getCurrentServerTime());122}123124private void checkChangeHere(Transferable contents) {125if (areFlavorListenersRegistered()) {126checkChange(DataTransferer.getInstance().127getFormatsForTransferableAsArray(contents, getDefaultFlavorTable()));128}129}130131private static int getPollInterval() {132synchronized (XClipboard.classLock) {133if (pollInterval <= 0) {134pollInterval = AccessController.doPrivileged(135new GetIntegerAction("awt.datatransfer.clipboard.poll.interval",136defaultPollInterval));137if (pollInterval <= 0) {138pollInterval = defaultPollInterval;139}140}141return pollInterval;142}143}144145private XAtom getTargetsPropertyAtom() {146if (null == targetsPropertyAtom) {147targetsPropertyAtom =148XAtom.get("XAWT_TARGETS_OF_SELECTION:" + selection.getSelectionAtom().getName());149}150return targetsPropertyAtom;151}152153protected void registerClipboardViewerChecked() {154// for XConvertSelection() to be called for the first time in getTargetsDelayed()155isSelectionNotifyProcessed = true;156157boolean mustSchedule = false;158XToolkit.awtLock();159try {160synchronized (XClipboard.classLock) {161try {162Thread.sleep(70);163} catch (InterruptedException e) {164e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.165}166if (targetsAtom2Clipboard == null) {167targetsAtom2Clipboard = new HashMap<Long, XClipboard>(2);168}169mustSchedule = targetsAtom2Clipboard.isEmpty();170targetsAtom2Clipboard.put(getTargetsPropertyAtom().getAtom(), this);171if (mustSchedule) {172XToolkit.addEventDispatcher(XWindow.getXAWTRootWindow().getWindow(),173new SelectionNotifyHandler());174}175}176if (mustSchedule) {177XToolkit.schedule(new CheckChangeTimerTask(), XClipboard.getPollInterval());178}179} finally {180XToolkit.awtUnlock();181}182}183184private static class CheckChangeTimerTask implements Runnable {185public void run() {186for (XClipboard clpbrd : targetsAtom2Clipboard.values()) {187clpbrd.getTargetsDelayed();188}189synchronized (XClipboard.classLock) {190if (targetsAtom2Clipboard != null && !targetsAtom2Clipboard.isEmpty()) {191// The viewer is still registered, schedule next poll.192XToolkit.schedule(this, XClipboard.getPollInterval());193}194}195}196}197198private static class SelectionNotifyHandler implements XEventDispatcher {199public void dispatchEvent(XEvent ev) {200if (ev.get_type() == XConstants.SelectionNotify) {201final XSelectionEvent xse = ev.get_xselection();202XClipboard clipboard = null;203synchronized (XClipboard.classLock) {204if (targetsAtom2Clipboard != null && targetsAtom2Clipboard.isEmpty()) {205// The viewer was unregistered, remove the dispatcher.206XToolkit.removeEventDispatcher(XWindow.getXAWTRootWindow().getWindow(), this);207return;208}209final long propertyAtom = xse.get_property();210clipboard = targetsAtom2Clipboard.get(propertyAtom);211}212if (null != clipboard) {213clipboard.checkChange(xse);214}215}216}217}218219protected void unregisterClipboardViewerChecked() {220isSelectionNotifyProcessed = false;221synchronized (XClipboard.classLock) {222targetsAtom2Clipboard.remove(getTargetsPropertyAtom().getAtom());223}224}225226// checkChange() will be called on SelectionNotify227private void getTargetsDelayed() {228XToolkit.awtLock();229try {230long curTime = System.currentTimeMillis();231if (isSelectionNotifyProcessed || curTime >= (convertSelectionTime + UNIXToolkit.getDatatransferTimeout()))232{233convertSelectionTime = curTime;234XlibWrapper.XConvertSelection(XToolkit.getDisplay(),235selection.getSelectionAtom().getAtom(),236XDataTransferer.TARGETS_ATOM.getAtom(),237getTargetsPropertyAtom().getAtom(),238XWindow.getXAWTRootWindow().getWindow(),239XConstants.CurrentTime);240isSelectionNotifyProcessed = false;241}242} finally {243XToolkit.awtUnlock();244}245}246247/*248* Tracks changes of available formats.249* NOTE: This method may be called by privileged threads.250* DO NOT INVOKE CLIENT CODE ON THIS THREAD!251*/252private void checkChange(XSelectionEvent xse) {253final long propertyAtom = xse.get_property();254if (propertyAtom != getTargetsPropertyAtom().getAtom()) {255// wrong atom256return;257}258259final XAtom selectionAtom = XAtom.get(xse.get_selection());260final XSelection changedSelection = XSelection.getSelection(selectionAtom);261262if (null == changedSelection || changedSelection != selection) {263// unknown selection - do nothing264return;265}266267isSelectionNotifyProcessed = true;268269if (selection.isOwner()) {270// selection is owner - do not need formats271return;272}273274long[] formats = null;275276if (propertyAtom == XConstants.None) {277// We treat None property atom as "empty selection".278formats = new long[0];279} else {280WindowPropertyGetter targetsGetter =281new WindowPropertyGetter(XWindow.getXAWTRootWindow().getWindow(),282XAtom.get(propertyAtom), 0,283XSelection.MAX_LENGTH, true,284XConstants.AnyPropertyType);285try {286targetsGetter.execute();287formats = XSelection.getFormats(targetsGetter);288} finally {289targetsGetter.dispose();290}291}292293XToolkit.awtUnlock();294try {295checkChange(formats);296} finally {297XToolkit.awtLock();298}299}300}301302303