5

On an (embedded) Ubuntu 12.04 system, we have a simple Java program that displays some graphics patterns on a window, updating every second or so. We use it to monitor some processes running on the system. The problem is that while it is active and not minimized, it steals the focus whenever the window is updated. This makes working with the open terminal windows impossible.

The behaviour is the same when running the app form command line or from Eclipse IDE.

The same problem does not occur on Windows 7 when running under NetBeans IDE.

How can we prevent the Java app from stealing the focus on the Ubuntu machine?


UPDATE 1: Found this question that seem to struggle with the same problem: How do I stop/workaround Java apps stealing focus in Linux window managers . Reading it, I learned that the problem is with using JFrame as a container, which is what we use. Their solution was to use the JWindow container instead of JFrame container. However, searching for the difference, the JWindow is "naked" and does not behave like a "real" window, as there's no decorations. Is there a way to use JWindow inside a JFrame, and thus eliminate the focus stealing?


UPDATE 2: Trying to run this program on an Ubuntu Virtual Machine on the PC gives the same misbehaviour. This suggests that there is a difference of the Java runtime of Windows 7 and Linux, and that the problem is not specific to the Embedded linux.


UPDATE 3: Here's a SSCCE:

//package SSCCE;

import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;

public class MonitorSSCCE extends JFrame{

    public static void main(String[] args) 
    {
        // Set the frame
        JFrame ecoreFrame = new JFrame("SSCCE");
        ecoreFrame.setSize(120, 120);
        ecoreFrame.setVisible(true);

        // Refresh frame every 200 msec
        while (true) {
            GRFX grfx = new GRFX();
            ecoreFrame.add(grfx);
            ecoreFrame.setVisible(true);
            grfx = null;

            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {

            }
        }
    }


    static int clr = 0;

    public static class GRFX extends JPanel {

        public void paintComponent(Graphics comp) {
            Graphics2D comp2D = (Graphics2D) comp;

            // Draw a changin color rectangle
            comp2D.setColor(new Color(clr, 0, 0));
            Rectangle2D.Double rect = new Rectangle2D.Double(10, 10, 100, 100);
            comp2D.fill(rect);
            clr = clr + 10;
            if (clr > 255)
                clr = 0;
        }
    }
}

UPDATE 4: While preparing the SSCCE, I had some reading and find out about the plethora of window refresh methods of the JFrame object. It happens that the problem was the setVisible() call inside the while loop. The solution was to replace it with the repaint() method.

Community
  • 1
  • 1
ysap
  • 7,723
  • 7
  • 59
  • 122
  • Please edit your question to include a minimal [sscce](http://sscce.org/) that exhibits the problem you describe. – trashgod Aug 26 '13 at 20:57
  • For reference, this [example](http://stackoverflow.com/a/12228640/230513) "displays some graphics…, updating every second," but it does _not_ steal focus. – trashgod Aug 26 '13 at 21:05
  • 1
    @trashgod - thanks. I am not a Java programmer, and the guy that wrote the app was copying code example from a book - so his familiarity with the Java GUI concepts is very limited as well. I will look at the link you provided and see if it solves the problem. – ysap Aug 26 '13 at 21:10
  • @trashgod - it seems like the calls in yur `display()` method are the same as what we used. As I mentioned it behaves well on Windows but not on Ubuntu. – ysap Aug 26 '13 at 21:15

2 Answers2

2

On Ubuntu 12.04.2 with the Unity window manager, this example animates normally on the desktop in the background at 1 Hz while a terminal and software update are also running. A few points of reference for comparison:

Addendum: I re-factored your example below to illustrate some additional points:

image

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Rectangle2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

/**
 * @see https://stackoverflow.com/a/18455006/230513
 */
public class TestGRFX {

    private static class GRFX extends JPanel {

        private static final int N = 256;
        private float clr = 0;
        private Rectangle2D.Double rect = new Rectangle2D.Double(0, 0, N, N);
        private Timer t = new Timer(100, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                GRFX.this.repaint();
            }
        });

        public void start() {
            t.start();
        }

        @Override
        public void paintComponent(Graphics g) {
            Graphics2D g2D = (Graphics2D) g;
            g2D.setColor(new Color(Color.HSBtoRGB(clr, 1, 1)));
            g2D.fill(rect);
            clr += .01;
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(N, N);
        }
    }

    private void display() {
        JFrame f = new JFrame("TestGRFX");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        GRFX g = new GRFX();
        f.add(g);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
        g.start();
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new TestGRFX().display();
            }
        });
    }
}
Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • The 3rd bullet encouraged me to research the window update methods and to find the solution. It happens that `setVisible()` is stealing the focus and had to be replaced. – ysap Aug 27 '13 at 16:06
0

Replacing the setVisible() method call inside the while() loop by repaint() eliminated the problem:

    // Refresh frame every 200 msec
    while (true) {
        GRFX grfx = new GRFX();
        ecoreFrame.add(grfx);
        ecoreFrame.repaint();
        grfx = null;

        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {

        }
    }
ysap
  • 7,723
  • 7
  • 59
  • 122
  • Question 1 - is it necessary to `null` the `grfx` object at each iteration? If I don't, will this cause a memory leak? – ysap Aug 27 '13 at 16:13
  • Question 2 - Are the graphics objects put on the JFrame really objects in the sense that the rectangle have attributes which can be changed later on and the canvas will be correctly repainted (think a moving square - will the old square get erased correctly)? – ysap Aug 27 '13 at 16:15