blob: f98dffbf3f1779455fb916b4595ef7a2b8732e36 [file] [log] [blame]
/*
* 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;
}
}