Java thread goes to sleep when not in focus on OSX

2019-05-08 07:02发布

I'm writing a program that listens to the System Clipboard for changes. The listener runs on a separate thread and performs some action (say, write to file) when the contents of the Clipboard changes.

I'm polling the clipboard using the ClipboardOwner interface, so that when my program loses ownership of the Clipboard (meaning another process has modified the clipboard) an event is fired in my program letting me read the changes.

public class OwnershipClipboardListener extends Thread implements ClipboardOwner
{
    private Clipboard clipB = Toolkit.getDefaultToolkit().getSystemClipboard();

    public void run()
    {
        /* Initialize ClipboardListener and gain ownership of clipboard */
    }

    @Override
    public void lostOwnership(Clipboard clipboard, Transferable transferable)
    {
        /* Auto-fired when I lose Clipboard ownership.
           Can do processing and regaining ownership here */
    }    
}

The problem is, when running in OSX, any change to the clipboard is reflected only if I manually Cmd-Tab to the running process icon in the dock. So if there multiple clipboard operations before I switch to the dock icon, only the last one has any effect. I don't face this issue on Linux or Windows.

It's like the thread goes to sleep when the program loses focus, but the last Event trigger still fires when it wakes up. Is there any way I can prevent this sleep?

3条回答
老娘就宠你
2楼-- · 2019-05-08 07:30

Seems Keith is right. However, you can do a workaround by sending the application to the background (on *Nix):

java -jar clipboard-1.0.jar &

This opens the Java application in the background and does not need window focus for notifications to fire.

查看更多
Viruses.
3楼-- · 2019-05-08 07:33

I suspect that OSX doesn't provide notification of clipboard changes, so Java is doing the best it can by notifying you whenever it gets woken for some other reason.

My suspicion comes from the NSPasteboard docs, the changeCount routine in particular. It says "You can therefore record the change count at the time that you take ownership of the pasteboard and later compare it with the value returned from changeCount to determine whether you still have ownership." No mention of using an event to detect changes.

查看更多
手持菜刀,她持情操
4楼-- · 2019-05-08 07:35

I'm trying to use this workaround however it don't do the trick for me, ideas? Note that there is a bug in Mac OS X port of java: http://java.net/jira/browse/MACOSX_PORT-511

This is my source code:


import java.awt.Toolkit;  
import java.awt.datatransfer.*;  
import java.io.IOException;  

public class ClipboardListener extends Thread implements ClipboardOwner {

    Clipboard systemClipboard = Toolkit.getDefaultToolkit().getSystemClipboard();  

    public void run(){  
        Transferable selection = systemClipboard.getContents(this);  
        gainOwnership(selection);  
        while (true) {}
    }  

    public void gainOwnership(Transferable t){ 
        try {this.sleep(100);} 
        catch (InterruptedException e) {}
        systemClipboard.setContents(t, this);  
    }  

    public void lostOwnership(Clipboard clipboard, Transferable contents) {
        try {System.out.println((String) clipboard.getData(DataFlavor.stringFlavor));} 
        catch (UnsupportedFlavorException e) {} 
        catch (IOException e) {}
        gainOwnership(contents);  
    }  
}

public class myApp {

    public static void main(String[] args){
        ClipboardListener listener = new ClipboardListener();
        listener.start();}
}
查看更多
登录 后发表回答