Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to detect window occlusion

Using AWT, I would like to save resources like flash does, by stopping draws to the screen when the window is hidden. But first, I need a method to detect if the Frame is completely covered by one or more other windows. Windows that are likely not from the same application, so I can't just sum up their shapes.

So the question is, is it possible to detect if the window is covered by other windows from other applications?

like image 527
warren Avatar asked Jan 25 '14 07:01

warren


1 Answers

Everything is possible just you need some creativity and hard work :)

I hope you know that Java can call native Windows API (this won't be very performance vise, but we have only this way), for this we could use JNA lib which will give us access to native shared libraries.

I have done some quick concept check this code only checks if active window fully covers java application window, but you can iterate over visible windows and calculate area too, JNA gives that access too.

For my demo project I was using these JNA dependencies:

compile("net.java.dev.jna", "jna", "4.5.0")
compile("net.java.dev.jna", "jna-platform", "4.5.0")

My main class:

package com.sauliuxx.inc;

import com.sauliuxx.inc.workers.ActiveWindowChecker;
import com.sun.jna.platform.win32.WinDef;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * The type App.
 */
public class App extends Frame implements ActionListener {

    private final String title = "Demo123";
    private Label sizeLabel;
    private Label positionLabel;
    private Label visibleLabel;

    BlockingQueue<WinDef.RECT> q =
            new LinkedBlockingQueue<>();

    private App() {
        this.setTitle(title);
        this.setLayout(new BorderLayout());
        this.setSize(500, 500);
        Panel infoPanel = new Panel();
        sizeLabel = new Label(this.getSize().height + " X " + this.getSize().width);
        infoPanel.add(sizeLabel);
        positionLabel = new Label("X: " + this.getLocation().getX() + " Y: " + this.getLocation().getY());
        infoPanel.add(positionLabel);
        visibleLabel = new Label(this.isVisible() ? "true" : "false");
        infoPanel.add(visibleLabel);
        this.add(infoPanel, BorderLayout.PAGE_END);

        Timer timer = new Timer(250, this);
        timer.start();

        this.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });

        this.addComponentListener(new ComponentListener() {
            @Override
            public void componentResized(ComponentEvent componentEvent) {
                sizeLabel.setText(componentEvent.getComponent().getSize().height + " X " + componentEvent.getComponent().getSize().width);
            }

            @Override
            public void componentMoved(ComponentEvent componentEvent) {
                positionLabel.setText("X: " + componentEvent.getComponent().getLocation().getX() + " Y: " + componentEvent.getComponent().getLocation().getY());
            }

            @Override
            public void componentShown(ComponentEvent componentEvent) {
                visibleLabel.setText("true");
            }

            @Override
            public void componentHidden(ComponentEvent componentEvent) {
                visibleLabel.setText("false");
            }
        });

        ActiveWindowChecker awcDeamon = new ActiveWindowChecker(q);
        awcDeamon.setDaemon(true);
        awcDeamon.start();

    }

    @Override
    public void actionPerformed(ActionEvent actionEvent) {

        WinDef.RECT rect = null;

        try {
            rect = q.take();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if (this.isActive()) {
            System.out.println("action");
        } else {
            //System.out.println("rect = " + (rect != null ? rect : ""));
            //System.out.println("frame = [(" + (int)this.getLocation().getX() + "," + (int)this.getLocation().getY() + ") (" + this.getSize().width + "," + this.getSize().height + ")]");

            // x and y windows to compare top left point
            int rxTop = rect == null ? 0: rect.left;
            int ryTop = rect == null ? 0:rect.top;
            int fxTop = (int) this.getLocation().getX();
            int fyTop = (int) this.getLocation().getY();

            // bottom right points
            int rxBottom = rect == null ? 0: rect.right;
            int ryBottom = rect == null ? 0: rect.bottom;
            int fxBottom = fxTop + this.getSize().width;
            int fyBottom = fyTop + this.getSize().height;

            if ((rxTop >= fxTop || ryTop >= fyTop) || (rxBottom <= fxBottom || ryBottom <= fyBottom))
            {
                System.out.println("Not covered by active window.");
            }
            else{
                System.out.println("Covered by active window.");
            }
        }
    }

    /**
     * The entry point of application.
     *
     * @param args the input arguments
     */
    public static void main(String... args) {

        if (!System.getProperty("os.name").contains("Windows")) {
            System.err.println("ERROR: Only implemented on Windows");
            System.exit(1);
        }

        java.awt.EventQueue.invokeLater(() -> new App().setVisible(true));
    }
}

My worker class:

package com.sauliuxx.inc.workers;

import com.sun.jna.Native;
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinDef;

import java.util.concurrent.BlockingQueue;

/**
 * The type Active window checker.
 */
public class ActiveWindowChecker extends Thread {

    private static final int MAX_TITLE_LENGTH = 1024;

    private final BlockingQueue<WinDef.RECT> queue;

    /**
     * Instantiates a new Active window checker.
     *
     * @param q the q
     */
    public ActiveWindowChecker(BlockingQueue<WinDef.RECT> q) {
        this.queue = q;
    }

    @Override
    public void run() {
        Exception ex = null;
        while (ex == null) {
            char[] buffer = new char[MAX_TITLE_LENGTH * 2];
            WinDef.HWND hwnd = User32.INSTANCE.GetForegroundWindow();
            User32.INSTANCE.GetWindowText(hwnd, buffer, MAX_TITLE_LENGTH);
            System.out.println("Active window title: " + Native.toString(buffer));
            WinDef.RECT rect = new WinDef.RECT();
            User32.INSTANCE.GetWindowRect(hwnd, rect);
            try {
                queue.put(rect);
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
                ex = e;
            }
        }
    }
}
like image 182
Saulius Next Avatar answered Oct 07 '22 23:10

Saulius Next