28

The following code from a standalone application works in ubuntu:

import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;

public class ClipboardTest {

    public static void main(String[] args) throws Exception {
        Clipboard clipBoard = Toolkit.getDefaultToolkit().getSystemClipboard();        
        // print the last copied thing
        System.out.println(clipBoard.getContents(null).getTransferData(DataFlavor.stringFlavor));
        StringSelection data = new StringSelection("NOW");
        clipBoard.setContents(data, data);
        // prints NOW
        System.out.println(clipBoard.getContents(null).getTransferData(DataFlavor.stringFlavor));
    }

}

Pasting (Ctrl+V) into a different application results in nothing; I expect "NOW". Calling the above code a second time gives the following exception:

Exception in thread "main" java.awt.datatransfer.UnsupportedFlavorException: Unicode String
    at sun.awt.datatransfer.ClipboardTransferable.getTransferData(ClipboardTransferable.java:160)

As a standalone application, this should work even after 2011 security changes. Copying via Ctrl+C from inside of a JTextField and then pasting elsewhere works.

Have been unsuccessful on ubuntu 11.04 with both the latest java7 (jdk1.7.0_10) and jdk1.6.0_33; It should work and does work as expected on windows 7 with the latest java7 and on mac osx 10.6 with java6_37. Also tried xubuntu 12.04 with those javas and it doesn't work there. Is this a linux/ubuntu bug?

Related question

Community
  • 1
  • 1
Karussell
  • 17,085
  • 16
  • 97
  • 197

4 Answers4

19

I got the same problem with the application at my work and here's an article I've found that explain why and possible solutions. I hope it helps.

Why it happens

Clipboard persistence is a bug that affects many programs under Ubuntu and other X11-based operating systems. Fixing it is a Google Summer of Code 2010 project. Wikipedia has a good overview of the issue. If you want to fix as a user, you can install Parcellite or another clipboard manager. If you want to fix it as a programmer, you can modify your program to conform to the ClipboardManager specification.

X-Window wiki

Using gnome library you could call the store method on the clipboard and fix this. That's the only thing so far that seems to be worth trying. Also saw a similar thing for GTK but only in an Eclipse's bug.

Jonathan Drapeau
  • 2,610
  • 2
  • 26
  • 32
  • Looks that you have found the real cause + pain! Thanks! – Karussell Jan 22 '13 at 22:03
  • Although I don't understand why it happens (your wikipedia link). I understand the difference of the nice copy-on-selection mechanism vs. copy via CTRL+C – Karussell Jan 22 '13 at 22:07
  • Sorry, made a mistake when I found the second article, the why it happens should be the second link. What I understand is that since the clipboard under linux doesn't store the data in a permenant place, and only keeps a reference, when the application is lost, so is the data. Edited the links. – Jonathan Drapeau Jan 22 '13 at 22:14
15

I tried your code with debian testing (7.0) and openjdk 7u3. The result is the same, but i think i found the Problem (Solution).

Content in the clipboard is only valid as long as the process exists. It works if i change your code to this:

import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;

public class ClipboardTest {

    public static void main(String[] args) throws Exception {
        Clipboard clipBoard = Toolkit.getDefaultToolkit().getSystemClipboard();
        // print the last copied thing
        Transferable t = clipBoard.getContents(null);
        if (t.isDataFlavorSupported(DataFlavor.stringFlavor))
            System.out.println(t.getTransferData(DataFlavor.stringFlavor));
        StringSelection data = new StringSelection("NOW");
        clipBoard.setContents(data, data);
        // prints NOW
        System.out.println(clipBoard.getContents(null).getTransferData(DataFlavor.stringFlavor));
        System.in.read();
    }
}

The if statement prevent your code from throwing an exception when there is no usable content, which happens if you run your code once and the process ends.
The System.in.read() just keeps the process alive. While not press enter i can paste into another application and "NOW" comes out as expected.
Like this the code works every time for me.

Hope this helps.

