|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package sun.swing; |
|
|
|
import java.awt.BorderLayout; |
|
import java.awt.Color; |
|
import java.awt.Component; |
|
import java.awt.Container; |
|
import java.awt.Dimension; |
|
import java.awt.EventQueue; |
|
import java.awt.Graphics; |
|
import java.awt.Graphics2D; |
|
import java.awt.MouseInfo; |
|
import java.awt.Point; |
|
import java.awt.Rectangle; |
|
import java.awt.Window; |
|
import java.awt.dnd.DragGestureEvent; |
|
import java.awt.dnd.DragGestureListener; |
|
import java.awt.dnd.DragGestureRecognizer; |
|
import java.awt.dnd.DragSource; |
|
import java.awt.dnd.DropTarget; |
|
import java.awt.dnd.InvalidDnDOperationException; |
|
import java.awt.dnd.peer.DragSourceContextPeer; |
|
import java.awt.event.ContainerEvent; |
|
import java.awt.event.ContainerListener; |
|
import java.awt.image.BufferedImage; |
|
import java.awt.image.DataBufferInt; |
|
import java.beans.PropertyChangeEvent; |
|
import java.beans.PropertyChangeListener; |
|
import java.security.AccessController; |
|
import javax.swing.JComponent; |
|
|
|
import javax.swing.JLayeredPane; |
|
import javax.swing.JPanel; |
|
import javax.swing.JRootPane; |
|
import javax.swing.LayoutFocusTraversalPolicy; |
|
import javax.swing.RepaintManager; |
|
import javax.swing.RootPaneContainer; |
|
import javax.swing.SwingUtilities; |
|
|
|
import sun.awt.AWTAccessor; |
|
import sun.awt.DisplayChangedListener; |
|
import sun.awt.LightweightFrame; |
|
import sun.awt.OverrideNativeWindowHandle; |
|
import sun.security.action.GetPropertyAction; |
|
import sun.swing.SwingUtilities2.RepaintListener; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public final class JLightweightFrame extends LightweightFrame implements RootPaneContainer { |
|
|
|
private final JRootPane rootPane = new JRootPane(); |
|
|
|
private LightweightContent content; |
|
|
|
private Component component; |
|
private JPanel contentPane; |
|
|
|
private BufferedImage bbImage; |
|
|
|
private volatile int scaleFactor = 1; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private static boolean copyBufferEnabled; |
|
private int[] copyBuffer; |
|
|
|
private PropertyChangeListener layoutSizeListener; |
|
private RepaintListener repaintListener; |
|
|
|
static { |
|
SwingAccessor.setJLightweightFrameAccessor(new SwingAccessor.JLightweightFrameAccessor() { |
|
@Override |
|
public void updateCursor(JLightweightFrame frame) { |
|
frame.updateClientCursor(); |
|
} |
|
}); |
|
copyBufferEnabled = "true".equals(AccessController. |
|
doPrivileged(new GetPropertyAction("swing.jlf.copyBufferEnabled", "true"))); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public JLightweightFrame() { |
|
super(); |
|
copyBufferEnabled = "true".equals(AccessController. |
|
doPrivileged(new GetPropertyAction("swing.jlf.copyBufferEnabled", "true"))); |
|
|
|
add(rootPane, BorderLayout.CENTER); |
|
setFocusTraversalPolicy(new LayoutFocusTraversalPolicy()); |
|
if (getGraphicsConfiguration().isTranslucencyCapable()) { |
|
setBackground(new Color(0, 0, 0, 0)); |
|
} |
|
|
|
layoutSizeListener = new PropertyChangeListener() { |
|
@Override |
|
public void propertyChange(PropertyChangeEvent e) { |
|
Dimension d = (Dimension)e.getNewValue(); |
|
|
|
if ("preferredSize".equals(e.getPropertyName())) { |
|
content.preferredSizeChanged(d.width, d.height); |
|
|
|
} else if ("maximumSize".equals(e.getPropertyName())) { |
|
content.maximumSizeChanged(d.width, d.height); |
|
|
|
} else if ("minimumSize".equals(e.getPropertyName())) { |
|
content.minimumSizeChanged(d.width, d.height); |
|
} |
|
} |
|
}; |
|
|
|
repaintListener = (JComponent c, int x, int y, int w, int h) -> { |
|
Window jlf = SwingUtilities.getWindowAncestor(c); |
|
if (jlf != JLightweightFrame.this) { |
|
return; |
|
} |
|
Point p = SwingUtilities.convertPoint(c, x, y, jlf); |
|
Rectangle r = new Rectangle(p.x, p.y, w, h).intersection( |
|
new Rectangle(0, 0, bbImage.getWidth() / scaleFactor, |
|
bbImage.getHeight() / scaleFactor)); |
|
|
|
if (!r.isEmpty()) { |
|
notifyImageUpdated(r.x, r.y, r.width, r.height); |
|
} |
|
}; |
|
|
|
SwingAccessor.getRepaintManagerAccessor().addRepaintListener( |
|
RepaintManager.currentManager(this), repaintListener); |
|
} |
|
|
|
@Override |
|
public void dispose() { |
|
SwingAccessor.getRepaintManagerAccessor().removeRepaintListener( |
|
RepaintManager.currentManager(this), repaintListener); |
|
super.dispose(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public void setContent(final LightweightContent content) { |
|
if (content == null) { |
|
System.err.println("JLightweightFrame.setContent: content may not be null!"); |
|
return; |
|
} |
|
this.content = content; |
|
this.component = content.getComponent(); |
|
|
|
Dimension d = this.component.getPreferredSize(); |
|
content.preferredSizeChanged(d.width, d.height); |
|
|
|
d = this.component.getMaximumSize(); |
|
content.maximumSizeChanged(d.width, d.height); |
|
|
|
d = this.component.getMinimumSize(); |
|
content.minimumSizeChanged(d.width, d.height); |
|
|
|
initInterior(); |
|
} |
|
|
|
@Override |
|
public Graphics getGraphics() { |
|
if (bbImage == null) return null; |
|
|
|
Graphics2D g = bbImage.createGraphics(); |
|
g.setBackground(getBackground()); |
|
g.setColor(getForeground()); |
|
g.setFont(getFont()); |
|
g.scale(scaleFactor, scaleFactor); |
|
return g; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public void grabFocus() { |
|
if (content != null) content.focusGrabbed(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public void ungrabFocus() { |
|
if (content != null) content.focusUngrabbed(); |
|
} |
|
|
|
@Override |
|
public int getScaleFactor() { |
|
return scaleFactor; |
|
} |
|
|
|
@Override |
|
public void notifyDisplayChanged(final int scaleFactor) { |
|
if (scaleFactor != this.scaleFactor) { |
|
if (!copyBufferEnabled) content.paintLock(); |
|
try { |
|
if (bbImage != null) { |
|
resizeBuffer(getWidth(), getHeight(), scaleFactor); |
|
} |
|
} finally { |
|
if (!copyBufferEnabled) content.paintUnlock(); |
|
} |
|
this.scaleFactor = scaleFactor; |
|
} |
|
if (getPeer() instanceof DisplayChangedListener) { |
|
((DisplayChangedListener)getPeer()).displayChanged(); |
|
} |
|
repaint(); |
|
} |
|
|
|
@Override |
|
public void addNotify() { |
|
super.addNotify(); |
|
if (getPeer() instanceof DisplayChangedListener) { |
|
((DisplayChangedListener)getPeer()).displayChanged(); |
|
} |
|
} |
|
|
|
private void syncCopyBuffer(boolean reset, int x, int y, int w, int h, int scale) { |
|
content.paintLock(); |
|
try { |
|
int[] srcBuffer = ((DataBufferInt)bbImage.getRaster().getDataBuffer()).getData(); |
|
if (reset) { |
|
copyBuffer = new int[srcBuffer.length]; |
|
} |
|
int linestride = bbImage.getWidth(); |
|
|
|
x *= scale; |
|
y *= scale; |
|
w *= scale; |
|
h *= scale; |
|
|
|
for (int i=0; i<h; i++) { |
|
int from = (y + i) * linestride + x; |
|
System.arraycopy(srcBuffer, from, copyBuffer, from, w); |
|
} |
|
} finally { |
|
content.paintUnlock(); |
|
} |
|
} |
|
|
|
private void notifyImageUpdated(int x, int y, int width, int height) { |
|
if (copyBufferEnabled) { |
|
syncCopyBuffer(false, x, y, width, height, scaleFactor); |
|
} |
|
content.imageUpdated(x, y, width, height); |
|
} |
|
|
|
private void initInterior() { |
|
contentPane = new JPanel() { |
|
@Override |
|
public void paint(Graphics g) { |
|
if (!copyBufferEnabled) { |
|
content.paintLock(); |
|
} |
|
try { |
|
super.paint(g); |
|
|
|
final Rectangle clip = g.getClipBounds() != null ? |
|
g.getClipBounds() : |
|
new Rectangle(0, 0, contentPane.getWidth(), contentPane.getHeight()); |
|
|
|
clip.x = Math.max(0, clip.x); |
|
clip.y = Math.max(0, clip.y); |
|
clip.width = Math.min(contentPane.getWidth(), clip.width); |
|
clip.height = Math.min(contentPane.getHeight(), clip.height); |
|
|
|
EventQueue.invokeLater(new Runnable() { |
|
@Override |
|
public void run() { |
|
Rectangle c = contentPane.getBounds().intersection(clip); |
|
notifyImageUpdated(c.x, c.y, c.width, c.height); |
|
} |
|
}); |
|
} finally { |
|
if (!copyBufferEnabled) { |
|
content.paintUnlock(); |
|
} |
|
} |
|
} |
|
@Override |
|
protected boolean isPaintingOrigin() { |
|
return true; |
|
} |
|
}; |
|
contentPane.setLayout(new BorderLayout()); |
|
contentPane.add(component); |
|
if ("true".equals(AccessController. |
|
doPrivileged(new GetPropertyAction("swing.jlf.contentPaneTransparent", "false")))) |
|
{ |
|
contentPane.setOpaque(false); |
|
} |
|
setContentPane(contentPane); |
|
|
|
contentPane.addContainerListener(new ContainerListener() { |
|
@Override |
|
public void componentAdded(ContainerEvent e) { |
|
Component c = JLightweightFrame.this.component; |
|
if (e.getChild() == c) { |
|
c.addPropertyChangeListener("preferredSize", layoutSizeListener); |
|
c.addPropertyChangeListener("maximumSize", layoutSizeListener); |
|
c.addPropertyChangeListener("minimumSize", layoutSizeListener); |
|
} |
|
} |
|
@Override |
|
public void componentRemoved(ContainerEvent e) { |
|
Component c = JLightweightFrame.this.component; |
|
if (e.getChild() == c) { |
|
c.removePropertyChangeListener(layoutSizeListener); |
|
} |
|
} |
|
}); |
|
} |
|
|
|
@SuppressWarnings("deprecation") |
|
@Override public void reshape(int x, int y, int width, int height) { |
|
super.reshape(x, y, width, height); |
|
|
|
if (width == 0 || height == 0) { |
|
return; |
|
} |
|
if (!copyBufferEnabled) { |
|
content.paintLock(); |
|
} |
|
try { |
|
boolean createBB = (bbImage == null); |
|
int newW = width; |
|
int newH = height; |
|
if (bbImage != null) { |
|
int imgWidth = bbImage.getWidth() / scaleFactor; |
|
int imgHeight = bbImage.getHeight() / scaleFactor; |
|
if (width != imgWidth || height != imgHeight) { |
|
createBB = true; |
|
if (bbImage != null) { |
|
int oldW = imgWidth; |
|
int oldH = imgHeight; |
|
if ((oldW >= newW) && (oldH >= newH)) { |
|
createBB = false; |
|
} else { |
|
if (oldW >= newW) { |
|
newW = oldW; |
|
} else { |
|
newW = Math.max((int)(oldW * 1.2), width); |
|
} |
|
if (oldH >= newH) { |
|
newH = oldH; |
|
} else { |
|
newH = Math.max((int)(oldH * 1.2), height); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
if (createBB) { |
|
resizeBuffer(newW, newH, scaleFactor); |
|
return; |
|
} |
|
content.imageReshaped(0, 0, width, height); |
|
|
|
} finally { |
|
if (!copyBufferEnabled) { |
|
content.paintUnlock(); |
|
} |
|
} |
|
} |
|
|
|
private void resizeBuffer(int width, int height, int newScaleFactor) { |
|
bbImage = new BufferedImage(width*newScaleFactor,height*newScaleFactor, |
|
BufferedImage.TYPE_INT_ARGB_PRE); |
|
int[] pixels= ((DataBufferInt)bbImage.getRaster().getDataBuffer()).getData(); |
|
if (copyBufferEnabled) { |
|
syncCopyBuffer(true, 0, 0, width, height, newScaleFactor); |
|
pixels = copyBuffer; |
|
} |
|
content.imageBufferReset(pixels, 0, 0, width, height, |
|
width * newScaleFactor, newScaleFactor); |
|
} |
|
|
|
@Override |
|
public JRootPane getRootPane() { |
|
return rootPane; |
|
} |
|
|
|
@Override |
|
public void setContentPane(Container contentPane) { |
|
getRootPane().setContentPane(contentPane); |
|
} |
|
|
|
@Override |
|
public Container getContentPane() { |
|
return getRootPane().getContentPane(); |
|
} |
|
|
|
@Override |
|
public void setLayeredPane(JLayeredPane layeredPane) { |
|
getRootPane().setLayeredPane(layeredPane); |
|
} |
|
|
|
@Override |
|
public JLayeredPane getLayeredPane() { |
|
return getRootPane().getLayeredPane(); |
|
} |
|
|
|
@Override |
|
public void setGlassPane(Component glassPane) { |
|
getRootPane().setGlassPane(glassPane); |
|
} |
|
|
|
@Override |
|
public Component getGlassPane() { |
|
return getRootPane().getGlassPane(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private void updateClientCursor() { |
|
Point p = MouseInfo.getPointerInfo().getLocation(); |
|
SwingUtilities.convertPointFromScreen(p, this); |
|
Component target = SwingUtilities.getDeepestComponentAt(this, p.x, p.y); |
|
if (target != null) { |
|
content.setCursor(target.getCursor()); |
|
} |
|
} |
|
|
|
|
|
public void overrideNativeWindowHandle(long handle, Runnable closeWindow) { |
|
final Object peer = AWTAccessor.getComponentAccessor().getPeer(this); |
|
if (peer instanceof OverrideNativeWindowHandle) { |
|
((OverrideNativeWindowHandle) peer).overrideWindowHandle(handle); |
|
} |
|
if (closeWindow != null) { |
|
closeWindow.run(); |
|
} |
|
} |
|
|
|
public <T extends DragGestureRecognizer> T createDragGestureRecognizer( |
|
Class<T> abstractRecognizerClass, |
|
DragSource ds, Component c, int srcActions, |
|
DragGestureListener dgl) |
|
{ |
|
return content == null ? null : content.createDragGestureRecognizer( |
|
abstractRecognizerClass, ds, c, srcActions, dgl); |
|
} |
|
|
|
public DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent dge) throws InvalidDnDOperationException { |
|
return content == null ? null : content.createDragSourceContextPeer(dge); |
|
} |
|
|
|
public void addDropTarget(DropTarget dt) { |
|
if (content == null) return; |
|
content.addDropTarget(dt); |
|
} |
|
|
|
public void removeDropTarget(DropTarget dt) { |
|
if (content == null) return; |
|
content.removeDropTarget(dt); |
|
} |
|
} |