views:

48

answers:

2

Hi, we have problems with Java 6 applications that do not properly refresh when switching virtual desktops. The problem so far has been reproduced on Fedora 11 and 13 with GNOME and Suse SLES 10 with KDE. I use the following test case to reproduce the problem:

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.Timer;

public class RepaintTest {
    private JLabel label;

    private void createAndShowGUI() {
        final JFrame frame = new JFrame("RepaintTest");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        label = new JLabel("Repaint Test");
        label.setOpaque(true);
        frame.getContentPane().add(label);
        frame.pack();
        frame.setSize(200, 100);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                final RepaintTest repaintTest = new RepaintTest();
                repaintTest.createAndShowGUI();
                new Timer(5000, new ActionListener() {
                    boolean flip;
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        repaintTest.label.setBackground(flip ? Color.GREEN : Color.RED);
                        flip = !flip;
                    }
                }).start();
            }
        });
    }
}

Start this program and move another window, for example, a terminal window, partially in front of it. Wait for the window background to become red, switch to another virtual desktop and wait for five seconds, then switch back to your original screen. The background now should be completely green. Instead, what I get is a window that is only partially updated in the visible parts not covered by the other window, see screen shot.

This problem does not occur with Java 5 and it does not occur when using one of the following properties at startup:

-Dswing.handleTopLevelPaint=false

or

-Dswing.bufferPerWindow=false

However, turning off Swing's double buffering seems not to be a very good option. Is this a JDK bug on Linux or can we do anything in our applications to fix this repaint problem?

Thanks in advance, Mark.

+1  A: 

Your TimerTask needs to change the label on the event dispatch thread, e.g.

new Timer().schedule(new TimerTask() {
    boolean flip;
    @Override
    public void run() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                repaintTest.label.setBackground(flip ? Color.GREEN : Color.RED);
                flip = !flip;
            }
        });
    }
}, 5000, 5000);

More conveniently, use javax.swing.Timer, as its action event handler executes on the event-dispatching thread.

trashgod