/* * Copyright (c) 2011, 2015, 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.lwawt; import java.awt.*; import java.awt.List; import java.awt.datatransfer.*; import java.awt.dnd.DropTarget; import java.awt.image.*; import java.awt.peer.*; import java.security.*; import java.util.*; import sun.awt.*; import sun.misc.ManagedLocalsThread; import sun.print.*; import sun.awt.util.ThreadGroupUtils; import static sun.lwawt.LWWindowPeer.PeerType; public abstract class LWToolkit extends SunToolkit implements Runnable { private static final int STATE_NONE = 0; private static final int STATE_INIT = 1; private static final int STATE_MESSAGELOOP = 2; private static final int STATE_SHUTDOWN = 3; private static final int STATE_CLEANUP = 4; private static final int STATE_DONE = 5; private int runState = STATE_NONE; private Clipboard clipboard; private MouseInfoPeer mouseInfoPeer; /** * Dynamic Layout Resize client code setting. */ private volatile boolean dynamicLayoutSetting = true; protected LWToolkit() { } /* * This method is called by subclasses to start this toolkit * by launching the message loop. * * This method waits for the toolkit to be completely initialized * and returns before the message pump is started. */ protected final void init() { AWTAutoShutdown.notifyToolkitThreadBusy(); AccessController.doPrivileged((PrivilegedAction) () -> { Runnable shutdownRunnable = () -> { shutdown(); waitForRunState(STATE_CLEANUP); }; Thread shutdown = new ManagedLocalsThread( ThreadGroupUtils.getRootThreadGroup(), shutdownRunnable); shutdown.setContextClassLoader(null); Runtime.getRuntime().addShutdownHook(shutdown); String name = "AWT-LW"; Thread toolkitThread = new ManagedLocalsThread( ThreadGroupUtils.getRootThreadGroup(), this, name); toolkitThread.setDaemon(true); toolkitThread.setPriority(Thread.NORM_PRIORITY + 1); toolkitThread.start(); return null; }); waitForRunState(STATE_MESSAGELOOP); } /* * Implemented in subclasses to initialize platform-dependent * part of the toolkit (open X display connection, create * toolkit HWND, etc.) * * This method is called on the toolkit thread. */ protected abstract void platformInit(); /* * Sends a request to stop the message pump. */ public final void shutdown() { setRunState(STATE_SHUTDOWN); platformShutdown(); } /* * Implemented in subclasses to release all the platform- * dependent resources. Called after the message loop is * terminated. * * Could be called (always called?) on a non-toolkit thread. */ protected abstract void platformShutdown(); /* * Implemented in subclasses to release all the platform * resources before the application is terminated. * * This method is called on the toolkit thread. */ protected abstract void platformCleanup(); private synchronized int getRunState() { return runState; } private synchronized void setRunState(int state) { runState = state; notifyAll(); } public final boolean isTerminating() { return getRunState() >= STATE_SHUTDOWN; } private void waitForRunState(int state) { while (getRunState() < state) { try { synchronized (this) { wait(); } } catch (InterruptedException z) { // TODO: log break; } } } @Override public final void run() { setRunState(STATE_INIT); platformInit(); AWTAutoShutdown.notifyToolkitThreadFree(); setRunState(STATE_MESSAGELOOP); while (getRunState() < STATE_SHUTDOWN) { try { platformRunMessage(); if (Thread.currentThread().isInterrupted()) { if (AppContext.getAppContext().isDisposed()) { break; } } } catch (ThreadDeath td) { //XXX: if there isn't native code on the stack, the VM just //kills the thread right away. Do we expect to catch it //nevertheless? break; } catch (Throwable t) { // TODO: log System.err.println("Exception on the toolkit thread"); t.printStackTrace(System.err); } } //XXX: if that's a secondary loop, jump back to the STATE_MESSAGELOOP setRunState(STATE_CLEANUP); AWTAutoShutdown.notifyToolkitThreadFree(); platformCleanup(); setRunState(STATE_DONE); } /* * Process the next message(s) from the native event queue. * * Initially, all the LWToolkit implementations were supposed * to have the similar message loop sequence: check if any events * available, peek events, wait. However, the later analysis shown * that X11 and Windows implementations are really different, so * let the subclasses do whatever they require. */ protected abstract void platformRunMessage(); public static LWToolkit getLWToolkit() { return (LWToolkit)Toolkit.getDefaultToolkit(); } // ---- TOPLEVEL PEERS ---- // /* * Note that LWWindowPeer implements WindowPeer, FramePeer * and DialogPeer interfaces. */ protected LWWindowPeer createDelegatedPeer(Window target, PlatformComponent platformComponent, PlatformWindow platformWindow, PeerType peerType) { LWWindowPeer peer = new LWWindowPeer(target, platformComponent, platformWindow, peerType); targetCreatedPeer(target, peer); peer.initialize(); return peer; } @Override public final FramePeer createLightweightFrame(LightweightFrame target) { PlatformComponent platformComponent = createLwPlatformComponent(); PlatformWindow platformWindow = createPlatformWindow(PeerType.LW_FRAME); LWLightweightFramePeer peer = new LWLightweightFramePeer(target, platformComponent, platformWindow); targetCreatedPeer(target, peer); peer.initialize(); return peer; } @Override public final WindowPeer createWindow(Window target) { PlatformComponent platformComponent = createPlatformComponent(); PlatformWindow platformWindow = createPlatformWindow(PeerType.SIMPLEWINDOW); return createDelegatedPeer(target, platformComponent, platformWindow, PeerType.SIMPLEWINDOW); } @Override public final FramePeer createFrame(Frame target) { PlatformComponent platformComponent = createPlatformComponent(); PlatformWindow platformWindow = createPlatformWindow(PeerType.FRAME); return createDelegatedPeer(target, platformComponent, platformWindow, PeerType.FRAME); } @Override public DialogPeer createDialog(Dialog target) { PlatformComponent platformComponent = createPlatformComponent(); PlatformWindow platformWindow = createPlatformWindow(PeerType.DIALOG); return createDelegatedPeer(target, platformComponent, platformWindow, PeerType.DIALOG); } @Override public final FileDialogPeer createFileDialog(FileDialog target) { FileDialogPeer peer = createFileDialogPeer(target); targetCreatedPeer(target, peer); return peer; } // ---- LIGHTWEIGHT COMPONENT PEERS ---- // @Override public final ButtonPeer createButton(Button target) { PlatformComponent platformComponent = createPlatformComponent(); LWButtonPeer peer = new LWButtonPeer(target, platformComponent); targetCreatedPeer(target, peer); peer.initialize(); return peer; } @Override public final CheckboxPeer createCheckbox(Checkbox target) { PlatformComponent platformComponent = createPlatformComponent(); LWCheckboxPeer peer = new LWCheckboxPeer(target, platformComponent); targetCreatedPeer(target, peer); peer.initialize(); return peer; } @Override public final ChoicePeer createChoice(Choice target) { PlatformComponent platformComponent = createPlatformComponent(); LWChoicePeer peer = new LWChoicePeer(target, platformComponent); targetCreatedPeer(target, peer); peer.initialize(); return peer; } @Override public final LabelPeer createLabel(Label target) { PlatformComponent platformComponent = createPlatformComponent(); LWLabelPeer peer = new LWLabelPeer(target, platformComponent); targetCreatedPeer(target, peer); peer.initialize(); return peer; } @Override public final CanvasPeer createCanvas(Canvas target) { PlatformComponent platformComponent = createPlatformComponent(); LWCanvasPeer peer = new LWCanvasPeer<>(target, platformComponent); targetCreatedPeer(target, peer); peer.initialize(); return peer; } @Override public final ListPeer createList(List target) { PlatformComponent platformComponent = createPlatformComponent(); LWListPeer peer = new LWListPeer(target, platformComponent); targetCreatedPeer(target, peer); peer.initialize(); return peer; } @Override public final PanelPeer createPanel(Panel target) { PlatformComponent platformComponent = createPlatformComponent(); LWPanelPeer peer = new LWPanelPeer(target, platformComponent); targetCreatedPeer(target, peer); peer.initialize(); return peer; } @Override public final ScrollPanePeer createScrollPane(ScrollPane target) { PlatformComponent platformComponent = createPlatformComponent(); LWScrollPanePeer peer = new LWScrollPanePeer(target, platformComponent); targetCreatedPeer(target, peer); peer.initialize(); return peer; } @Override public final ScrollbarPeer createScrollbar(Scrollbar target) { PlatformComponent platformComponent = createPlatformComponent(); LWScrollBarPeer peer = new LWScrollBarPeer(target, platformComponent); targetCreatedPeer(target, peer); peer.initialize(); return peer; } @Override public final TextAreaPeer createTextArea(TextArea target) { PlatformComponent platformComponent = createPlatformComponent(); LWTextAreaPeer peer = new LWTextAreaPeer(target, platformComponent); targetCreatedPeer(target, peer); peer.initialize(); return peer; } @Override public final TextFieldPeer createTextField(TextField target) { PlatformComponent platformComponent = createPlatformComponent(); LWTextFieldPeer peer = new LWTextFieldPeer(target, platformComponent); targetCreatedPeer(target, peer); peer.initialize(); return peer; } // ---- NON-COMPONENT PEERS ---- // @Override public final ColorModel getColorModel() throws HeadlessException { return GraphicsEnvironment.getLocalGraphicsEnvironment() .getDefaultScreenDevice() .getDefaultConfiguration().getColorModel(); } @Override public final boolean isDesktopSupported() { return true; } @Override public final boolean isTaskbarSupported() { return true; } @Override public final KeyboardFocusManagerPeer getKeyboardFocusManagerPeer() { return LWKeyboardFocusManagerPeer.getInstance(); } @Override public final synchronized MouseInfoPeer getMouseInfoPeer() { if (mouseInfoPeer == null) { mouseInfoPeer = createMouseInfoPeerImpl(); } return mouseInfoPeer; } protected final MouseInfoPeer createMouseInfoPeerImpl() { return new LWMouseInfoPeer(); } protected abstract PlatformWindow getPlatformWindowUnderMouse(); @Override public final PrintJob getPrintJob(Frame frame, String doctitle, Properties props) { return getPrintJob(frame, doctitle, null, null); } @Override public final PrintJob getPrintJob(Frame frame, String doctitle, JobAttributes jobAttributes, PageAttributes pageAttributes) { if (GraphicsEnvironment.isHeadless()) { throw new IllegalArgumentException(); } PrintJob2D printJob = new PrintJob2D(frame, doctitle, jobAttributes, pageAttributes); if (!printJob.printDialog()) { printJob = null; } return printJob; } @Override public final Clipboard getSystemClipboard() { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkPermission(AWTPermissions.ACCESS_CLIPBOARD_PERMISSION); } synchronized (this) { if (clipboard == null) { clipboard = createPlatformClipboard(); } } return clipboard; } protected abstract SecurityWarningWindow createSecurityWarning( Window ownerWindow, LWWindowPeer ownerPeer); // ---- DELEGATES ---- // public abstract Clipboard createPlatformClipboard(); /* * Creates a delegate for the given peer type (window, frame, dialog, etc.) */ protected abstract PlatformWindow createPlatformWindow(PeerType peerType); protected abstract PlatformComponent createPlatformComponent(); protected abstract PlatformComponent createLwPlatformComponent(); protected abstract FileDialogPeer createFileDialogPeer(FileDialog target); protected abstract PlatformDropTarget createDropTarget(DropTarget dropTarget, Component component, LWComponentPeer peer); // ---- UTILITY METHODS ---- // /* * Expose non-public targetToPeer() method. */ public static final Object targetToPeer(Object target) { return SunToolkit.targetToPeer(target); } /* * Expose non-public targetDisposedPeer() method. */ public static final void targetDisposedPeer(Object target, Object peer) { SunToolkit.targetDisposedPeer(target, peer); } /* * Returns the current cursor manager. */ public abstract LWCursorManager getCursorManager(); public static void postEvent(AWTEvent event) { postEvent(targetToAppContext(event.getSource()), event); } @Override public final void grab(final Window w) { final Object peer = AWTAccessor.getComponentAccessor().getPeer(w); if (peer != null) { ((LWWindowPeer) peer).grab(); } } @Override public final void ungrab(final Window w) { final Object peer = AWTAccessor.getComponentAccessor().getPeer(w); if (peer != null) { ((LWWindowPeer) peer).ungrab(false); } } @Override protected final Object lazilyLoadDesktopProperty(final String name) { if (name.equals("awt.dynamicLayoutSupported")) { return isDynamicLayoutSupported(); } return super.lazilyLoadDesktopProperty(name); } @Override public final void setDynamicLayout(final boolean dynamic) { dynamicLayoutSetting = dynamic; } @Override protected final boolean isDynamicLayoutSet() { return dynamicLayoutSetting; } @Override public final boolean isDynamicLayoutActive() { // "Live resizing" is active by default and user's data is ignored. return isDynamicLayoutSupported(); } /** * Returns true if dynamic layout of Containers on resize is supported by * the underlying operating system and/or window manager. */ protected final boolean isDynamicLayoutSupported() { // "Live resizing" is supported by default. return true; } }