raffael
  • 2,427
  • 4
  • 26
  • 42
  • yeah the if is necessary .. but keeping the process open is the key!! Thanks a lot! Pasting into other applications really works. Now the strange part begins. Pasting into my Java app also behaves exactly as you described. But pasting it into NetBeans results in the system clipboard content! And when I stop the ClipboardTest the content immediately changes to "NOW" (whereas the 'paste' into native apps results in an empty string). very strange. I'll give you the credits if no one else finds the exact reason. Thanks again! – Karussell Jan 21 '13 at 22:17
  • I don't fully understand the new strange behavior. Could you give me a step by step explanation to reproduce? You may also check if you are using an application for the clipboard history and play with the settings. I remember a problem with klipper and java some years ago. – raffael Jan 22 '13 at 11:26
  • 1. Running your modified ClipboardTest 2. paste into native app => "NOW" 3. paste into Netbeans => "something different" 4. stopping ClipboardTest 5. paste into Netbeans => "NOW" – Karussell Jan 22 '13 at 16:02
  • This seems to be a problem of netbeans. I'm able to reproduce it. It does not occur if i start the ClipboardTest on the command line outside of netbeans. And it also does not occur in eclipse. – raffael Jan 22 '13 at 17:37
  • Thanks a lot! Do you think that the entire thing an ubuntu bug? – Karussell Jan 22 '13 at 19:17
  • I think that not keeping things in clipboard after closing the process is by design. For the thing with the netbeans problem i would guess it is a bug in netbeans. If it is a linux/ubuntu/debian bug, than it probably would happen with eclipse as well. – raffael Jan 22 '13 at 19:26
  • Why do you think it's by design? I mean, in other OS it behaves different. Shouldn't the 'design' of Java always be the same? – Karussell Jan 22 '13 at 20:22
  • Thanks, see Jonathans answer for an official reference – Karussell Jan 23 '13 at 07:19
4

Q: Have you tried something like this:

gksudo gedit /opt/java/64/jre1.7.0_04/lib/security/java.policy =>

permission java.awt.AWTPermission "accessClipboard";

See also:

Community
  • 1
  • 1
paulsm4
  • 114,292
  • 17
  • 138
  • 190
  • Hey, as I said this has nothing todo with the security policy. Because 1. it is NOT an applet (I run it from the command line) 2. it works under mac+windows 3. it does not work even with a jdk where this limitation was introduced 4. there is already "permission java.security.AllPermission;" – Karussell Jan 20 '13 at 14:30
  • Did you even *try* setting the Java policy? Or look at the other suggestions in the other links? Or did you just "assume" none of it has any bearing? – paulsm4 Jan 20 '13 at 18:38
  • One other question: If I were to get it working on the current release (Ubuntu 12.04 LTS/32 bit; it's been a couple of years since I've played with any older versions), would you be willing to upgrade to that version? – paulsm4 Jan 20 '13 at 19:12
  • What should I try if the policy already has AllPermission? I tried to replace that AllPermission with your suggested one - doesn't work. Also please see the question - I'm now on 12.04 (xubuntu but shouldn't matter). – Karussell Jan 20 '13 at 22:27
  • also tried to add this to the 'default permissions granted to all domains' in the java.policy - doesn't work. Does this work for your ubuntu 12.04? – Karussell Jan 20 '13 at 22:33
1

Here you can show a test:

A TextArea (its default copy/paste actions works out of the box with any other app on ubuntu)

I have added two buttons which copy and paste from/to system clipboard

import javax.swing.*;
import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.event.ActionEvent;
import java.io.IOException;

public class PruebaClipboard {
    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setTitle("Copy/Paste");
        frame.getContentPane().setLayout(new BorderLayout());
        JPanel btnPanel = new JPanel();
        JButton btnCopy = new JButton("copy");
        JButton btnPaste = new JButton("paste");
        btnPanel.add(btnCopy);
        btnPanel.add(btnPaste);
        final JTextArea textComp = new JTextArea(7,15);

        Action copyAction = new AbstractAction("copy") {
            public void actionPerformed(ActionEvent e) {
                Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
                StringSelection stringSelection = new StringSelection(textComp.getText());
                clipboard.setContents(stringSelection, stringSelection);
            }
        };

        btnCopy.setAction(copyAction);
        Action pasteAction = new AbstractAction("paste") {
            public void actionPerformed(ActionEvent e) {
                Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
                //odd: the Object param of getContents is not currently used
                Transferable contents = clipboard.getContents(null);
                boolean hasTransferableText = (contents != null) && contents.isDataFlavorSupported(DataFlavor.stringFlavor);
                if (hasTransferableText) {
                    try {
                        String result = "";
                        result = (String) contents.getTransferData(DataFlavor.stringFlavor);
                        textComp.append(result);
                    } catch (UnsupportedFlavorException ex) {
                        //highly unlikely since we are using a standard DataFlavor
                        System.out.println(ex);
                        ex.printStackTrace();
                    } catch (IOException ex) {
                        System.out.println(ex);
                        ex.printStackTrace();
                    }
                }
            }
        };
        btnPaste.setAction(pasteAction);

        frame.getContentPane().add(textComp);
        frame.getContentPane().add(btnPanel, BorderLayout.SOUTH);

        frame.setSize(new Dimension(400, 300));
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
    }
}

I think you must take care of:

boolean hasTransferableText = (contents != null) && contents.isDataFlavorSupported(DataFlavor.stringFlavor);

And see there is a DataFlavor.plainTextFlavor which maybe is what you need to use (although it is deprecated)

I have tested the code through java 1.4 to java 1.6 on Ubuntu 12.10, but the code where I extract it is in use since ubuntu 9.0 I recall.

albfan
  • 12,542
  • 4
  • 61
  • 80