jdk/src/solaris/classes/sun/awt/X11/XClipboard.java
changeset 117 766ae458aaf1
parent 2 90ce3da70b43
child 439 3488710b02f8
equal deleted inserted replaced
116:9c43d9eb1029 117:766ae458aaf1
     1 /*
     1 /*
     2  * Copyright 2003-2007 Sun Microsystems, Inc.  All Rights Reserved.
     2  * Copyright 2003-2008 Sun Microsystems, Inc.  All Rights Reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     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
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Sun designates this
     7  * published by the Free Software Foundation.  Sun designates this
    24  */
    24  */
    25 
    25 
    26 package sun.awt.X11;
    26 package sun.awt.X11;
    27 
    27 
    28 import java.awt.datatransfer.Transferable;
    28 import java.awt.datatransfer.Transferable;
    29 
       
    30 import java.util.SortedMap;
    29 import java.util.SortedMap;
    31 import java.util.Set;
       
    32 import java.util.Iterator;
       
    33 import java.util.HashSet;
       
    34 
       
    35 import java.io.IOException;
    30 import java.io.IOException;
    36 
       
    37 import java.security.AccessController;
    31 import java.security.AccessController;
    38 
    32 import java.util.HashMap;
       
    33 import java.util.Map;
       
    34 import sun.awt.UNIXToolkit;
    39 import sun.awt.datatransfer.DataTransferer;
    35 import sun.awt.datatransfer.DataTransferer;
    40 import sun.awt.datatransfer.SunClipboard;
    36 import sun.awt.datatransfer.SunClipboard;
    41 import sun.awt.datatransfer.ClipboardTransferable;
    37 import sun.awt.datatransfer.ClipboardTransferable;
    42 
       
    43 import sun.security.action.GetIntegerAction;
    38 import sun.security.action.GetIntegerAction;
    44 
       
    45 
       
    46 
    39 
    47 /**
    40 /**
    48  * A class which interfaces with the X11 selection service in order to support
    41  * A class which interfaces with the X11 selection service in order to support
    49  * data transfer via Clipboard operations.
    42  * data transfer via Clipboard operations.
    50  */
    43  */
    51 public class XClipboard extends SunClipboard implements Runnable {
    44 public final class XClipboard extends SunClipboard implements OwnershipListener
       
    45 {
    52     private final XSelection selection;
    46     private final XSelection selection;
       
    47     // Time of calling XConvertSelection().
       
    48     private long convertSelectionTime;
       
    49     // The flag used not to call XConvertSelection() if the previous SelectionNotify
       
    50     // has not been processed by checkChange().
       
    51     private volatile boolean isSelectionNotifyProcessed;
       
    52     // The property in which the owner should place requested targets
       
    53     // when tracking changes of available data flavors (practically targets).
       
    54     private volatile XAtom targetsPropertyAtom;
    53 
    55 
    54     private static final Object classLock = new Object();
    56     private static final Object classLock = new Object();
    55 
    57 
    56     private static final int defaultPollInterval = 200;
    58     private static final int defaultPollInterval = 200;
    57 
    59 
    58     private static int pollInterval;
    60     private static int pollInterval;
    59 
    61 
    60     private static Set listenedClipboards;
    62     private static Map<Long, XClipboard> targetsAtom2Clipboard;
    61 
       
    62 
    63 
    63     /**
    64     /**
    64      * Creates a system clipboard object.
    65      * Creates a system clipboard object.
    65      */
    66      */
    66     public XClipboard(String name, String selectionName) {
    67     public XClipboard(String name, String selectionName) {
    67         super(name);
    68         super(name);
    68         selection = new XSelection(XAtom.get(selectionName), this);
    69         selection = new XSelection(XAtom.get(selectionName));
    69     }
    70         selection.registerOwershipListener(this);
    70 
    71     }
    71     /**
    72 
    72      * The action to be run when we lose ownership
    73     /*
    73      * NOTE: This method may be called by privileged threads.
    74      * NOTE: This method may be called by privileged threads.
    74      *       DO NOT INVOKE CLIENT CODE ON THIS THREAD!
    75      *       DO NOT INVOKE CLIENT CODE ON THIS THREAD!
    75      */
    76      */
    76     public void run() {
    77     public void ownershipChanged(final boolean isOwner) {
    77         lostOwnershipImpl();
    78         if (isOwner) {
       
    79             checkChangeHere(contents);
       
    80         } else {
       
    81             lostOwnershipImpl();
       
    82         }
    78     }
    83     }
    79 
    84 
    80     protected synchronized void setContentsNative(Transferable contents) {
    85     protected synchronized void setContentsNative(Transferable contents) {
    81         SortedMap formatMap = DataTransferer.getInstance().getFormatsForTransferable
    86         SortedMap formatMap = DataTransferer.getInstance().getFormatsForTransferable
    82                 (contents, DataTransferer.adaptFlavorMap(flavorMap));
    87                 (contents, DataTransferer.adaptFlavorMap(flavorMap));
    83         long[] formats =
    88         long[] formats = DataTransferer.keysToLongArray(formatMap);
    84             DataTransferer.getInstance().keysToLongArray(formatMap);
       
    85 
    89 
    86         if (!selection.setOwner(contents, formatMap, formats,
    90         if (!selection.setOwner(contents, formatMap, formats,
    87                                 XToolkit.getCurrentServerTime())) {
    91                                 XToolkit.getCurrentServerTime())) {
    88             this.owner = null;
    92             this.owner = null;
    89             this.contents = null;
    93             this.contents = null;
    92 
    96 
    93     public long getID() {
    97     public long getID() {
    94         return selection.getSelectionAtom().getAtom();
    98         return selection.getSelectionAtom().getAtom();
    95     }
    99     }
    96 
   100 
       
   101     @Override
    97     public synchronized Transferable getContents(Object requestor) {
   102     public synchronized Transferable getContents(Object requestor) {
    98         if (contents != null) {
   103         if (contents != null) {
    99             return contents;
   104             return contents;
   100         }
   105         }
   101         return new ClipboardTransferable(this);
   106         return new ClipboardTransferable(this);
   113 
   118 
   114     protected byte[] getClipboardData(long format) throws IOException {
   119     protected byte[] getClipboardData(long format) throws IOException {
   115         return selection.getData(format, XToolkit.getCurrentServerTime());
   120         return selection.getData(format, XToolkit.getCurrentServerTime());
   116     }
   121     }
   117 
   122 
   118     // Called on the toolkit thread under awtLock.
   123     private void checkChangeHere(Transferable contents) {
   119     public void checkChange(long[] formats) {
       
   120         if (!selection.isOwner()) {
       
   121             super.checkChange(formats);
       
   122         }
       
   123     }
       
   124 
       
   125     void checkChangeHere(Transferable contents) {
       
   126         if (areFlavorListenersRegistered()) {
   124         if (areFlavorListenersRegistered()) {
   127             super.checkChange(DataTransferer.getInstance().
   125             checkChange(DataTransferer.getInstance().
   128                         getFormatsForTransferableAsArray(contents, flavorMap));
   126                         getFormatsForTransferableAsArray(contents, flavorMap));
   129         }
   127         }
   130     }
   128     }
   131 
   129 
       
   130     private static int getPollInterval() {
       
   131         synchronized (XClipboard.classLock) {
       
   132             if (pollInterval <= 0) {
       
   133                 pollInterval = AccessController.doPrivileged(
       
   134                         new GetIntegerAction("awt.datatransfer.clipboard.poll.interval",
       
   135                                              defaultPollInterval));
       
   136                 if (pollInterval <= 0) {
       
   137                     pollInterval = defaultPollInterval;
       
   138                 }
       
   139             }
       
   140             return pollInterval;
       
   141         }
       
   142     }
       
   143 
       
   144     private XAtom getTargetsPropertyAtom() {
       
   145         if (null == targetsPropertyAtom) {
       
   146             targetsPropertyAtom =
       
   147                     XAtom.get("XAWT_TARGETS_OF_SELECTION:" + selection.getSelectionAtom().getName());
       
   148         }
       
   149         return targetsPropertyAtom;
       
   150     }
       
   151 
   132     protected void registerClipboardViewerChecked() {
   152     protected void registerClipboardViewerChecked() {
   133         if (pollInterval <= 0) {
   153         // for XConvertSelection() to be called for the first time in getTargetsDelayed()
   134             pollInterval = ((Integer)AccessController.doPrivileged(
   154         isSelectionNotifyProcessed = true;
   135                     new GetIntegerAction("awt.datatransfer.clipboard.poll.interval",
   155 
   136                                          defaultPollInterval))).intValue();
       
   137             if (pollInterval <= 0) {
       
   138                 pollInterval = defaultPollInterval;
       
   139             }
       
   140         }
       
   141         selection.initializeSelectionForTrackingChanges();
       
   142         boolean mustSchedule = false;
   156         boolean mustSchedule = false;
   143         synchronized (XClipboard.classLock) {
   157         synchronized (XClipboard.classLock) {
   144             if (listenedClipboards == null) {
   158             if (targetsAtom2Clipboard == null) {
   145                 listenedClipboards = new HashSet(2);
   159                 targetsAtom2Clipboard = new HashMap<Long, XClipboard>(2);
   146             }
   160             }
   147             mustSchedule = listenedClipboards.isEmpty();
   161             mustSchedule = targetsAtom2Clipboard.isEmpty();
   148             listenedClipboards.add(this);
   162             targetsAtom2Clipboard.put(getTargetsPropertyAtom().getAtom(), this);
       
   163             if (mustSchedule) {
       
   164                 XToolkit.addEventDispatcher(XWindow.getXAWTRootWindow().getWindow(),
       
   165                                             new SelectionNotifyHandler());
       
   166             }
   149         }
   167         }
   150         if (mustSchedule) {
   168         if (mustSchedule) {
   151             XToolkit.schedule(new CheckChangeTimerTask(), pollInterval);
   169             XToolkit.schedule(new CheckChangeTimerTask(), XClipboard.getPollInterval());
   152         }
   170         }
   153     }
   171     }
   154 
   172 
   155     private static class CheckChangeTimerTask implements Runnable {
   173     private static class CheckChangeTimerTask implements Runnable {
   156         public void run() {
   174         public void run() {
   157             for (Iterator iter = listenedClipboards.iterator(); iter.hasNext();) {
   175             for (XClipboard clpbrd : targetsAtom2Clipboard.values()) {
   158                 XClipboard clpbrd = (XClipboard)iter.next();
   176                 clpbrd.getTargetsDelayed();
   159                 clpbrd.selection.getTargetsDelayed();
       
   160             }
   177             }
   161             synchronized (XClipboard.classLock) {
   178             synchronized (XClipboard.classLock) {
   162                 if (listenedClipboards != null && !listenedClipboards.isEmpty()) {
   179                 if (targetsAtom2Clipboard != null && !targetsAtom2Clipboard.isEmpty()) {
   163                     XToolkit.schedule(this, pollInterval);
   180                     XToolkit.schedule(this, XClipboard.getPollInterval());
       
   181                 }
       
   182             }
       
   183         }
       
   184     }
       
   185 
       
   186     private static class SelectionNotifyHandler implements XEventDispatcher {
       
   187         public void dispatchEvent(XEvent ev) {
       
   188             if (ev.get_type() == XlibWrapper.SelectionNotify) {
       
   189                 final XSelectionEvent xse = ev.get_xselection();
       
   190                 XClipboard clipboard = null;
       
   191                 synchronized (XClipboard.classLock) {
       
   192                     if (targetsAtom2Clipboard != null && !targetsAtom2Clipboard.isEmpty()) {
       
   193                         XToolkit.removeEventDispatcher(XWindow.getXAWTRootWindow().getWindow(), this);
       
   194                         return;
       
   195                     }
       
   196                     final long propertyAtom = xse.get_property();
       
   197                     clipboard = targetsAtom2Clipboard.get(propertyAtom);
       
   198                 }
       
   199                 if (null != clipboard) {
       
   200                     clipboard.checkChange(xse);
   164                 }
   201                 }
   165             }
   202             }
   166         }
   203         }
   167     }
   204     }
   168 
   205 
   169     protected void unregisterClipboardViewerChecked() {
   206     protected void unregisterClipboardViewerChecked() {
   170         selection.deinitializeSelectionForTrackingChanges();
   207         isSelectionNotifyProcessed = false;
   171         synchronized (XClipboard.classLock) {
   208         synchronized (XClipboard.classLock) {
   172             listenedClipboards.remove(this);
   209             targetsAtom2Clipboard.remove(getTargetsPropertyAtom().getAtom());
   173         }
   210         }
   174     }
   211     }
   175 
   212 
       
   213     // checkChange() will be called on SelectionNotify
       
   214     private void getTargetsDelayed() {
       
   215         XToolkit.awtLock();
       
   216         try {
       
   217             long curTime = System.currentTimeMillis();
       
   218             if (isSelectionNotifyProcessed || curTime >= (convertSelectionTime + UNIXToolkit.getDatatransferTimeout()))
       
   219             {
       
   220                 convertSelectionTime = curTime;
       
   221                 XlibWrapper.XConvertSelection(XToolkit.getDisplay(),
       
   222                                               selection.getSelectionAtom().getAtom(),
       
   223                                               XDataTransferer.TARGETS_ATOM.getAtom(),
       
   224                                               getTargetsPropertyAtom().getAtom(),
       
   225                                               XWindow.getXAWTRootWindow().getWindow(),
       
   226                                               XlibWrapper.CurrentTime);
       
   227                 isSelectionNotifyProcessed = false;
       
   228             }
       
   229         } finally {
       
   230             XToolkit.awtUnlock();
       
   231         }
       
   232     }
       
   233 
       
   234     /*
       
   235      * Tracks changes of available formats.
       
   236      * NOTE: This method may be called by privileged threads.
       
   237      *       DO NOT INVOKE CLIENT CODE ON THIS THREAD!
       
   238      */
       
   239     private void checkChange(XSelectionEvent xse) {
       
   240         final long propertyAtom = xse.get_property();
       
   241         if (propertyAtom != getTargetsPropertyAtom().getAtom()) {
       
   242             // wrong atom
       
   243             return;
       
   244         }
       
   245 
       
   246         final XAtom selectionAtom = XAtom.get(xse.get_selection());
       
   247         final XSelection changedSelection = XSelection.getSelection(selectionAtom);
       
   248 
       
   249         if (null == changedSelection || changedSelection != selection) {
       
   250             // unknown selection - do nothing
       
   251             return;
       
   252         }
       
   253 
       
   254         isSelectionNotifyProcessed = true;
       
   255 
       
   256         if (selection.isOwner()) {
       
   257             // selection is owner - do not need formats
       
   258             return;
       
   259         }
       
   260 
       
   261         long[] formats = null;
       
   262 
       
   263         if (propertyAtom == XlibWrapper.None) {
       
   264             // We treat None property atom as "empty selection".
       
   265             formats = new long[0];
       
   266         } else {
       
   267             WindowPropertyGetter targetsGetter =
       
   268                 new WindowPropertyGetter(XWindow.getXAWTRootWindow().getWindow(),
       
   269                                          XAtom.get(propertyAtom), 0,
       
   270                                          XSelection.MAX_LENGTH, true,
       
   271                                          XlibWrapper.AnyPropertyType);
       
   272             try {
       
   273                 targetsGetter.execute();
       
   274                 formats = XSelection.getFormats(targetsGetter);
       
   275             } finally {
       
   276                 targetsGetter.dispose();
       
   277             }
       
   278         }
       
   279 
       
   280         checkChange(formats);
       
   281     }
   176 }
   282 }