1 /*
   2  * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.lwawt;
  27 
  28 import java.awt.*;
  29 import java.awt.List;
  30 import java.awt.datatransfer.*;
  31 import java.awt.dnd.*;
  32 import java.awt.dnd.peer.*;
  33 import java.awt.image.*;
  34 import java.awt.peer.*;
  35 import java.security.*;
  36 import java.util.*;
  37 
  38 import sun.awt.*;
  39 import sun.lwawt.macosx.*;
  40 import sun.print.*;
  41 
  42 public abstract class LWToolkit extends SunToolkit implements Runnable {
  43 
  44     private final static int STATE_NONE = 0;
  45     private final static int STATE_INIT = 1;
  46     private final static int STATE_MESSAGELOOP = 2;
  47     private final static int STATE_SHUTDOWN = 3;
  48     private final static int STATE_CLEANUP = 4;
  49     private final static int STATE_DONE = 5;
  50 
  51     private int runState = STATE_NONE;
  52 
  53     private Clipboard clipboard;
  54     private MouseInfoPeer mouseInfoPeer;
  55 
  56     public LWToolkit() {
  57     }
  58 
  59     /*
  60      * This method is called by subclasses to start this toolkit
  61      * by launching the message loop.
  62      *
  63      * This method waits for the toolkit to be completely initialized
  64      * and returns before the message pump is started.
  65      */
  66     protected final void init() {
  67         AWTAutoShutdown.notifyToolkitThreadBusy();
  68 
  69         ThreadGroup mainTG = AccessController.doPrivileged(
  70             new PrivilegedAction<ThreadGroup>() {
  71                 public ThreadGroup run() {
  72                     ThreadGroup currentTG = Thread.currentThread().getThreadGroup();
  73                     ThreadGroup parentTG = currentTG.getParent();
  74                     while (parentTG != null) {
  75                         currentTG = parentTG;
  76                         parentTG = currentTG.getParent();
  77                     }
  78                     return currentTG;
  79                 }
  80             }
  81         );
  82 
  83         Runtime.getRuntime().addShutdownHook(
  84             new Thread(mainTG, new Runnable() {
  85                 public void run() {
  86                     shutdown();
  87                     waitForRunState(STATE_CLEANUP);
  88                 }
  89             })
  90         );
  91 
  92         Thread toolkitThread = new Thread(mainTG, this, "AWT-LW");
  93         toolkitThread.setDaemon(true);
  94         toolkitThread.setPriority(Thread.NORM_PRIORITY + 1);
  95         toolkitThread.start();
  96 
  97         waitForRunState(STATE_MESSAGELOOP);
  98     }
  99 
 100     /*
 101      * Implemented in subclasses to initialize platform-dependent
 102      * part of the toolkit (open X display connection, create
 103      * toolkit HWND, etc.)
 104      *
 105      * This method is called on the toolkit thread.
 106      */
 107     protected abstract void platformInit();
 108 
 109     /*
 110      * Sends a request to stop the message pump.
 111      */
 112     public void shutdown() {
 113         setRunState(STATE_SHUTDOWN);
 114         platformShutdown();
 115     }
 116 
 117     /*
 118      * Implemented in subclasses to release all the platform-
 119      * dependent resources. Called after the message loop is
 120      * terminated.
 121      *
 122      * Could be called (always called?) on a non-toolkit thread.
 123      */
 124     protected abstract void platformShutdown();
 125 
 126     /*
 127      * Implemented in subclasses to release all the platform
 128      * resources before the application is terminated.
 129      *
 130      * This method is called on the toolkit thread.
 131      */
 132     protected abstract void platformCleanup();
 133 
 134     private synchronized int getRunState() {
 135         return runState;
 136     }
 137 
 138     private synchronized void setRunState(int state) {
 139         runState = state;
 140         notifyAll();
 141     }
 142 
 143     public boolean isTerminating() {
 144         return getRunState() >= STATE_SHUTDOWN;
 145     }
 146 
 147     private void waitForRunState(int state) {
 148         while (getRunState() < state) {
 149             try {
 150                 synchronized (this) {
 151                     wait();
 152                 }
 153             } catch (InterruptedException z) {
 154                 // TODO: log
 155                 break;
 156             }
 157         }
 158     }
 159 
 160     public void run() {
 161         setRunState(STATE_INIT);
 162         platformInit();
 163         AWTAutoShutdown.notifyToolkitThreadFree();
 164         setRunState(STATE_MESSAGELOOP);
 165         while (getRunState() < STATE_SHUTDOWN) {
 166             try {
 167                 platformRunMessage();
 168                 if (Thread.currentThread().isInterrupted()) {
 169                     if (AppContext.getAppContext().isDisposed()) {
 170                         break;
 171                     }
 172                 }
 173             } catch (ThreadDeath td) {
 174                 //XXX: if there isn't native code on the stack, the VM just
 175                 //kills the thread right away. Do we expect to catch it
 176                 //nevertheless?
 177                 break;
 178             } catch (Throwable t) {
 179                 // TODO: log
 180                 System.err.println("Exception on the toolkit thread");
 181                 t.printStackTrace(System.err);
 182             }
 183         }
 184         //XXX: if that's a secondary loop, jump back to the STATE_MESSAGELOOP
 185         setRunState(STATE_CLEANUP);
 186         AWTAutoShutdown.notifyToolkitThreadFree();
 187         platformCleanup();
 188         setRunState(STATE_DONE);
 189     }
 190 
 191     /*
 192      * Process the next message(s) from the native event queue.
 193      *
 194      * Initially, all the LWToolkit implementations were supposed
 195      * to have the similar message loop sequence: check if any events
 196      * available, peek events, wait. However, the later analysis shown
 197      * that X11 and Windows implementations are really different, so
 198      * let the subclasses do whatever they require.
 199      */
 200     protected abstract void platformRunMessage();
 201 
 202     public static LWToolkit getLWToolkit() {
 203         return (LWToolkit)Toolkit.getDefaultToolkit();
 204     }
 205 
 206     // ---- TOPLEVEL PEERS ---- //
 207 
 208     /*
 209      * Note that LWWindowPeer implements WindowPeer, FramePeer
 210      * and DialogPeer interfaces.
 211      */
 212     private LWWindowPeer createDelegatedPeer(Window target, PlatformComponent platformComponent,
 213                                              PlatformWindow platformWindow, LWWindowPeer.PeerType peerType)
 214     {
 215         LWWindowPeer peer = new LWWindowPeer(target, platformComponent, platformWindow, peerType);
 216         targetCreatedPeer(target, peer);
 217         peer.initialize();
 218         return peer;
 219     }
 220     
 221     private LWLightweightFramePeer createDelegatedLwPeer(LightweightFrame target,
 222                                                          PlatformComponent platformComponent,
 223                                                          PlatformWindow platformWindow)
 224     {
 225         LWLightweightFramePeer peer = new LWLightweightFramePeer(target, platformComponent, platformWindow);
 226         targetCreatedPeer(target, peer);
 227         peer.initialize();
 228         return peer;
 229     }
 230     
 231     @Override
 232     public FramePeer createLightweightFrame(LightweightFrame target) {
 233         PlatformComponent platformComponent = createLwPlatformComponent();
 234         PlatformWindow platformWindow = createPlatformWindow(LWWindowPeer.PeerType.LW_FRAME);
 235         return createDelegatedLwPeer(target, platformComponent, platformWindow);
 236     }        
 237 
 238     @Override
 239     public WindowPeer createWindow(Window target) {
 240         PlatformComponent platformComponent = createPlatformComponent();
 241         PlatformWindow platformWindow = createPlatformWindow(LWWindowPeer.PeerType.SIMPLEWINDOW);
 242         return createDelegatedPeer(target, platformComponent, platformWindow, LWWindowPeer.PeerType.SIMPLEWINDOW);
 243     }
 244 
 245     @Override
 246     public FramePeer createFrame(Frame target) {
 247         PlatformComponent platformComponent = createPlatformComponent();
 248         PlatformWindow platformWindow = createPlatformWindow(LWWindowPeer.PeerType.FRAME);
 249         return createDelegatedPeer(target, platformComponent, platformWindow, LWWindowPeer.PeerType.FRAME);
 250     }
 251 
 252     public LWWindowPeer createEmbeddedFrame(CEmbeddedFrame target) {
 253         PlatformComponent platformComponent = createPlatformComponent();
 254         PlatformWindow platformWindow = createPlatformWindow(LWWindowPeer.PeerType.EMBEDDED_FRAME);
 255         return createDelegatedPeer(target, platformComponent, platformWindow, LWWindowPeer.PeerType.EMBEDDED_FRAME);
 256     }
 257 
 258     public LWWindowPeer createEmbeddedFrame(CViewEmbeddedFrame target) {
 259         PlatformComponent platformComponent = createPlatformComponent();
 260         PlatformWindow platformWindow = createPlatformWindow(LWWindowPeer.PeerType.VIEW_EMBEDDED_FRAME);
 261         return createDelegatedPeer(target, platformComponent, platformWindow, LWWindowPeer.PeerType.VIEW_EMBEDDED_FRAME);
 262     }
 263 
 264 
 265     CPrinterDialogPeer createCPrinterDialog(CPrinterDialog target) {
 266         PlatformComponent platformComponent = createPlatformComponent();
 267         PlatformWindow platformWindow = createPlatformWindow(LWWindowPeer.PeerType.DIALOG);
 268         CPrinterDialogPeer peer = new CPrinterDialogPeer(target, platformComponent, platformWindow);
 269         targetCreatedPeer(target, peer);
 270         return peer;
 271     }
 272 
 273     @Override
 274     public DialogPeer createDialog(Dialog target) {
 275         if (target instanceof CPrinterDialog) {
 276             return createCPrinterDialog((CPrinterDialog)target);
 277         }
 278 
 279         PlatformComponent platformComponent = createPlatformComponent();
 280         PlatformWindow platformWindow = createPlatformWindow(LWWindowPeer.PeerType.DIALOG);
 281         return createDelegatedPeer(target, platformComponent, platformWindow, LWWindowPeer.PeerType.DIALOG);
 282     }
 283 
 284     @Override
 285     public FileDialogPeer createFileDialog(FileDialog target) {
 286         FileDialogPeer peer = createFileDialogPeer(target);
 287         targetCreatedPeer(target, peer);
 288         return peer;
 289     }
 290 
 291     // ---- LIGHTWEIGHT COMPONENT PEERS ---- //
 292 
 293     @Override
 294     public ButtonPeer createButton(Button target) {
 295         PlatformComponent platformComponent = createPlatformComponent();
 296         LWButtonPeer peer = new LWButtonPeer(target, platformComponent);
 297         targetCreatedPeer(target, peer);
 298         peer.initialize();
 299         return peer;
 300     }
 301 
 302     @Override
 303     public CheckboxPeer createCheckbox(Checkbox target) {
 304         PlatformComponent platformComponent = createPlatformComponent();
 305         LWCheckboxPeer peer = new LWCheckboxPeer(target, platformComponent);
 306         targetCreatedPeer(target, peer);
 307         peer.initialize();
 308         return peer;
 309     }
 310 
 311     @Override
 312     public CheckboxMenuItemPeer createCheckboxMenuItem(CheckboxMenuItem target) {
 313         throw new RuntimeException("not implemented");
 314     }
 315 
 316     @Override
 317     public ChoicePeer createChoice(Choice target) {
 318         PlatformComponent platformComponent = createPlatformComponent();
 319         LWChoicePeer peer = new LWChoicePeer(target, platformComponent);
 320         targetCreatedPeer(target, peer);
 321         peer.initialize();
 322         return peer;
 323     }
 324 
 325     @Override
 326     public LabelPeer createLabel(Label target) {
 327         PlatformComponent platformComponent = createPlatformComponent();
 328         LWLabelPeer peer = new LWLabelPeer(target, platformComponent);
 329         targetCreatedPeer(target, peer);
 330         peer.initialize();
 331         return peer;
 332     }
 333 
 334     @Override
 335     public CanvasPeer createCanvas(Canvas target) {
 336         PlatformComponent platformComponent = createPlatformComponent();
 337         LWCanvasPeer<?, ?> peer = new LWCanvasPeer<>(target, platformComponent);
 338         targetCreatedPeer(target, peer);
 339         peer.initialize();
 340         return peer;
 341     }
 342 
 343     @Override
 344     public ListPeer createList(List target) {
 345         PlatformComponent platformComponent = createPlatformComponent();
 346         LWListPeer peer = new LWListPeer(target, platformComponent);
 347         targetCreatedPeer(target, peer);
 348         peer.initialize();
 349         return peer;
 350     }
 351 
 352     @Override
 353     public MenuPeer createMenu(Menu target) {
 354         throw new RuntimeException("not implemented");
 355     }
 356 
 357     @Override
 358     public MenuBarPeer createMenuBar(MenuBar target) {
 359         throw new RuntimeException("not implemented");
 360     }
 361 
 362     @Override
 363     public MenuItemPeer createMenuItem(MenuItem target) {
 364         throw new RuntimeException("not implemented");
 365     }
 366 
 367     @Override
 368     public PanelPeer createPanel(Panel target) {
 369         PlatformComponent platformComponent = createPlatformComponent();
 370         LWPanelPeer peer = new LWPanelPeer(target, platformComponent);
 371         targetCreatedPeer(target, peer);
 372         peer.initialize();
 373         return peer;
 374     }
 375 
 376     @Override
 377     public PopupMenuPeer createPopupMenu(PopupMenu target) {
 378         throw new RuntimeException("not implemented");
 379     }
 380 
 381     @Override
 382     public ScrollPanePeer createScrollPane(ScrollPane target) {
 383         PlatformComponent platformComponent = createPlatformComponent();
 384         LWScrollPanePeer peer = new LWScrollPanePeer(target, platformComponent);
 385         targetCreatedPeer(target, peer);
 386         peer.initialize();
 387         return peer;
 388     }
 389 
 390     @Override
 391     public ScrollbarPeer createScrollbar(Scrollbar target) {
 392         PlatformComponent platformComponent = createPlatformComponent();
 393         LWScrollBarPeer peer = new LWScrollBarPeer(target, platformComponent);
 394         targetCreatedPeer(target, peer);
 395         peer.initialize();
 396         return peer;
 397     }
 398 
 399     @Override
 400     public TextAreaPeer createTextArea(TextArea target) {
 401         PlatformComponent platformComponent = createPlatformComponent();
 402         LWTextAreaPeer peer = new LWTextAreaPeer(target, platformComponent);
 403         targetCreatedPeer(target, peer);
 404         peer.initialize();
 405         return peer;
 406     }
 407 
 408     @Override
 409     public TextFieldPeer createTextField(TextField target) {
 410         PlatformComponent platformComponent = createPlatformComponent();
 411         LWTextFieldPeer peer = new LWTextFieldPeer(target, platformComponent);
 412         targetCreatedPeer(target, peer);
 413         peer.initialize();
 414         return peer;
 415     }
 416 
 417     // ---- NON-COMPONENT PEERS ---- //
 418 
 419     @Override
 420     public ColorModel getColorModel() throws HeadlessException {
 421         return GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration().getColorModel();
 422     }
 423 
 424     @Override
 425     public boolean isDesktopSupported() {
 426         return true;
 427     }
 428 
 429     @Override
 430     protected DesktopPeer createDesktopPeer(Desktop target) {
 431        return new CDesktopPeer();
 432     }
 433 
 434     @Override
 435     public DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent dge) {
 436         DragSourceContextPeer dscp = CDragSourceContextPeer.createDragSourceContextPeer(dge);
 437 
 438         return dscp;
 439     }
 440 
 441     @Override
 442     public KeyboardFocusManagerPeer getKeyboardFocusManagerPeer() {
 443         return LWKeyboardFocusManagerPeer.getInstance();
 444     }
 445 
 446     @Override
 447     public synchronized MouseInfoPeer getMouseInfoPeer() {
 448         if (mouseInfoPeer == null) {
 449             mouseInfoPeer = createMouseInfoPeerImpl();
 450         }
 451         return mouseInfoPeer;
 452     }
 453 
 454     protected MouseInfoPeer createMouseInfoPeerImpl() {
 455         return new LWMouseInfoPeer();
 456     }
 457 
 458     public PrintJob getPrintJob(Frame frame, String doctitle, Properties props) {
 459         return getPrintJob(frame, doctitle, null, null);
 460     }
 461 
 462     public PrintJob getPrintJob(Frame frame, String doctitle, JobAttributes jobAttributes, PageAttributes pageAttributes) {
 463         if (GraphicsEnvironment.isHeadless()) {
 464             throw new IllegalArgumentException();
 465         }
 466 
 467         PrintJob2D printJob = new PrintJob2D(frame, doctitle, jobAttributes, pageAttributes);
 468 
 469         if (printJob.printDialog() == false) {
 470             printJob = null;
 471         }
 472 
 473         return printJob;
 474     }
 475 
 476     @Override
 477     public RobotPeer createRobot(Robot target, GraphicsDevice screen) {
 478         throw new RuntimeException("not implemented");
 479     }
 480 
 481     @Override
 482     public boolean isTraySupported() {
 483         throw new RuntimeException("not implemented");
 484     }
 485 
 486     @Override
 487     public SystemTrayPeer createSystemTray(SystemTray target) {
 488         throw new RuntimeException("not implemented");
 489     }
 490 
 491     @Override
 492     public TrayIconPeer createTrayIcon(TrayIcon target) {
 493         throw new RuntimeException("not implemented");
 494     }
 495 
 496     @Override
 497     public Clipboard getSystemClipboard() {
 498         SecurityManager security = System.getSecurityManager();
 499         if (security != null) {
 500             security.checkSystemClipboardAccess();
 501         }
 502 
 503         synchronized (this) {
 504             if (clipboard == null) {
 505                 clipboard = createPlatformClipboard();
 506             }
 507         }
 508         return clipboard;
 509     }
 510 
 511     // ---- DELEGATES ---- //
 512 
 513     public abstract Clipboard createPlatformClipboard();
 514 
 515     /*
 516      * Creates a delegate for the given peer type (window, frame, dialog, etc.)
 517      */
 518     protected abstract PlatformWindow createPlatformWindow(LWWindowPeer.PeerType peerType);
 519 
 520     protected abstract PlatformComponent createPlatformComponent();
 521     
 522     protected abstract PlatformComponent createLwPlatformComponent();    
 523 
 524     protected abstract FileDialogPeer createFileDialogPeer(FileDialog target);
 525 
 526     // ---- UTILITY METHODS ---- //
 527 
 528     /*
 529      * Expose non-public targetToPeer() method.
 530      */
 531     public final static Object targetToPeer(Object target) {
 532         return SunToolkit.targetToPeer(target);
 533     }
 534 
 535     /*
 536      * Expose non-public targetDisposedPeer() method.
 537      */
 538     public final static void targetDisposedPeer(Object target, Object peer) {
 539         SunToolkit.targetDisposedPeer(target, peer);
 540     }
 541 
 542     /*
 543      * Returns the current cursor manager.
 544      */
 545     public abstract LWCursorManager getCursorManager();
 546 
 547     public static void postEvent(AWTEvent event) {
 548         postEvent(targetToAppContext(event.getSource()), event);
 549     }
 550 
 551     @Override
 552     public void grab(Window w) {
 553         // When grab/ungrab API is public,
 554         // it should go through Window.grab(),
 555         // not via SunToolkit.grab(Window).
 556         if (w instanceof LightweightFrame) {
 557             ((LightweightFrame)w).grabFocus();
 558             return;
 559         }
 560         if (w.getPeer() != null) {
 561             ((LWWindowPeer)w.getPeer()).grab();
 562         }
 563     }
 564 
 565     @Override
 566     public void ungrab(Window w) {
 567         // When grab/ungrab API is public,
 568         // it should go through Window.ungrab(boolean),
 569         // not via SunToolkit.ungrab(Window).
 570         if (w instanceof LightweightFrame) {
 571             ((LightweightFrame)w).ungrabFocus(false);
 572             return;
 573         }
 574         if (w.getPeer() != null) {
 575             ((LWWindowPeer)w.getPeer()).ungrab(false);
 576         }
 577     }
 578 }