LWToolkit.java 16.8 KB
Newer Older
1
/*
2
 * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
 * 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.image.*;
import java.awt.peer.*;
import java.security.*;
import java.util.*;

import sun.awt.*;
import sun.print.*;
38
import sun.security.util.SecurityConstants;
39
import sun.misc.ThreadGroupUtils;
40

41 42
import static sun.lwawt.LWWindowPeer.PeerType;

43 44 45 46 47 48 49 50 51 52 53 54 55 56
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;

57 58 59 60 61 62
    /**
     * Dynamic Layout Resize client code setting.
     */
    private volatile boolean dynamicLayoutSetting = true;

    protected LWToolkit() {
63 64 65 66 67 68 69 70 71 72 73 74
    }

    /*
     * 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();

75 76
        ThreadGroup rootTG = AccessController.doPrivileged(
                (PrivilegedAction<ThreadGroup>) ThreadGroupUtils::getRootThreadGroup);
77 78

        Runtime.getRuntime().addShutdownHook(
79 80 81
            new Thread(rootTG, () -> {
                shutdown();
                waitForRunState(STATE_CLEANUP);
82 83 84
            })
        );

85
        Thread toolkitThread = new Thread(rootTG, this, "AWT-LW");
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
        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.
     */
105
    public final void shutdown() {
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
        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();
    }

136
    public final boolean isTerminating() {
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
        return getRunState() >= STATE_SHUTDOWN;
    }

    private void waitForRunState(int state) {
        while (getRunState() < state) {
            try {
                synchronized (this) {
                    wait();
                }
            } catch (InterruptedException z) {
                // TODO: log
                break;
            }
        }
    }

