blob: a6eec6eec3b9116bc285d7301ee0227ff34f3267 [file] [log] [blame]
/*
* Copyright (c) 2011, 2016, 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.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<Void>) () -> {
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();
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 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() {
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;
}
}