/* * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code 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 Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ 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.Rectangle; import java.awt.event.ComponentListener; 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.JLayeredPane; import javax.swing.JPanel; import javax.swing.JRootPane; import javax.swing.LayoutFocusTraversalPolicy; import javax.swing.RootPaneContainer; import sun.awt.LightweightFrame; import sun.security.action.GetPropertyAction; /** * The frame serves as a lightweight container which paints its content * to an offscreen image and provides access to the image's data via the * {@link LightweightContent} interface. Note, that it may not be shown * as a standalone toplevel frame. Its purpose is to provide functionality * for lightweight embedding. * * @author Artem Ananiev * @author Anton Tarasov */ 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; /** * {@code copyBufferEnabled}, true by default, defines the following strategy. * A duplicating (copy) buffer is created for the original pixel buffer. * The copy buffer is synchronized with the original buffer every time the * latter changes. {@code JLightweightFrame} passes the copy buffer array * to the {@link LightweightContent#imageBufferReset} method. The code spot * which synchronizes two buffers becomes the only critical section guarded * by the lock (managed with the {@link LightweightContent#paintLock()}, * {@link LightweightContent#paintUnlock()} methods). */ private boolean copyBufferEnabled; private int[] copyBuffer; private PropertyChangeListener layoutSizeListener; /** * Constructs a new, initially invisible {@code JLightweightFrame} * instance. */ public JLightweightFrame() { super(); copyBufferEnabled = "true".equals(AccessController. doPrivileged(new GetPropertyAction("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); } } }; } /** * Sets the {@link LightweightContent} instance for this frame. * The {@code JComponent} object returned by the * {@link LightweightContent#getComponent()} method is immediately * added to the frame's content pane. * * @param content the {@link LightweightContent} instance */ 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()); return g; } /** * {@inheritDoc} * * @see LightweightContent#focusGrabbed() */ @Override public void grabFocus() { if (content != null) content.focusGrabbed(); } /** * {@inheritDoc} * * @see LightweightContent#focusUngrabbed() */ @Override public void ungrabFocus() { if (content != null) content.focusUngrabbed(); } private void syncCopyBuffer(boolean reset, int x, int y, int w, int h) { content.paintLock(); try { int[] srcBuffer = ((DataBufferInt)bbImage.getRaster().getDataBuffer()).getData(); if (reset) { copyBuffer = new int[srcBuffer.length]; } int linestride = bbImage.getWidth(); for (int i=0; i= 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) { BufferedImage oldBB = bbImage; bbImage = new BufferedImage(newW, newH, BufferedImage.TYPE_INT_ARGB_PRE); if (oldBB != null) { Graphics g = bbImage.getGraphics(); try { g.drawImage(oldBB, 0, 0, newW, newH, null); } finally { g.dispose(); oldBB.flush(); } } int[] pixels = ((DataBufferInt)bbImage.getRaster().getDataBuffer()).getData(); if (copyBufferEnabled) { syncCopyBuffer(true, 0, 0, width, height); pixels = copyBuffer; } content.imageBufferReset(pixels, 0, 0, width, height, bbImage.getWidth()); return; } } content.imageReshaped(0, 0, width, height); } finally { if (!copyBufferEnabled) { content.paintUnlock(); } } } @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(); } }