| /* |
| * Copyright (c) 2011, 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.lwawt; |
| |
| import java.awt.*; |
| import java.awt.List; |
| import java.awt.datatransfer.*; |
| import java.awt.dnd.*; |
| import java.awt.dnd.peer.*; |
| import java.awt.image.*; |
| import java.awt.peer.*; |
| import java.security.*; |
| import java.util.*; |
| |
| import sun.awt.*; |
| import sun.lwawt.macosx.*; |
| import sun.print.*; |
| import sun.security.util.SecurityConstants; |
| |
| public abstract class LWToolkit extends SunToolkit implements Runnable { |
| |
| private final static int STATE_NONE = 0; |
| private final static int STATE_INIT = 1; |
| private final static int STATE_MESSAGELOOP = 2; |
| private final static int STATE_SHUTDOWN = 3; |
| private final static int STATE_CLEANUP = 4; |
| private final static 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(); |
| |
| ThreadGroup mainTG = AccessController.doPrivileged( |
| new PrivilegedAction<ThreadGroup>() { |
| public ThreadGroup run() { |
| ThreadGroup currentTG = Thread.currentThread().getThreadGroup(); |
| ThreadGroup parentTG = currentTG.getParent(); |
| while (parentTG != null) { |
| currentTG = parentTG; |
| parentTG = currentTG.getParent(); |
| } |
| return currentTG; |
| } |
| } |
| ); |
| |
| Runtime.getRuntime().addShutdownHook( |
| new Thread(mainTG, new Runnable() { |
| public void run() { |
| shutdown(); |
| waitForRunState(STATE_CLEANUP); |
| } |
| }) |
| ); |
| |
| Thread toolkitThread = new Thread(mainTG, this, "AWT-LW"); |
| 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 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 boolean isTerminating() { |
| return getRunState() >= STATE_SHUTDOWN; |
| } |
| |
| private void waitForRunState(int state) { |
| while (getRunState() < state) { |
| try { |
| synchronized (this) { |
| wait(); |
| } |
| } catch (InterruptedException z) { |
| // TODO: log |
| break; |
| } |
| } |
| } |
| |
| public 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. |
| */ |
| private LWWindowPeer createDelegatedPeer(Window target, PlatformComponent platformComponent, |
| PlatformWindow platformWindow, LWWindowPeer.PeerType peerType) |
| { |
| LWWindowPeer peer = new LWWindowPeer(target, platformComponent, platformWindow, peerType); |
| targetCreatedPeer(target, peer); |
| peer.initialize(); |
| return peer; |
| } |
| |
| private LWLightweightFramePeer createDelegatedLwPeer(LightweightFrame target, |
| PlatformComponent platformComponent, |
| PlatformWindow platformWindow) |
| { |
| LWLightweightFramePeer peer = new LWLightweightFramePeer(target, platformComponent, platformWindow); |
| targetCreatedPeer(target, peer); |
| peer.initialize(); |
| return peer; |
| } |
| |
| @Override |
| public FramePeer createLightweightFrame(LightweightFrame target) { |
| PlatformComponent platformComponent = createLwPlatformComponent(); |
| PlatformWindow platformWindow = createPlatformWindow(LWWindowPeer.PeerType.LW_FRAME); |
| return createDelegatedLwPeer(target, platformComponent, platformWindow); |
| } |
| |
| @Override |
| public WindowPeer createWindow(Window target) { |
| PlatformComponent platformComponent = createPlatformComponent(); |
| PlatformWindow platformWindow = createPlatformWindow(LWWindowPeer.PeerType.SIMPLEWINDOW); |
| return createDelegatedPeer(target, platformComponent, platformWindow, LWWindowPeer.PeerType.SIMPLEWINDOW); |
| } |
| |
| @Override |
| public FramePeer createFrame(Frame target) { |
| PlatformComponent platformComponent = createPlatformComponent(); |
| PlatformWindow platformWindow = createPlatformWindow(LWWindowPeer.PeerType.FRAME); |
| return createDelegatedPeer(target, platformComponent, platformWindow, LWWindowPeer.PeerType.FRAME); |
| } |
| |
| public LWWindowPeer createEmbeddedFrame(CEmbeddedFrame target) { |
| PlatformComponent platformComponent = createPlatformComponent(); |
| PlatformWindow platformWindow = createPlatformWindow(LWWindowPeer.PeerType.EMBEDDED_FRAME); |
| return createDelegatedPeer(target, platformComponent, platformWindow, LWWindowPeer.PeerType.EMBEDDED_FRAME); |
| } |
| |
| public LWWindowPeer createEmbeddedFrame(CViewEmbeddedFrame target) { |
| PlatformComponent platformComponent = createPlatformComponent(); |
| PlatformWindow platformWindow = createPlatformWindow(LWWindowPeer.PeerType.VIEW_EMBEDDED_FRAME); |
| return createDelegatedPeer(target, platformComponent, platformWindow, LWWindowPeer.PeerType.VIEW_EMBEDDED_FRAME); |
| } |
| |
| |
| CPrinterDialogPeer createCPrinterDialog(CPrinterDialog target) { |
| PlatformComponent platformComponent = createPlatformComponent(); |
| PlatformWindow platformWindow = createPlatformWindow(LWWindowPeer.PeerType.DIALOG); |
| CPrinterDialogPeer peer = new CPrinterDialogPeer(target, platformComponent, platformWindow); |
| targetCreatedPeer(target, peer); |
| return peer; |
| } |
| |
| @Override |
| public DialogPeer createDialog(Dialog target) { |
| if (target instanceof CPrinterDialog) { |
| return createCPrinterDialog((CPrinterDialog)target); |
| } |
| |
| PlatformComponent platformComponent = createPlatformComponent(); |
| PlatformWindow platformWindow = createPlatformWindow(LWWindowPeer.PeerType.DIALOG); |
| return createDelegatedPeer(target, platformComponent, platformWindow, LWWindowPeer.PeerType.DIALOG); |
| } |
| |
| @Override |
| public FileDialogPeer createFileDialog(FileDialog target) { |
| FileDialogPeer peer = createFileDialogPeer(target); |
| targetCreatedPeer(target, peer); |
| return peer; |
| } |
| |
| // ---- LIGHTWEIGHT COMPONENT PEERS ---- // |
| |
| @Override |
| public ButtonPeer createButton(Button target) { |
| PlatformComponent platformComponent = createPlatformComponent(); |
| LWButtonPeer peer = new LWButtonPeer(target, platformComponent); |
| targetCreatedPeer(target, peer); |
| peer.initialize(); |
| return peer; |
| } |
| |
| @Override |
| public CheckboxPeer createCheckbox(Checkbox target) { |
| PlatformComponent platformComponent = createPlatformComponent(); |
| LWCheckboxPeer peer = new LWCheckboxPeer(target, platformComponent); |
| targetCreatedPeer(target, peer); |
| peer.initialize(); |
| return peer; |
| } |
| |
| @Override |
| public CheckboxMenuItemPeer createCheckboxMenuItem(CheckboxMenuItem target) { |
| throw new RuntimeException("not implemented"); |
| } |
| |
| @Override |
| public ChoicePeer createChoice(Choice target) { |
| PlatformComponent platformComponent = createPlatformComponent(); |
| LWChoicePeer peer = new LWChoicePeer(target, platformComponent); |
| targetCreatedPeer(target, peer); |
| peer.initialize(); |
| return peer; |
| } |
| |
| @Override |
| public LabelPeer createLabel(Label target) { |
| PlatformComponent platformComponent = createPlatformComponent(); |
| LWLabelPeer peer = new LWLabelPeer(target, platformComponent); |
| targetCreatedPeer(target, peer); |
| peer.initialize(); |
| return peer; |
| } |
| |
| @Override |
| public CanvasPeer createCanvas(Canvas target) { |
| PlatformComponent platformComponent = createPlatformComponent(); |
| LWCanvasPeer<?, ?> peer = new LWCanvasPeer<>(target, platformComponent); |
| targetCreatedPeer(target, peer); |
| peer.initialize(); |
| return peer; |
| } |
| |
| @Override |
| public ListPeer createList(List target) { |
| PlatformComponent platformComponent = createPlatformComponent(); |
| LWListPeer peer = new LWListPeer(target, platformComponent); |
| targetCreatedPeer(target, peer); |
| peer.initialize(); |
| return peer; |
| } |
| |
| @Override |
| public MenuPeer createMenu(Menu target) { |
| throw new RuntimeException("not implemented"); |
| } |
| |
| @Override |
| public MenuBarPeer createMenuBar(MenuBar target) { |
| throw new RuntimeException("not implemented"); |
| } |
| |
| @Override |
| public MenuItemPeer createMenuItem(MenuItem target) { |
| throw new RuntimeException("not implemented"); |
| } |
| |
| @Override |
| public PanelPeer createPanel(Panel target) { |
| PlatformComponent platformComponent = createPlatformComponent(); |
| LWPanelPeer peer = new LWPanelPeer(target, platformComponent); |
| targetCreatedPeer(target, peer); |
| peer.initialize(); |
| return peer; |
| } |
| |
| @Override |
| public PopupMenuPeer createPopupMenu(PopupMenu target) { |
| throw new RuntimeException("not implemented"); |
| } |
| |
| @Override |
| public ScrollPanePeer createScrollPane(ScrollPane target) { |
| PlatformComponent platformComponent = createPlatformComponent(); |
| LWScrollPanePeer peer = new LWScrollPanePeer(target, platformComponent); |
| targetCreatedPeer(target, peer); |
| peer.initialize(); |
| return peer; |
| } |
| |
| @Override |
| public ScrollbarPeer createScrollbar(Scrollbar target) { |
| PlatformComponent platformComponent = createPlatformComponent(); |
| LWScrollBarPeer peer = new LWScrollBarPeer(target, platformComponent); |
| targetCreatedPeer(target, peer); |
| peer.initialize(); |
| return peer; |
| } |
| |
| @Override |
| public TextAreaPeer createTextArea(TextArea target) { |
| PlatformComponent platformComponent = createPlatformComponent(); |
| LWTextAreaPeer peer = new LWTextAreaPeer(target, platformComponent); |
| targetCreatedPeer(target, peer); |
| peer.initialize(); |
| return peer; |
| } |
| |
| @Override |
| public 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 ColorModel getColorModel() throws HeadlessException { |
| return GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration().getColorModel(); |
| } |
| |
| @Override |
| public boolean isDesktopSupported() { |
| return true; |
| } |
| |
| @Override |
| protected DesktopPeer createDesktopPeer(Desktop target) { |
| return new CDesktopPeer(); |
| } |
| |
| @Override |
| public DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent dge) { |
| DragSourceContextPeer dscp = CDragSourceContextPeer.createDragSourceContextPeer(dge); |
| |
| return dscp; |
| } |
| |
| @Override |
| public KeyboardFocusManagerPeer getKeyboardFocusManagerPeer() { |
| return LWKeyboardFocusManagerPeer.getInstance(); |
| } |
| |
| @Override |
| public synchronized MouseInfoPeer getMouseInfoPeer() { |
| if (mouseInfoPeer == null) { |
| mouseInfoPeer = createMouseInfoPeerImpl(); |
| } |
| return mouseInfoPeer; |
| } |
| |
| protected MouseInfoPeer createMouseInfoPeerImpl() { |
| return new LWMouseInfoPeer(); |
| } |
| |
| public PrintJob getPrintJob(Frame frame, String doctitle, Properties props) { |
| return getPrintJob(frame, doctitle, null, null); |
| } |
| |
| public 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() == false) { |
| printJob = null; |
| } |
| |
| return printJob; |
| } |
| |
| @Override |
| public RobotPeer createRobot(Robot target, GraphicsDevice screen) { |
| throw new RuntimeException("not implemented"); |
| } |
| |
| @Override |
| public boolean isTraySupported() { |
| throw new RuntimeException("not implemented"); |
| } |
| |
| @Override |
| public SystemTrayPeer createSystemTray(SystemTray target) { |
| throw new RuntimeException("not implemented"); |
| } |
| |
| @Override |
| public TrayIconPeer createTrayIcon(TrayIcon target) { |
| throw new RuntimeException("not implemented"); |
| } |
| |
| @Override |
| public Clipboard getSystemClipboard() { |
| SecurityManager security = System.getSecurityManager(); |
| if (security != null) { |
| security.checkPermission(SecurityConstants.AWT.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(LWWindowPeer.PeerType peerType); |
| |
| protected abstract PlatformComponent createPlatformComponent(); |
| |
| protected abstract PlatformComponent createLwPlatformComponent(); |
| |
| protected abstract FileDialogPeer createFileDialogPeer(FileDialog target); |
| |
| // ---- UTILITY METHODS ---- // |
| |
| /* |
| * Expose non-public targetToPeer() method. |
| */ |
| public final static Object targetToPeer(Object target) { |
| return SunToolkit.targetToPeer(target); |
| } |
| |
| /* |
| * Expose non-public targetDisposedPeer() method. |
| */ |
| public final static 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 void grab(final Window w) { |
| final Object peer = AWTAccessor.getComponentAccessor().getPeer(w); |
| if (peer != null) { |
| ((LWWindowPeer) peer).grab(); |
| } |
| } |
| |
| @Override |
| public 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; |
| } |
| } |