Is it possible to detect window occlusion
Asked Answered
I

1

9

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?

Ilion answered 25/1, 2014 at 7:43 Comment(7)
Java-2D should do that automatically.Cognizance
My tests show that rendering speed/cost is unaffected by if the window is covered or not.Ilion
How exactly are you rendering? An MCVE might help here.Cognizance
Currently, I am drawing to the screen by rendering to either a buffered image or a volatile image, depending on if I need low level pixel manipulation or not, then drawing the image to the window. I am monitoring by setting the resolution to max and looking at the computer's CPU usage while playing an animation at 10.7hz.Ilion
Java-2D will only save on part of painting the final image! This (you'll find) takes virtually no time and is not the bottleneck.Cognizance
If I understand you correctly, I already knew that Relying on builtin Java2D behaviour would not be enough. To save on resources when window is hidden.Ilion
"If I understand you correctly," No, you obviously don't.Cognizance
E
3

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;
            }
        }
    }
}
Erlindaerline answered 6/3, 2018 at 19:43 Comment(2)
Creative, but less than ideal for my purposes, since I need to support at least Windows, Linux and OS X. I'm sure the same can be done on those platforms, but I find it hard to motivate maintaining this for multiple platforms.Hinkley
I believe you have two challenges: build application which could work on all systems and Java is good choice also you can use other languages which runs on JVM, second app should interact with all these operating system platforms, and this is hell.Erlindaerline

© 2022 - 2024 — McMap. All rights reserved.