org.nuiton.jaxx.runtime.swing.session.WindowState Maven / Gradle / Ivy
package org.nuiton.jaxx.runtime.swing.session;
/*
* #%L
* JAXX :: Runtime
* %%
* Copyright (C) 2008 - 2024 Code Lutin, Ultreia.io
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* .
* #L%
*/
import javax.swing.JFrame;
import java.awt.Dialog;
import java.awt.Frame;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.awt.Window;
/**
* State for Window
*
* @author poussin
* @author Kevin Morin - [email protected]
* @since 2.5.16
*/
public class WindowState implements State {
private static final String WINDOW_STATE_NORMAL_BOUNDS =
"WindowState.normalBounds";
protected Rectangle bounds;
protected Rectangle gcBounds;
protected int frameState = Frame.NORMAL;
public WindowState() {
}
public WindowState(Rectangle bounds, Rectangle gcBounds, int frameState) {
this.bounds = new Rectangle(bounds);
this.gcBounds = new Rectangle(gcBounds);
this.frameState = frameState;
}
public Rectangle getBounds() {
return bounds;
}
public void setBounds(Rectangle bounds) {
this.bounds = bounds;
}
public Rectangle getGcBounds() {
return gcBounds;
}
public void setGcBounds(Rectangle gcBounds) {
this.gcBounds = gcBounds;
}
public int getFrameState() {
return frameState;
}
public void setFrameState(int frameState) {
this.frameState = frameState;
}
protected Window checkComponent(Object o) {
if (o == null) {
throw new IllegalArgumentException("null component");
}
if (!(o instanceof Window)) {
throw new IllegalArgumentException("invalid component");
}
return (Window) o;
}
/**
* Checks whether the window supports resizing
*
* @param window the {@code Window} to be checked
* @return true if the window supports resizing
*/
protected static boolean isResizable(Window window) {
boolean resizable = true;
if (window instanceof Frame) {
resizable = ((Frame) window).isResizable();
} else if (window instanceof Dialog) {
resizable = ((Dialog) window).isResizable();
}
return resizable;
}
/**
* Gets {@code Window} bounds from the client property
*
* @param window the source {@code Window}
* @return bounds from the client property
*/
protected static Rectangle getWindowNormalBounds(Window window) {
Rectangle result = null;
if (window instanceof JFrame) {
Object res = ((JFrame) window).getRootPane().getClientProperty(
WINDOW_STATE_NORMAL_BOUNDS);
if (res instanceof Rectangle) {
result = (Rectangle) res;
}
}
return result;
}
/**
* Calculates virtual graphic bounds.
* On multiscreen systems all screens are united into one virtual screen.
*
* @return the graphic bounds
*/
public static Rectangle computeVirtualGraphicsBounds() {
Rectangle virtualBounds = new Rectangle();
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice[] gs = ge.getScreenDevices();
for (GraphicsDevice gd : gs) {
GraphicsConfiguration gc = gd.getDefaultConfiguration();
virtualBounds = virtualBounds.union(gc.getBounds());
}
return virtualBounds;
}
/**
* Puts {@code Window} bounds to client property.
*
* @param window the target {@code Window}
* @param bounds bounds
*/
public static void putWindowNormalBounds(Window window, Rectangle bounds) {
if (window instanceof JFrame) {
((JFrame) window).getRootPane().putClientProperty(
WINDOW_STATE_NORMAL_BOUNDS, bounds);
}
}
@Override
public State getState(Object o) {
Window c = checkComponent(o);
int frameState = Frame.NORMAL;
if (c instanceof Frame) {
frameState = ((Frame) c).getExtendedState();
}
GraphicsConfiguration gc = c.getGraphicsConfiguration();
Rectangle gcBounds = (gc == null) ? null : gc.getBounds();
Rectangle frameBounds = c.getBounds();
/* If this is a JFrame created by FrameView and it's been maximized,
* retrieve the frame's normal (not maximized) bounds. More info:
* see FrameStateListener#windowStateChanged in FrameView.
*/
if ((c instanceof JFrame) && (0 != (frameState & Frame.MAXIMIZED_BOTH))) {
frameBounds = getWindowNormalBounds(c);
}
WindowState result = null;
if (frameBounds != null && !frameBounds.isEmpty()) {
result = new WindowState();
result.setBounds(frameBounds);
result.setGcBounds(gcBounds);
result.setFrameState(frameState);
}
return result;
}
@Override
public void setState(Object o, State state) {
Window w = checkComponent(o);
if ((state != null) && !(state instanceof WindowState)) {
throw new IllegalArgumentException("invalid state");
}
WindowState windowState = (WindowState) state;
if (windowState.getBounds() != null) {
putWindowNormalBounds(w, windowState.getBounds());
if (!w.isLocationByPlatform() && (state != null)) {
Rectangle gcBounds0 = windowState.getGcBounds();
if (gcBounds0 != null && isResizable(w)) {
if (computeVirtualGraphicsBounds().contains(gcBounds0.getLocation())) {
w.setBounds(windowState.getBounds());
} else {
w.setSize(windowState.getBounds().getSize());
}
}
}
if (w instanceof Frame) {
((Frame) w).setExtendedState(windowState.getFrameState());
}
}
}
}