153 154
    @Override
    public final void run() {
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
        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.
     */
206 207 208 209
    protected LWWindowPeer createDelegatedPeer(Window target,
                                               PlatformComponent platformComponent,
                                               PlatformWindow platformWindow,
                                               PeerType peerType) {
210
        LWWindowPeer peer = new LWWindowPeer(target, platformComponent, platformWindow, peerType);
211 212 213 214 215
        targetCreatedPeer(target, peer);
        peer.initialize();
        return peer;
    }

216 217 218 219 220 221 222
    @Override
    public final FramePeer createLightweightFrame(LightweightFrame target) {
        PlatformComponent platformComponent = createLwPlatformComponent();
        PlatformWindow platformWindow = createPlatformWindow(PeerType.LW_FRAME);
        LWLightweightFramePeer peer = new LWLightweightFramePeer(target,
                                                                 platformComponent,
                                                                 platformWindow);
223 224 225 226 227 228
        targetCreatedPeer(target, peer);
        peer.initialize();
        return peer;
    }

    @Override
229
    public final WindowPeer createWindow(Window target) {
230
        PlatformComponent platformComponent = createPlatformComponent();
231 232
        PlatformWindow platformWindow = createPlatformWindow(PeerType.SIMPLEWINDOW);
        return createDelegatedPeer(target, platformComponent, platformWindow, PeerType.SIMPLEWINDOW);
233 234 235
    }

    @Override
236
    public final FramePeer createFrame(Frame target) {
237
        PlatformComponent platformComponent = createPlatformComponent();
238 239
        PlatformWindow platformWindow = createPlatformWindow(PeerType.FRAME);
        return createDelegatedPeer(target, platformComponent, platformWindow, PeerType.FRAME);
240 241 242 243 244
    }

    @Override
    public DialogPeer createDialog(Dialog target) {
        PlatformComponent platformComponent = createPlatformComponent();
245 246
        PlatformWindow platformWindow = createPlatformWindow(PeerType.DIALOG);
        return createDelegatedPeer(target, platformComponent, platformWindow, PeerType.DIALOG);
247 248 249
    }

    @Override
250
    public final FileDialogPeer createFileDialog(FileDialog target) {
251 252 253 254 255 256 257 258
        FileDialogPeer peer = createFileDialogPeer(target);
        targetCreatedPeer(target, peer);
        return peer;
    }

    // ---- LIGHTWEIGHT COMPONENT PEERS ---- //

    @Override
259
    public final ButtonPeer createButton(Button target) {
260 261 262 263 264 265 266 267
        PlatformComponent platformComponent = createPlatformComponent();
        LWButtonPeer peer = new LWButtonPeer(target, platformComponent);
        targetCreatedPeer(target, peer);
        peer.initialize();
        return peer;
    }

    @Override
268
    public final CheckboxPeer createCheckbox(Checkbox target) {
269 270 271 272 273 274 275 276
        PlatformComponent platformComponent = createPlatformComponent();
        LWCheckboxPeer peer = new LWCheckboxPeer(target, platformComponent);
        targetCreatedPeer(target, peer);
        peer.initialize();
        return peer;
    }

    @Override
277
    public final ChoicePeer createChoice(Choice target) {
278 279 280 281 282 283 284 285
        PlatformComponent platformComponent = createPlatformComponent();
        LWChoicePeer peer = new LWChoicePeer(target, platformComponent);
        targetCreatedPeer(target, peer);
        peer.initialize();
        return peer;
    }

    @Override
286
    public final LabelPeer createLabel(Label target) {
287 288 289 290 291 292 293 294
        PlatformComponent platformComponent = createPlatformComponent();
        LWLabelPeer peer = new LWLabelPeer(target, platformComponent);
        targetCreatedPeer(target, peer);
        peer.initialize();
        return peer;
    }

    @Override
295
    public final CanvasPeer createCanvas(Canvas target) {
296
        PlatformComponent platformComponent = createPlatformComponent();
297
        LWCanvasPeer<?, ?> peer = new LWCanvasPeer<>(target, platformComponent);
298 299 300 301 302 303
        targetCreatedPeer(target, peer);
        peer.initialize();
        return peer;
    }

    @Override
304
    public final ListPeer createList(List target) {
305 306 307 308 309 310 311 312
        PlatformComponent platformComponent = createPlatformComponent();
        LWListPeer peer = new LWListPeer(target, platformComponent);
        targetCreatedPeer(target, peer);
        peer.initialize();
        return peer;
    }

    @Override
313
    public final PanelPeer createPanel(Panel target) {
314 315 316 317 318 319 320 321
        PlatformComponent platformComponent = createPlatformComponent();
        LWPanelPeer peer = new LWPanelPeer(target, platformComponent);
        targetCreatedPeer(target, peer);
        peer.initialize();
        return peer;
    }

    @Override
322
    public final ScrollPanePeer createScrollPane(ScrollPane target) {
323 324 325 326 327 328 329 330
        PlatformComponent platformComponent = createPlatformComponent();
        LWScrollPanePeer peer = new LWScrollPanePeer(target, platformComponent);
        targetCreatedPeer(target, peer);
        peer.initialize();
        return peer;
    }

    @Override
331
    public final ScrollbarPeer createScrollbar(Scrollbar target) {
332 333 334 335 336 337 338 339
        PlatformComponent platformComponent = createPlatformComponent();
        LWScrollBarPeer peer = new LWScrollBarPeer(target, platformComponent);
        targetCreatedPeer(target, peer);
        peer.initialize();
        return peer;
    }

    @Override
340
    public final TextAreaPeer createTextArea(TextArea target) {
341 342 343 344 345 346 347 348
        PlatformComponent platformComponent = createPlatformComponent();
        LWTextAreaPeer peer = new LWTextAreaPeer(target, platformComponent);
        targetCreatedPeer(target, peer);
        peer.initialize();
        return peer;
    }

    @Override
349
    public final TextFieldPeer createTextField(TextField target) {
350 351 352 353 354 355 356 357 358 359
        PlatformComponent platformComponent = createPlatformComponent();
        LWTextFieldPeer peer = new LWTextFieldPeer(target, platformComponent);
        targetCreatedPeer(target, peer);
        peer.initialize();
        return peer;
    }

    // ---- NON-COMPONENT PEERS ---- //

    @Override
360 361 362 363
    public final ColorModel getColorModel() throws HeadlessException {
        return GraphicsEnvironment.getLocalGraphicsEnvironment()
                                  .getDefaultScreenDevice()
                                  .getDefaultConfiguration().getColorModel();
364 365 366
    }

    @Override
367
    public final boolean isDesktopSupported() {
368 369 370 371
        return true;
    }

    @Override
372
    public final KeyboardFocusManagerPeer getKeyboardFocusManagerPeer() {
373
        return LWKeyboardFocusManagerPeer.getInstance();
374 375 376
    }

    @Override
377
    public final synchronized MouseInfoPeer getMouseInfoPeer() {
378 379 380 381 382 383
        if (mouseInfoPeer == null) {
            mouseInfoPeer = createMouseInfoPeerImpl();
        }
        return mouseInfoPeer;
    }

384
    protected final MouseInfoPeer createMouseInfoPeerImpl() {
385 386 387
        return new LWMouseInfoPeer();
    }

388 389 390
    @Override
    public final PrintJob getPrintJob(Frame frame, String doctitle,
                                      Properties props) {
391 392 393
        return getPrintJob(frame, doctitle, null, null);
    }

394 395 396 397
    @Override
    public final PrintJob getPrintJob(Frame frame, String doctitle,
                                      JobAttributes jobAttributes,
                                      PageAttributes pageAttributes) {
398 399 400 401 402 403
        if (GraphicsEnvironment.isHeadless()) {
            throw new IllegalArgumentException();
        }

        PrintJob2D printJob = new PrintJob2D(frame, doctitle, jobAttributes, pageAttributes);

404
        if (!printJob.printDialog()) {
405 406 407 408 409 410 411
            printJob = null;
        }

        return printJob;
    }

    @Override
412
    public final Clipboard getSystemClipboard() {
413 414
        SecurityManager security = System.getSecurityManager();
        if (security != null) {
415
            security.checkPermission(SecurityConstants.AWT.ACCESS_CLIPBOARD_PERMISSION);
416 417 418 419 420 421 422 423 424 425
        }

        synchronized (this) {
            if (clipboard == null) {
                clipboard = createPlatformClipboard();
            }
        }
        return clipboard;
    }

426 427
    protected abstract SecurityWarningWindow createSecurityWarning(
            Window ownerWindow, LWWindowPeer ownerPeer);
428

429 430 431 432 433 434 435
    // ---- DELEGATES ---- //

    public abstract Clipboard createPlatformClipboard();

    /*
     * Creates a delegate for the given peer type (window, frame, dialog, etc.)
     */
436
    protected abstract PlatformWindow createPlatformWindow(PeerType peerType);
437 438 439

    protected abstract PlatformComponent createPlatformComponent();

440 441
    protected abstract PlatformComponent createLwPlatformComponent();

442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469
    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
470
    public final void grab(final Window w) {
471 472 473
        final Object peer = AWTAccessor.getComponentAccessor().getPeer(w);
        if (peer != null) {
            ((LWWindowPeer) peer).grab();
474 475 476 477
        }
    }

    @Override
478
    public final void ungrab(final Window w) {
479 480 481
        final Object peer = AWTAccessor.getComponentAccessor().getPeer(w);
        if (peer != null) {
            ((LWWindowPeer) peer).ungrab(false);
482 483
        }
    }
484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516

    @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;
    }
517
}