Path: blob/master/src/java.desktop/macosx/classes/sun/lwawt/LWComponentPeer.java
41153 views
/*1* Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.lwawt;2627import java.awt.AWTEvent;28import java.awt.AWTException;29import java.awt.BufferCapabilities;30import java.awt.Color;31import java.awt.Component;32import java.awt.Container;33import java.awt.Cursor;34import java.awt.Dimension;35import java.awt.Font;36import java.awt.FontMetrics;37import java.awt.Graphics;38import java.awt.GraphicsConfiguration;39import java.awt.Image;40import java.awt.Point;41import java.awt.Rectangle;42import java.awt.Toolkit;43import java.awt.Window;44import java.awt.dnd.DropTarget;45import java.awt.dnd.peer.DropTargetPeer;46import java.awt.event.AWTEventListener;47import java.awt.event.ComponentEvent;48import java.awt.event.FocusEvent;49import java.awt.event.InputEvent;50import java.awt.event.KeyEvent;51import java.awt.event.MouseEvent;52import java.awt.event.MouseWheelEvent;53import java.awt.event.PaintEvent;54import java.awt.image.ColorModel;55import java.awt.image.VolatileImage;56import java.awt.peer.ComponentPeer;57import java.awt.peer.ContainerPeer;58import java.awt.peer.KeyboardFocusManagerPeer;59import java.lang.reflect.Field;60import java.security.AccessController;61import java.security.PrivilegedAction;62import java.util.concurrent.atomic.AtomicBoolean;6364import javax.swing.JComponent;65import javax.swing.RepaintManager;66import javax.swing.SwingUtilities;6768import com.sun.java.swing.SwingUtilities3;69import sun.awt.AWTAccessor;70import sun.awt.CGraphicsDevice;71import sun.awt.PaintEventDispatcher;72import sun.awt.RepaintArea;73import sun.awt.SunToolkit;74import sun.awt.event.IgnorePaintEvent;75import sun.awt.image.SunVolatileImage;76import sun.java2d.SunGraphics2D;77import sun.java2d.metal.MTLRenderQueue;78import sun.java2d.opengl.OGLRenderQueue;79import sun.java2d.pipe.Region;80import sun.java2d.pipe.RenderQueue;81import sun.util.logging.PlatformLogger;8283public abstract class LWComponentPeer<T extends Component, D extends JComponent>84implements ComponentPeer, DropTargetPeer85{86private static final PlatformLogger focusLog = PlatformLogger.getLogger("sun.lwawt.focus.LWComponentPeer");8788/**89* State lock is to be used for modifications to this peer's fields (e.g.90* bounds, background, font, etc.) It should be the last lock in the lock91* chain92*/93private final Object stateLock = new Object();9495/**96* The lock to operate with the peers hierarchy. AWT tree lock is not used97* as there are many peers related ops to be done on the toolkit thread, and98* we don't want to depend on a public lock on this thread99*/100private static final Object peerTreeLock = new Object();101102/**103* The associated AWT object.104*/105private final T target;106107/**108* Container peer. It may not be the peer of the target's direct parent, for109* example, in the case of hw/lw mixing. However, let's skip this scenario110* for the time being. We also assume the container peer is not null, which111* might also be false if addNotify() is called for a component outside of112* the hierarchy. The exception is LWWindowPeers: their containers are113* always null114*/115private final LWContainerPeer<?, ?> containerPeer;116117/**118* Handy reference to the top-level window peer. Window peer is borrowed119* from the containerPeer in constructor, and should also be updated when120* the component is reparented to another container121*/122private final LWWindowPeer windowPeer;123124private final AtomicBoolean disposed = new AtomicBoolean(false);125126// Bounds are relative to parent peer127private final Rectangle bounds = new Rectangle();128private Region region;129130// Component state. Should be accessed under the state lock131private boolean visible = false;132private boolean enabled = true;133134private Color background;135private Color foreground;136private Font font;137138/**139* Paint area to coalesce all the paint events and store the target dirty140* area.141*/142private final RepaintArea targetPaintArea;143144// private volatile boolean paintPending;145private volatile boolean isLayouting;146147private final D delegate;148private Container delegateContainer;149private Component delegateDropTarget;150private final Object dropTargetLock = new Object();151152private int fNumDropTargets = 0;153private PlatformDropTarget fDropTarget = null;154155private final PlatformComponent platformComponent;156157/**158* Character with reasonable value between the minimum width and maximum.159*/160static final char WIDE_CHAR = '0';161162/**163* The back buffer provide user with a BufferStrategy.164*/165private Image backBuffer;166167/**168* All Swing delegates use delegateContainer as a parent. This container169* intentionally do not use parent of the peer.170*/171@SuppressWarnings("serial")// Safe: outer class is non-serializable.172private final class DelegateContainer extends Container {173{174enableEvents(0xFFFFFFFF);175}176177@Override178public boolean isLightweight() {179return false;180}181182@Override183public Point getLocation() {184return getLocationOnScreen();185}186187@Override188public Point getLocationOnScreen() {189return LWComponentPeer.this.getLocationOnScreen();190}191192@Override193public int getX() {194return getLocation().x;195}196197@Override198public int getY() {199return getLocation().y;200}201}202203LWComponentPeer(final T target, final PlatformComponent platformComponent) {204targetPaintArea = new LWRepaintArea();205this.target = target;206this.platformComponent = platformComponent;207208// Container peer is always null for LWWindowPeers, so209// windowPeer is always null for them as well. On the other210// hand, LWWindowPeer shouldn't use windowPeer at all211final Container container = SunToolkit.getNativeContainer(target);212containerPeer = (LWContainerPeer) LWToolkit.targetToPeer(container);213windowPeer = containerPeer != null ? containerPeer.getWindowPeerOrSelf()214: null;215// don't bother about z-order here as updateZOrder()216// will be called from addNotify() later anyway217if (containerPeer != null) {218containerPeer.addChildPeer(this);219}220221// the delegate must be created after the target is set222AWTEventListener toolkitListener = null;223synchronized (Toolkit.getDefaultToolkit()) {224try {225toolkitListener = getToolkitAWTEventListener();226setToolkitAWTEventListener(null);227228synchronized (getDelegateLock()) {229delegate = createDelegate();230if (delegate != null) {231delegate.setVisible(false);232delegateContainer = new DelegateContainer();233delegateContainer.add(delegate);234delegateContainer.addNotify();235delegate.addNotify();236resetColorsAndFont(delegate);237delegate.setOpaque(true);238} else {239return;240}241}242243} finally {244setToolkitAWTEventListener(toolkitListener);245}246247// todo swing: later on we will probably have one global RM248SwingUtilities3.setDelegateRepaintManager(delegate, new RepaintManager() {249@Override250public void addDirtyRegion(final JComponent c, final int x, final int y, final int w, final int h) {251repaintPeer(SwingUtilities.convertRectangle(252c, new Rectangle(x, y, w, h), getDelegate()));253}254});255}256}257258/**259* This method must be called under Toolkit.getDefaultToolkit() lock260* and followed by setToolkitAWTEventListener()261*/262@SuppressWarnings("removal")263protected final AWTEventListener getToolkitAWTEventListener() {264return AccessController.doPrivileged(new PrivilegedAction<AWTEventListener>() {265public AWTEventListener run() {266Toolkit toolkit = Toolkit.getDefaultToolkit();267try {268Field field = Toolkit.class.getDeclaredField("eventListener");269field.setAccessible(true);270return (AWTEventListener) field.get(toolkit);271} catch (Exception e) {272throw new InternalError(e.toString());273}274}275});276}277278@SuppressWarnings("removal")279protected final void setToolkitAWTEventListener(final AWTEventListener listener) {280AccessController.doPrivileged(new PrivilegedAction<Void>() {281public Void run() {282Toolkit toolkit = Toolkit.getDefaultToolkit();283try {284Field field = Toolkit.class.getDeclaredField("eventListener");285field.setAccessible(true);286field.set(toolkit, listener);287} catch (Exception e) {288throw new InternalError(e.toString());289}290return null;291}292});293}294295/**296* This method is called under getDelegateLock().297* Overridden in subclasses.298*/299D createDelegate() {300return null;301}302303final D getDelegate() {304return delegate;305}306307/**308* This method should be called under getDelegateLock().309*/310Component getDelegateFocusOwner() {311return getDelegate();312}313314/**315* Initializes this peer. The call to initialize() is not placed to316* LWComponentPeer ctor to let the subclass ctor to finish completely first.317* Instead, it's the LWToolkit object who is responsible for initialization.318* Note that we call setVisible() at the end of initialization.319*/320public final void initialize() {321platformComponent.initialize(getPlatformWindow());322initializeImpl();323setVisible(target.isVisible());324}325326/**327* Fetching general properties from the target. Should be overridden in328* subclasses to initialize specific peers properties.329*/330void initializeImpl() {331// note that these methods can be overridden by the user and332// can return some strange values like null.333setBackground(target.getBackground());334setForeground(target.getForeground());335setFont(target.getFont());336setBounds(target.getBounds());337setEnabled(target.isEnabled());338}339340private static void resetColorsAndFont(final Container c) {341c.setBackground(null);342c.setForeground(null);343c.setFont(null);344for (int i = 0; i < c.getComponentCount(); i++) {345resetColorsAndFont((Container) c.getComponent(i));346}347}348349final Object getStateLock() {350return stateLock;351}352353/**354* Synchronize all operations with the Swing delegates under AWT tree lock,355* using a new separate lock to synchronize access to delegates may lead356* deadlocks. Think of it as a 'virtual EDT'.357*358* @return DelegateLock359*/360final Object getDelegateLock() {361return getTarget().getTreeLock();362}363364protected static final Object getPeerTreeLock() {365return peerTreeLock;366}367368public final T getTarget() {369return target;370}371372// Just a helper method373// Returns the window peer or null if this is a window peer374protected final LWWindowPeer getWindowPeer() {375return windowPeer;376}377378// Returns the window peer or 'this' if this is a window peer379protected LWWindowPeer getWindowPeerOrSelf() {380return getWindowPeer();381}382383// Just a helper method384protected final LWContainerPeer<?, ?> getContainerPeer() {385return containerPeer;386}387388public PlatformWindow getPlatformWindow() {389LWWindowPeer windowPeer = getWindowPeer();390return windowPeer.getPlatformWindow();391}392393// ---- PEER METHODS ---- //394395// Just a helper method396public LWToolkit getLWToolkit() {397return LWToolkit.getLWToolkit();398}399400@Override401public final void dispose() {402if (disposed.compareAndSet(false, true)) {403disposeImpl();404}405}406407protected void disposeImpl() {408destroyBuffers();409LWContainerPeer<?, ?> cp = getContainerPeer();410if (cp != null) {411cp.removeChildPeer(this);412}413platformComponent.dispose();414LWToolkit.targetDisposedPeer(getTarget(), this);415}416417public final boolean isDisposed() {418return disposed.get();419}420421/*422* GraphicsConfiguration is borrowed from the parent peer. The423* return value must not be null.424*425* Overridden in LWWindowPeer.426*/427@Override428public GraphicsConfiguration getGraphicsConfiguration() {429// Don't check windowPeer for null as it can only happen430// for windows, but this method is overridden in431// LWWindowPeer and doesn't call super()432return getWindowPeer().getGraphicsConfiguration();433}434435436// Just a helper method437public final LWGraphicsConfig getLWGC() {438return (LWGraphicsConfig) getGraphicsConfiguration();439}440441/*442* Overridden in LWWindowPeer to replace its surface443* data and back buffer.444*/445@Override446public boolean updateGraphicsData(GraphicsConfiguration gc) {447// TODO: not implemented448// throw new RuntimeException("Has not been implemented yet.");449return false;450}451452@Override453public Graphics getGraphics() {454final Graphics g = getOnscreenGraphics();455if (g != null) {456synchronized (getPeerTreeLock()){457applyConstrain(g);458}459}460return g;461}462463/*464* Peer Graphics is borrowed from the parent peer, while465* foreground and background colors and font are specific to466* this peer.467*/468public final Graphics getOnscreenGraphics() {469final LWWindowPeer wp = getWindowPeerOrSelf();470return wp.getOnscreenGraphics(getForeground(), getBackground(),471getFont());472473}474475private void applyConstrain(final Graphics g) {476final SunGraphics2D sg2d = (SunGraphics2D) g;477final Rectangle size = localToWindow(getSize());478sg2d.constrain(size.x, size.y, size.width, size.height, getVisibleRegion());479}480481Region getVisibleRegion() {482return computeVisibleRect(this, getRegion());483}484485static final Region computeVisibleRect(final LWComponentPeer<?, ?> c,486Region region) {487final LWContainerPeer<?, ?> p = c.getContainerPeer();488if (p != null) {489final Rectangle r = c.getBounds();490region = region.getTranslatedRegion(r.x, r.y);491region = region.getIntersection(p.getRegion());492region = region.getIntersection(p.getContentSize());493region = p.cutChildren(region, c);494region = computeVisibleRect(p, region);495region = region.getTranslatedRegion(-r.x, -r.y);496}497return region;498}499500@Override501public ColorModel getColorModel() {502// Is it a correct implementation?503return getGraphicsConfiguration().getColorModel();504}505506public boolean isTranslucent() {507// Translucent windows of the top level are supported only508return false;509}510511@Override512public final void createBuffers(int numBuffers, BufferCapabilities caps)513throws AWTException {514getLWGC().assertOperationSupported(numBuffers, caps);515final Image buffer = getLWGC().createBackBuffer(this);516synchronized (getStateLock()) {517backBuffer = buffer;518}519}520521@Override522public final Image getBackBuffer() {523synchronized (getStateLock()) {524if (backBuffer != null) {525return backBuffer;526}527}528throw new IllegalStateException("Buffers have not been created");529}530531@Override532public final void flip(int x1, int y1, int x2, int y2,533BufferCapabilities.FlipContents flipAction) {534getLWGC().flip(this, getBackBuffer(), x1, y1, x2, y2, flipAction);535}536537@Override538public final void destroyBuffers() {539final Image oldBB;540synchronized (getStateLock()) {541oldBB = backBuffer;542backBuffer = null;543}544getLWGC().destroyBackBuffer(oldBB);545}546547// Helper method548public void setBounds(Rectangle r) {549setBounds(r.x, r.y, r.width, r.height, SET_BOUNDS);550}551552/**553* This method could be called on the toolkit thread.554*/555@Override556public void setBounds(int x, int y, int w, int h, int op) {557setBounds(x, y, w, h, op, true, false);558}559560protected void setBounds(int x, int y, int w, int h, int op, boolean notify,561final boolean updateTarget) {562Rectangle oldBounds;563synchronized (getStateLock()) {564oldBounds = new Rectangle(bounds);565if ((op & (SET_LOCATION | SET_BOUNDS)) != 0) {566bounds.x = x;567bounds.y = y;568}569if ((op & (SET_SIZE | SET_BOUNDS)) != 0) {570bounds.width = w;571bounds.height = h;572}573}574boolean moved = (oldBounds.x != x) || (oldBounds.y != y);575boolean resized = (oldBounds.width != w) || (oldBounds.height != h);576if (!moved && !resized) {577return;578}579final D delegate = getDelegate();580if (delegate != null) {581synchronized (getDelegateLock()) {582delegateContainer.setBounds(0, 0, w, h);583delegate.setBounds(delegateContainer.getBounds());584// TODO: the following means that the delegateContainer NEVER gets validated. That's WRONG!585delegate.validate();586}587}588589final Point locationInWindow = localToWindow(0, 0);590platformComponent.setBounds(locationInWindow.x, locationInWindow.y, w,591h);592if (notify) {593repaintOldNewBounds(oldBounds);594if (resized) {595handleResize(w, h, updateTarget);596}597if (moved) {598handleMove(x, y, updateTarget);599}600}601}602603public final Rectangle getBounds() {604synchronized (getStateLock()) {605// Return a copy to prevent subsequent modifications606return bounds.getBounds();607}608}609610public final Rectangle getSize() {611synchronized (getStateLock()) {612// Return a copy to prevent subsequent modifications613return new Rectangle(bounds.width, bounds.height);614}615}616617@Override618public Point getLocationOnScreen() {619Point windowLocation = getWindowPeer().getLocationOnScreen();620Point locationInWindow = localToWindow(0, 0);621return new Point(windowLocation.x + locationInWindow.x,622windowLocation.y + locationInWindow.y);623}624625/**626* Returns the cursor of the peer, which is cursor of the target by default,627* but peer can override this behavior.628*629* @param p Point relative to the peer.630* @return Cursor of the peer or null if default cursor should be used.631*/632Cursor getCursor(final Point p) {633return getTarget().getCursor();634}635636@Override637public void setBackground(final Color c) {638final Color oldBg = getBackground();639if (oldBg == c || (oldBg != null && oldBg.equals(c))) {640return;641}642synchronized (getStateLock()) {643background = c;644}645final D delegate = getDelegate();646if (delegate != null) {647synchronized (getDelegateLock()) {648// delegate will repaint the target649delegate.setBackground(c);650}651} else {652repaintPeer();653}654}655656public final Color getBackground() {657synchronized (getStateLock()) {658return background;659}660}661662@Override663public void setForeground(final Color c) {664final Color oldFg = getForeground();665if (oldFg == c || (oldFg != null && oldFg.equals(c))) {666return;667}668synchronized (getStateLock()) {669foreground = c;670}671final D delegate = getDelegate();672if (delegate != null) {673synchronized (getDelegateLock()) {674// delegate will repaint the target675delegate.setForeground(c);676}677} else {678repaintPeer();679}680}681682protected final Color getForeground() {683synchronized (getStateLock()) {684return foreground;685}686}687688@Override689public void setFont(final Font f) {690final Font oldF = getFont();691if (oldF == f || (oldF != null && oldF.equals(f))) {692return;693}694synchronized (getStateLock()) {695font = f;696}697final D delegate = getDelegate();698if (delegate != null) {699synchronized (getDelegateLock()) {700// delegate will repaint the target701delegate.setFont(f);702}703} else {704repaintPeer();705}706}707708protected final Font getFont() {709synchronized (getStateLock()) {710return font;711}712}713714@Override715public FontMetrics getFontMetrics(final Font f) {716// Borrow the metrics from the top-level window717// return getWindowPeer().getFontMetrics(f);718// Obtain the metrics from the offscreen window where this peer is719// mostly drawn to.720// TODO: check for "use platform metrics" settings721final Graphics g = getOnscreenGraphics();722if (g != null) {723try {724return g.getFontMetrics(f);725} finally {726g.dispose();727}728}729synchronized (getDelegateLock()) {730return delegateContainer.getFontMetrics(f);731}732}733734@Override735public void setEnabled(final boolean e) {736boolean status = e;737final LWComponentPeer<?, ?> cp = getContainerPeer();738if (cp != null) {739status &= cp.isEnabled();740}741synchronized (getStateLock()) {742if (enabled == status) {743return;744}745enabled = status;746}747748final D delegate = getDelegate();749750if (delegate != null) {751synchronized (getDelegateLock()) {752delegate.setEnabled(status);753}754} else {755repaintPeer();756}757}758759// Helper method760public final boolean isEnabled() {761synchronized (getStateLock()) {762return enabled;763}764}765766@Override767public void setVisible(final boolean v) {768synchronized (getStateLock()) {769if (visible == v) {770return;771}772visible = v;773}774setVisibleImpl(v);775}776777protected void setVisibleImpl(final boolean v) {778final D delegate = getDelegate();779780if (delegate != null) {781synchronized (getDelegateLock()) {782delegate.setVisible(v);783}784}785if (visible) {786repaintPeer();787} else {788repaintParent(getBounds());789}790}791792// Helper method793public final boolean isVisible() {794synchronized (getStateLock()) {795return visible;796}797}798799@Override800public void paint(final Graphics g) {801getTarget().paint(g);802}803804@Override805public void print(final Graphics g) {806getTarget().print(g);807}808809@Override810public void reparent(ContainerPeer newContainer) {811// TODO: not implemented812throw new UnsupportedOperationException("ComponentPeer.reparent()");813}814815@Override816public boolean isReparentSupported() {817// TODO: not implemented818return false;819}820821@Override822public void setZOrder(final ComponentPeer above) {823LWContainerPeer<?, ?> cp = getContainerPeer();824// Don't check containerPeer for null as it can only happen825// for windows, but this method is overridden in826// LWWindowPeer and doesn't call super()827cp.setChildPeerZOrder(this, (LWComponentPeer<?, ?>) above);828}829830@Override831public void coalescePaintEvent(PaintEvent e) {832if (!(e instanceof IgnorePaintEvent)) {833Rectangle r = e.getUpdateRect();834if ((r != null) && !r.isEmpty()) {835targetPaintArea.add(r, e.getID());836}837}838}839840/*841* Should be overridden in subclasses which use complex Swing components.842*/843@Override844public void layout() {845// TODO: not implemented846}847848@Override849public boolean isObscured() {850// TODO: not implemented851return false;852}853854@Override855public boolean canDetermineObscurity() {856// TODO: not implemented857return false;858}859860/**861* Determines the preferred size of the component. By default forwards the862* request to the Swing helper component. Should be overridden in subclasses863* if required.864*/865@Override866public Dimension getPreferredSize() {867final Dimension size;868synchronized (getDelegateLock()) {869size = getDelegate().getPreferredSize();870}871return validateSize(size);872}873874/**875* Determines the minimum size of the component. By default forwards the876* request to the Swing helper component. Should be overridden in subclasses877* if required.878*/879@Override880public Dimension getMinimumSize() {881final Dimension size;882synchronized (getDelegateLock()) {883size = getDelegate().getMinimumSize();884}885return validateSize(size);886}887888/**889* In some situations delegates can return empty minimum/preferred size.890* (For example: empty JLabel, etc), but awt components never should be891* empty. In the XPeers or WPeers we use some magic constants, but here we892* try to use something more useful,893*/894private Dimension validateSize(final Dimension size) {895if (size.width == 0 || size.height == 0) {896final FontMetrics fm = getFontMetrics(getFont());897size.width = fm.charWidth(WIDE_CHAR);898size.height = fm.getHeight();899}900return size;901}902903@Override904public void updateCursorImmediately() {905getLWToolkit().getCursorManager().updateCursor();906}907908@Override909public boolean isFocusable() {910// Overridden in focusable subclasses like buttons911return false;912}913914@Override915public boolean requestFocus(Component lightweightChild, boolean temporary,916boolean focusedWindowChangeAllowed, long time,917FocusEvent.Cause cause)918{919if (focusLog.isLoggable(PlatformLogger.Level.FINEST)) {920focusLog.finest("lightweightChild=" + lightweightChild + ", temporary=" + temporary +921", focusedWindowChangeAllowed=" + focusedWindowChangeAllowed +922", time= " + time + ", cause=" + cause);923}924if (LWKeyboardFocusManagerPeer.processSynchronousLightweightTransfer(925getTarget(), lightweightChild, temporary,926focusedWindowChangeAllowed, time)) {927return true;928}929930int result = LWKeyboardFocusManagerPeer.shouldNativelyFocusHeavyweight(931getTarget(), lightweightChild, temporary,932focusedWindowChangeAllowed, time, cause);933switch (result) {934case LWKeyboardFocusManagerPeer.SNFH_FAILURE:935return false;936case LWKeyboardFocusManagerPeer.SNFH_SUCCESS_PROCEED:937Window parentWindow = SunToolkit.getContainingWindow(getTarget());938if (parentWindow == null) {939focusLog.fine("request rejected, parentWindow is null");940LWKeyboardFocusManagerPeer.removeLastFocusRequest(getTarget());941return false;942}943final LWWindowPeer parentPeer =944AWTAccessor.getComponentAccessor()945.getPeer(parentWindow);946if (parentPeer == null) {947focusLog.fine("request rejected, parentPeer is null");948LWKeyboardFocusManagerPeer.removeLastFocusRequest(getTarget());949return false;950}951952// A fix for 7145768. Ensure the parent window is currently natively focused.953// The more evident place to perform this check is in KFM.shouldNativelyFocusHeavyweight,954// however that is the shared code and this particular problem's reproducibility has955// platform specifics. So, it was decided to narrow down the fix to lwawt (OSX) in956// current release. TODO: consider fixing it in the shared code.957if (!focusedWindowChangeAllowed) {958LWWindowPeer decoratedPeer = parentPeer.isSimpleWindow() ?959LWWindowPeer.getOwnerFrameDialog(parentPeer) : parentPeer;960961if (decoratedPeer == null || !decoratedPeer.getPlatformWindow().isActive()) {962if (focusLog.isLoggable(PlatformLogger.Level.FINE)) {963focusLog.fine("request rejected, focusedWindowChangeAllowed==false, " +964"decoratedPeer is inactive: " + decoratedPeer);965}966LWKeyboardFocusManagerPeer.removeLastFocusRequest(getTarget());967return false;968}969}970971boolean res = parentPeer.requestWindowFocus(cause);972// If parent window can be made focused and has been made focused (synchronously)973// then we can proceed with children, otherwise we retreat974if (!res || !parentWindow.isFocused()) {975if (focusLog.isLoggable(PlatformLogger.Level.FINE)) {976focusLog.fine("request rejected, res= " + res + ", parentWindow.isFocused()=" +977parentWindow.isFocused());978}979LWKeyboardFocusManagerPeer.removeLastFocusRequest(getTarget());980return false;981}982983KeyboardFocusManagerPeer kfmPeer = LWKeyboardFocusManagerPeer.getInstance();984Component focusOwner = kfmPeer.getCurrentFocusOwner();985return LWKeyboardFocusManagerPeer.deliverFocus(lightweightChild,986getTarget(), temporary,987focusedWindowChangeAllowed,988time, cause, focusOwner);989990case LWKeyboardFocusManagerPeer.SNFH_SUCCESS_HANDLED:991return true;992}993994return false;995}996997@Override998public final Image createImage(final int width, final int height) {999return getLWGC().createAcceleratedImage(getTarget(), width, height);1000}10011002@Override1003public final VolatileImage createVolatileImage(final int w, final int h) {1004return new SunVolatileImage(getTarget(), w, h);1005}10061007@Override1008public boolean handlesWheelScrolling() {1009// TODO: not implemented1010return false;1011}10121013@Override1014public final void applyShape(final Region shape) {1015synchronized (getStateLock()) {1016if (region == shape || (region != null && region.equals(shape))) {1017return;1018}1019}1020applyShapeImpl(shape);1021}10221023void applyShapeImpl(final Region shape) {1024synchronized (getStateLock()) {1025if (shape != null) {1026region = Region.WHOLE_REGION.getIntersection(shape);1027} else {1028region = null;1029}1030}1031repaintParent(getBounds());1032}10331034protected final Region getRegion() {1035synchronized (getStateLock()) {1036return isShaped() ? region : Region.getInstance(getSize());1037}1038}10391040public boolean isShaped() {1041synchronized (getStateLock()) {1042return region != null;1043}1044}10451046// DropTargetPeer Method1047@Override1048public void addDropTarget(DropTarget dt) {1049LWWindowPeer winPeer = getWindowPeerOrSelf();1050if (winPeer != null && winPeer != this) {1051// We need to register the DropTarget in the1052// peer of the window ancestor of the component1053winPeer.addDropTarget(dt);1054} else {1055synchronized (dropTargetLock) {1056// 10-14-02 VL: Windows WComponentPeer would add (or remove) the drop target only1057// if it's the first (or last) one for the component. Otherwise this call is a no-op.1058if (++fNumDropTargets == 1) {1059// Having a non-null drop target would be an error but let's check just in case:1060if (fDropTarget != null) {1061throw new IllegalStateException("Current drop target is not null");1062}1063// Create a new drop target:1064fDropTarget = LWToolkit.getLWToolkit().createDropTarget(dt, target, this);1065}1066}1067}1068}10691070// DropTargetPeer Method1071@Override1072public void removeDropTarget(DropTarget dt) {1073LWWindowPeer winPeer = getWindowPeerOrSelf();1074if (winPeer != null && winPeer != this) {1075// We need to unregister the DropTarget in the1076// peer of the window ancestor of the component1077winPeer.removeDropTarget(dt);1078} else {1079synchronized (dropTargetLock){1080// 10-14-02 VL: Windows WComponentPeer would add (or remove) the drop target only1081// if it's the first (or last) one for the component. Otherwise this call is a no-op.1082if (--fNumDropTargets == 0) {1083// Having a null drop target would be an error but let's check just in case:1084if (fDropTarget != null) {1085// Dispose of the drop target:1086fDropTarget.dispose();1087fDropTarget = null;1088} else1089System.err.println("CComponent.removeDropTarget(): current drop target is null.");1090}1091}1092}1093}10941095// ---- PEER NOTIFICATIONS ---- //10961097/**1098* Called when this peer's location has been changed either as a result1099* of target.setLocation() or as a result of user actions (window is1100* dragged with mouse).1101*1102* This method could be called on the toolkit thread.1103*/1104protected final void handleMove(final int x, final int y,1105final boolean updateTarget) {1106if (updateTarget) {1107AWTAccessor.getComponentAccessor().setLocation(getTarget(), x, y);1108postEvent(new ComponentEvent(getTarget(),1109ComponentEvent.COMPONENT_MOVED));1110}1111}11121113/**1114* Called when this peer's size has been changed either as a result of1115* target.setSize() or as a result of user actions (window is resized).1116*1117* This method could be called on the toolkit thread.1118*/1119protected final void handleResize(final int w, final int h,1120final boolean updateTarget) {1121Image oldBB = null;1122synchronized (getStateLock()) {1123if (backBuffer != null) {1124oldBB = backBuffer;1125backBuffer = getLWGC().createBackBuffer(this);1126}1127}1128getLWGC().destroyBackBuffer(oldBB);11291130if (updateTarget) {1131AWTAccessor.getComponentAccessor().setSize(getTarget(), w, h);1132postEvent(new ComponentEvent(getTarget(),1133ComponentEvent.COMPONENT_RESIZED));1134}1135}11361137protected final void repaintOldNewBounds(final Rectangle oldB) {1138repaintParent(oldB);1139repaintPeer(getSize());1140}11411142protected final void repaintParent(final Rectangle oldB) {1143final LWContainerPeer<?, ?> cp = getContainerPeer();1144if (cp != null) {1145// Repaint unobscured part of the parent1146cp.repaintPeer(cp.getContentSize().intersection(oldB));1147}1148}11491150// ---- EVENTS ---- //11511152/**1153* Post an event to the proper Java EDT.1154*/1155public void postEvent(final AWTEvent event) {1156LWToolkit.postEvent(event);1157}11581159protected void postPaintEvent(int x, int y, int w, int h) {1160// TODO: call getIgnoreRepaint() directly with the right ACC1161if (AWTAccessor.getComponentAccessor().getIgnoreRepaint(target)) {1162return;1163}1164PaintEvent event = PaintEventDispatcher.getPaintEventDispatcher().1165createPaintEvent(getTarget(), x, y, w, h);1166if (event != null) {1167postEvent(event);1168}1169}11701171/*1172* Gives a chance for the peer to handle the event after it's been1173* processed by the target.1174*/1175@Override1176public void handleEvent(AWTEvent e) {1177if ((e instanceof InputEvent) && ((InputEvent) e).isConsumed()) {1178return;1179}1180switch (e.getID()) {1181case FocusEvent.FOCUS_GAINED:1182case FocusEvent.FOCUS_LOST:1183handleJavaFocusEvent((FocusEvent) e);1184break;1185case PaintEvent.PAINT:1186// Got a native paint event1187// paintPending = false;1188// fall through to the next statement1189case PaintEvent.UPDATE:1190handleJavaPaintEvent();1191break;1192case MouseEvent.MOUSE_PRESSED:1193handleJavaMouseEvent((MouseEvent)e);1194}11951196sendEventToDelegate(e);1197}11981199protected void sendEventToDelegate(final AWTEvent e) {1200if (getDelegate() == null || !isShowing() || !isEnabled()) {1201return;1202}1203synchronized (getDelegateLock()) {1204AWTEvent delegateEvent = createDelegateEvent(e);1205if (delegateEvent != null) {1206AWTAccessor.getComponentAccessor()1207.processEvent((Component) delegateEvent.getSource(),1208delegateEvent);1209if (delegateEvent instanceof KeyEvent) {1210KeyEvent ke = (KeyEvent) delegateEvent;1211SwingUtilities.processKeyBindings(ke);1212}1213}1214}1215}12161217/**1218* Changes the target of the AWTEvent from awt component to appropriate1219* swing delegate.1220*/1221@SuppressWarnings("deprecation")1222private AWTEvent createDelegateEvent(final AWTEvent e) {1223// TODO modifiers should be changed to getModifiers()|getModifiersEx()?1224AWTEvent delegateEvent = null;1225if (e instanceof MouseWheelEvent) {1226MouseWheelEvent me = (MouseWheelEvent) e;1227delegateEvent = new MouseWheelEvent(1228delegate, me.getID(), me.getWhen(),1229me.getModifiers(),1230me.getX(), me.getY(),1231me.getXOnScreen(), me.getYOnScreen(),1232me.getClickCount(),1233me.isPopupTrigger(),1234me.getScrollType(),1235me.getScrollAmount(),1236me.getWheelRotation(),1237me.getPreciseWheelRotation());1238} else if (e instanceof MouseEvent) {1239MouseEvent me = (MouseEvent) e;12401241Component eventTarget = SwingUtilities.getDeepestComponentAt(delegate, me.getX(), me.getY());12421243if (me.getID() == MouseEvent.MOUSE_DRAGGED) {1244if (delegateDropTarget == null) {1245delegateDropTarget = eventTarget;1246} else {1247eventTarget = delegateDropTarget;1248}1249}1250if (me.getID() == MouseEvent.MOUSE_RELEASED && delegateDropTarget != null) {1251eventTarget = delegateDropTarget;1252delegateDropTarget = null;1253}1254if (eventTarget == null) {1255eventTarget = delegate;1256}1257delegateEvent = SwingUtilities.convertMouseEvent(getTarget(), me, eventTarget);1258} else if (e instanceof KeyEvent) {1259KeyEvent ke = (KeyEvent) e;1260delegateEvent = new KeyEvent(getDelegateFocusOwner(), ke.getID(), ke.getWhen(),1261ke.getModifiers(), ke.getKeyCode(), ke.getKeyChar(), ke.getKeyLocation());1262AWTAccessor.getKeyEventAccessor().setExtendedKeyCode((KeyEvent) delegateEvent,1263ke.getExtendedKeyCode());1264} else if (e instanceof FocusEvent) {1265FocusEvent fe = (FocusEvent) e;1266delegateEvent = new FocusEvent(getDelegateFocusOwner(), fe.getID(), fe.isTemporary());1267}1268return delegateEvent;1269}12701271protected void handleJavaMouseEvent(MouseEvent e) {1272Component target = getTarget();1273assert (e.getSource() == target);12741275if (!target.isFocusOwner() && LWKeyboardFocusManagerPeer.shouldFocusOnClick(target)) {1276LWKeyboardFocusManagerPeer.requestFocusFor(target, FocusEvent.Cause.MOUSE_EVENT);1277}1278}12791280/**1281* Handler for FocusEvents.1282*/1283void handleJavaFocusEvent(final FocusEvent e) {1284// Note that the peer receives all the FocusEvents from1285// its lightweight children as well1286KeyboardFocusManagerPeer kfmPeer = LWKeyboardFocusManagerPeer.getInstance();1287kfmPeer.setCurrentFocusOwner(e.getID() == FocusEvent.FOCUS_GAINED ? getTarget() : null);1288}12891290/**1291* All peers should clear background before paint.1292*1293* @return false on components that DO NOT require a clearRect() before1294* painting.1295*/1296protected final boolean shouldClearRectBeforePaint() {1297// TODO: sun.awt.noerasebackground1298return true;1299}13001301/**1302* Handler for PAINT and UPDATE PaintEvents.1303*/1304private void handleJavaPaintEvent() {1305// Skip all painting while layouting and all UPDATEs1306// while waiting for native paint1307// if (!isLayouting && !paintPending) {1308if (!isLayouting()) {1309targetPaintArea.paint(getTarget(), shouldClearRectBeforePaint());1310}1311}13121313// ---- UTILITY METHODS ---- //13141315/**1316* Finds a top-most visible component for the given point. The location is1317* specified relative to the peer's parent.1318*/1319LWComponentPeer<?, ?> findPeerAt(final int x, final int y) {1320final Rectangle r = getBounds();1321final Region sh = getRegion();1322final boolean found = isVisible() && sh.contains(x - r.x, y - r.y);1323return found ? this : null;1324}13251326/*1327* Translated the given point in Window coordinates to the point in1328* coordinates local to this component. The given window peer must be1329* the window where this component is in.1330*/1331public Point windowToLocal(int x, int y, LWWindowPeer wp) {1332return windowToLocal(new Point(x, y), wp);1333}13341335public Point windowToLocal(Point p, LWWindowPeer wp) {1336LWComponentPeer<?, ?> cp = this;1337while (cp != wp) {1338Rectangle cpb = cp.getBounds();1339p.x -= cpb.x;1340p.y -= cpb.y;1341cp = cp.getContainerPeer();1342}1343// Return a copy to prevent subsequent modifications1344return new Point(p);1345}13461347public Rectangle windowToLocal(Rectangle r, LWWindowPeer wp) {1348Point p = windowToLocal(r.getLocation(), wp);1349return new Rectangle(p, r.getSize());1350}13511352public Point localToWindow(int x, int y) {1353return localToWindow(new Point(x, y));1354}13551356public Point localToWindow(Point p) {1357LWComponentPeer<?, ?> cp = getContainerPeer();1358Rectangle r = getBounds();1359while (cp != null) {1360p.x += r.x;1361p.y += r.y;1362r = cp.getBounds();1363cp = cp.getContainerPeer();1364}1365// Return a copy to prevent subsequent modifications1366return new Point(p);1367}13681369public Rectangle localToWindow(Rectangle r) {1370Point p = localToWindow(r.getLocation());1371return new Rectangle(p, r.getSize());1372}13731374public final void repaintPeer() {1375repaintPeer(getSize());1376}13771378void repaintPeer(final Rectangle r) {1379final Rectangle toPaint = getSize().intersection(r);1380if (!isShowing() || toPaint.isEmpty()) {1381return;1382}13831384postPaintEvent(toPaint.x, toPaint.y, toPaint.width, toPaint.height);1385}13861387/**1388* Determines whether this peer is showing on screen. This means that the1389* peer must be visible, and it must be in a container that is visible and1390* showing.1391*1392* @see #isVisible()1393*/1394protected final boolean isShowing() {1395synchronized (getPeerTreeLock()) {1396if (isVisible()) {1397final LWContainerPeer<?, ?> container = getContainerPeer();1398return (container == null) || container.isShowing();1399}1400}1401return false;1402}14031404/**1405* Paints the peer. Delegate the actual painting to Swing components.1406*/1407protected final void paintPeer(final Graphics g) {1408final D delegate = getDelegate();1409if (delegate != null) {1410if (!SwingUtilities.isEventDispatchThread()) {1411throw new InternalError("Painting must be done on EDT");1412}1413synchronized (getDelegateLock()) {1414// JComponent.print() is guaranteed to not affect the double buffer1415getDelegate().print(g);1416}1417}1418}14191420protected static final void flushOnscreenGraphics(){1421RenderQueue rq = CGraphicsDevice.usingMetalPipeline() ?1422MTLRenderQueue.getInstance() : OGLRenderQueue.getInstance();1423rq.lock();1424try {1425rq.flushNow();1426} finally {1427rq.unlock();1428}1429}14301431/**1432* Used by ContainerPeer to skip all the paint events during layout.1433*1434* @param isLayouting layouting state.1435*/1436protected final void setLayouting(final boolean isLayouting) {1437this.isLayouting = isLayouting;1438}14391440/**1441* Returns layouting state. Used by ComponentPeer to skip all the paint1442* events during layout.1443*1444* @return true during layout, false otherwise.1445*/1446private boolean isLayouting() {1447return isLayouting;1448}1449}145014511452