| /* | |
| * Copyright (c) 2011, 2024, 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.util.*; | |
| import sun.awt.*; | |
| 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(); | |
| Runnable shutdownRunnable = () -> { | |
| shutdown(); | |
| waitForRunState(STATE_CLEANUP); | |
| }; | |
| Thread shutdown = new Thread( | |
| ThreadGroupUtils.getRootThreadGroup(), shutdownRunnable, | |
| "AWT-Shutdown", 0, false); | |
| shutdown.setContextClassLoader(null); | |
| Runtime.getRuntime().addShutdownHook(shutdown); | |
| String name = "AWT-LW"; | |
| Thread toolkitThread = new Thread( | |
| ThreadGroupUtils.getRootThreadGroup(), this, name, 0, false); | |
| toolkitThread.setDaemon(true); | |
| toolkitThread.setPriority(Thread.NORM_PRIORITY + 1); | |
| toolkitThread.start(); | |
| 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 (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 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 (frame == null) { | |
| throw new NullPointerException("frame must not be null"); | |
| } | |
| 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() { | |
| synchronized (this) { | |
| if (clipboard == null) { | |
| clipboard = createPlatformClipboard(); | |
| } | |
| } | |
| return clipboard; | |
| } | |
| // ---- 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; | |
| } | |
| } |