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 /** 57 * Dynamic Layout Resize client code setting. 58 */ 59 private volatile boolean dynamicLayoutSetting = true; 60 61 protected LWToolkit() { 62 } 63 64 /* 65 * This method is called by subclasses to start this toolkit 66 * by launching the message loop. 67 * 68 * This method waits for the toolkit to be completely initialized 69 * and returns before the message pump is started. 70 */ 71 protected final void init() { 72 AWTAutoShutdown.notifyToolkitThreadBusy(); 73 74 ThreadGroup mainTG = AccessController.doPrivileged( 75 new PrivilegedAction<ThreadGroup>() { 76 public ThreadGroup run() { 77 ThreadGroup currentTG = Thread.currentThread().getThreadGroup(); 78 ThreadGroup parentTG = currentTG.getParent(); 79 while (parentTG != null) { 80 currentTG = parentTG; 81 parentTG = currentTG.getParent(); 82 } 83 return currentTG; 84 } 85 } 86 ); 87 88 Runtime.getRuntime().addShutdownHook( 89 new Thread(mainTG, new Runnable() { 90 public void run() { 91 shutdown(); 92 waitForRunState(STATE_CLEANUP); 93 } 94 }) 95 ); 96 97 Thread toolkitThread = new Thread(mainTG, this, "AWT-LW"); 98 toolkitThread.setDaemon(true); 99 toolkitThread.setPriority(Thread.NORM_PRIORITY + 1); 100 toolkitThread.start(); 101 102 waitForRunState(STATE_MESSAGELOOP); 103 } 104 105 /* 106 * Implemented in subclasses to initialize platform-dependent 107 * part of the toolkit (open X display connection, create 108 * toolkit HWND, etc.) 109 * 110 * This method is called on the toolkit thread. 111 */ 112 protected abstract void platformInit(); 113 114 /* 115 * Sends a request to stop the message pump. 116 */ 117 public void shutdown() { 118 setRunState(STATE_SHUTDOWN); 119 platformShutdown(); 120 } 121 122 /* 123 * Implemented in subclasses to release all the platform- 124 * dependent resources. Called after the message loop is 125 * terminated. 126 * 127 * Could be called (always called?) on a non-toolkit thread. 128 */ 129 protected abstract void platformShutdown(); 130 131 /* 132 * Implemented in subclasses to release all the platform 133 * resources before the application is terminated. 134 * 135 * This method is called on the toolkit thread. 136 */ 137 protected abstract void platformCleanup(); 138 139 private synchronized int getRunState() { 140 return runState; 141 } 142 143 private synchronized void setRunState(int state) { 144 runState = state; 145 notifyAll(); 146 } 147 148 public boolean isTerminating() { 149 return getRunState() >= STATE_SHUTDOWN; 150 } 151 152 private void waitForRunState(int state) { 153 while (getRunState() < state) { 154 try { 155 synchronized (this) { 156 wait(); 157 } 158 } catch (InterruptedException z) { 159 // TODO: log 160 break; 161 } 162 } 163 } 164 165 public void run() { 166 setRunState(STATE_INIT); 167 platformInit(); 168 AWTAutoShutdown.notifyToolkitThreadFree(); 169 setRunState(STATE_MESSAGELOOP); 170 while (getRunState() < STATE_SHUTDOWN) { 171 try { 172 platformRunMessage(); 173 if (Thread.currentThread().isInterrupted()) { 174 if (AppContext.getAppContext().isDisposed()) { 175 break; 176 } 177 } 178 } catch (ThreadDeath td) { 179 //XXX: if there isn't native code on the stack, the VM just 180 //kills the thread right away. Do we expect to catch it 181 //nevertheless? 182 break; 183 } catch (Throwable t) { 184 // TODO: log 185 System.err.println("Exception on the toolkit thread"); 186 t.printStackTrace(System.err); 187 } 188 } 189 //XXX: if that's a secondary loop, jump back to the STATE_MESSAGELOOP 190 setRunState(STATE_CLEANUP); 191 AWTAutoShutdown.notifyToolkitThreadFree(); 192 platformCleanup(); 193 setRunState(STATE_DONE); 194 } 195 196 /* 197 * Process the next message(s) from the native event queue. 198 * 199 * Initially, all the LWToolkit implementations were supposed 200 * to have the similar message loop sequence: check if any events 201 * available, peek events, wait. However, the later analysis shown 202 * that X11 and Windows implementations are really different, so 203 * let the subclasses do whatever they require. 204 */ 205 protected abstract void platformRunMessage(); 206 207 public static LWToolkit getLWToolkit() { 208 return (LWToolkit)Toolkit.getDefaultToolkit(); 209 } 210 211 // ---- TOPLEVEL PEERS ---- // 212 213 /* 214 * Note that LWWindowPeer implements WindowPeer, FramePeer 215 * and DialogPeer interfaces. 216 */ 217 private LWWindowPeer createDelegatedPeer(Window target, PlatformComponent platformComponent, 218 PlatformWindow platformWindow, LWWindowPeer.PeerType peerType) 219 { 220 LWWindowPeer peer = new LWWindowPeer(target, platformComponent, platformWindow, peerType); 221 targetCreatedPeer(target, peer); 222 peer.initialize(); 223 return peer; 224 } 225 226 private LWLightweightFramePeer createDelegatedLwPeer(LightweightFrame target, 227 PlatformComponent platformComponent, 228 PlatformWindow platformWindow) 229 { 230 LWLightweightFramePeer peer = new LWLightweightFramePeer(target, platformComponent, platformWindow); 231 targetCreatedPeer(target, peer); 232 peer.initialize(); 233 return peer; 234 } 235 236 @Override 237 public FramePeer createLightweightFrame(LightweightFrame target) { 238 PlatformComponent platformComponent = createLwPlatformComponent(); 239 PlatformWindow platformWindow = createPlatformWindow(LWWindowPeer.PeerType.LW_FRAME); 240 return createDelegatedLwPeer(target, platformComponent, platformWindow); 241 } 242 243 @Override 244 public WindowPeer createWindow(Window target) { 245 PlatformComponent platformComponent = createPlatformComponent(); 246 PlatformWindow platformWindow = createPlatformWindow(LWWindowPeer.PeerType.SIMPLEWINDOW); 247 return createDelegatedPeer(target, platformComponent, platformWindow, LWWindowPeer.PeerType.SIMPLEWINDOW); 248 } 249 250 @Override 251 public FramePeer createFrame(Frame target) { 252 PlatformComponent platformComponent = createPlatformComponent(); 253 PlatformWindow platformWindow = createPlatformWindow(LWWindowPeer.PeerType.FRAME); 254 return createDelegatedPeer(target, platformComponent, platformWindow, LWWindowPeer.PeerType.FRAME); 255 } 256 257 public LWWindowPeer createEmbeddedFrame(CEmbeddedFrame target) { 258 PlatformComponent platformComponent = createPlatformComponent(); 259 PlatformWindow platformWindow = createPlatformWindow(LWWindowPeer.PeerType.EMBEDDED_FRAME); 260 return createDelegatedPeer(target, platformComponent, platformWindow, LWWindowPeer.PeerType.EMBEDDED_FRAME); 261 } 262 263 public LWWindowPeer createEmbeddedFrame(CViewEmbeddedFrame target) { 264 PlatformComponent platformComponent = createPlatformComponent(); 265 PlatformWindow platformWindow = createPlatformWindow(LWWindowPeer.PeerType.VIEW_EMBEDDED_FRAME); 266 return createDelegatedPeer(target, platformComponent, platformWindow, LWWindowPeer.PeerType.VIEW_EMBEDDED_FRAME); 267 } 268 269 270 CPrinterDialogPeer createCPrinterDialog(CPrinterDialog target) { 271 PlatformComponent platformComponent = createPlatformComponent(); 272 PlatformWindow platformWindow = createPlatformWindow(LWWindowPeer.PeerType.DIALOG); 273 CPrinterDialogPeer peer = new CPrinterDialogPeer(target, platformComponent, platformWindow); 274 targetCreatedPeer(target, peer); 275 return peer; 276 } 277 278 @Override 279 public DialogPeer createDialog(Dialog target) { 280 if (target instanceof CPrinterDialog) { 281 return createCPrinterDialog((CPrinterDialog)target); 282 } 283 284 PlatformComponent platformComponent = createPlatformComponent(); 285 PlatformWindow platformWindow = createPlatformWindow(LWWindowPeer.PeerType.DIALOG); 286 return createDelegatedPeer(target, platformComponent, platformWindow, LWWindowPeer.PeerType.DIALOG); 287 } 288 289 @Override 290 public FileDialogPeer createFileDialog(FileDialog target) { 291 FileDialogPeer peer = createFileDialogPeer(target); 292 targetCreatedPeer(target, peer); 293 return peer; 294 } 295 296 // ---- LIGHTWEIGHT COMPONENT PEERS ---- // 297 298 @Override 299 public ButtonPeer createButton(Button target) { 300 PlatformComponent platformComponent = createPlatformComponent(); 301 LWButtonPeer peer = new LWButtonPeer(target, platformComponent); 302 targetCreatedPeer(target, peer); 303 peer.initialize(); 304 return peer; 305 } 306 307 @Override 308 public CheckboxPeer createCheckbox(Checkbox target) { 309 PlatformComponent platformComponent = createPlatformComponent(); 310 LWCheckboxPeer peer = new LWCheckboxPeer(target, platformComponent); 311 targetCreatedPeer(target, peer); 312 peer.initialize(); 313 return peer; 314 } 315 316 @Override 317 public CheckboxMenuItemPeer createCheckboxMenuItem(CheckboxMenuItem target) { 318 throw new RuntimeException("not implemented"); 319 } 320 321 @Override 322 public ChoicePeer createChoice(Choice target) { 323 PlatformComponent platformComponent = createPlatformComponent(); 324 LWChoicePeer peer = new LWChoicePeer(target, platformComponent); 325 targetCreatedPeer(target, peer); 326 peer.initialize(); 327 return peer; 328 } 329 330 @Override 331 public LabelPeer createLabel(Label target) { 332 PlatformComponent platformComponent = createPlatformComponent(); 333 LWLabelPeer peer = new LWLabelPeer(target, platformComponent); 334 targetCreatedPeer(target, peer); 335 peer.initialize(); 336 return peer; 337 } 338 339 @Override 340 public CanvasPeer createCanvas(Canvas target) { 341 PlatformComponent platformComponent = createPlatformComponent(); 342 LWCanvasPeer<?, ?> peer = new LWCanvasPeer<>(target, platformComponent); 343 targetCreatedPeer(target, peer); 344 peer.initialize(); 345 return peer; 346 } 347 348 @Override 349 public ListPeer createList(List target) { 350 PlatformComponent platformComponent = createPlatformComponent(); 351 LWListPeer peer = new LWListPeer(target, platformComponent); 352 targetCreatedPeer(target, peer); 353 peer.initialize(); 354 return peer; 355 } 356 357 @Override 358 public MenuPeer createMenu(Menu target) { 359 throw new RuntimeException("not implemented"); 360 } 361 362 @Override 363 public MenuBarPeer createMenuBar(MenuBar target) { 364 throw new RuntimeException("not implemented"); 365 } 366 367 @Override 368 public MenuItemPeer createMenuItem(MenuItem target) { 369 throw new RuntimeException("not implemented"); 370 } 371 372 @Override 373 public PanelPeer createPanel(Panel target) { 374 PlatformComponent platformComponent = createPlatformComponent(); 375 LWPanelPeer peer = new LWPanelPeer(target, platformComponent); 376 targetCreatedPeer(target, peer); 377 peer.initialize(); 378 return peer; 379 } 380 381 @Override 382 public PopupMenuPeer createPopupMenu(PopupMenu target) { 383 throw new RuntimeException("not implemented"); 384 } 385 386 @Override 387 public ScrollPanePeer createScrollPane(ScrollPane target) { 388 PlatformComponent platformComponent = createPlatformComponent(); 389 LWScrollPanePeer peer = new LWScrollPanePeer(target, platformComponent); 390 targetCreatedPeer(target, peer); 391 peer.initialize(); 392 return peer; 393 } 394 395 @Override 396 public ScrollbarPeer createScrollbar(Scrollbar target) { 397 PlatformComponent platformComponent = createPlatformComponent(); 398 LWScrollBarPeer peer = new LWScrollBarPeer(target, platformComponent); 399 targetCreatedPeer(target, peer); 400 peer.initialize(); 401 return peer; 402 } 403 404 @Override 405 public TextAreaPeer createTextArea(TextArea target) { 406 PlatformComponent platformComponent = createPlatformComponent(); 407 LWTextAreaPeer peer = new LWTextAreaPeer(target, platformComponent); 408 targetCreatedPeer(target, peer); 409 peer.initialize(); 410 return peer; 411 } 412 413 @Override 414 public TextFieldPeer createTextField(TextField target) { 415 PlatformComponent platformComponent = createPlatformComponent(); 416 LWTextFieldPeer peer = new LWTextFieldPeer(target, platformComponent); 417 targetCreatedPeer(target, peer); 418 peer.initialize(); 419 return peer; 420 } 421 422 // ---- NON-COMPONENT PEERS ---- // 423 424 @Override 425 public ColorModel getColorModel() throws HeadlessException { 426 return GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration().getColorModel(); 427 } 428 429 @Override 430 public boolean isDesktopSupported() { 431 return true; 432 } 433 434 @Override 435 protected DesktopPeer createDesktopPeer(Desktop target) { 436 return new CDesktopPeer(); 437 } 438 439 @Override 440 public DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent dge) { 441 DragSourceContextPeer dscp = CDragSourceContextPeer.createDragSourceContextPeer(dge); 442 443 return dscp; 444 } 445 446 @Override 447 public KeyboardFocusManagerPeer getKeyboardFocusManagerPeer() { 448 return LWKeyboardFocusManagerPeer.getInstance(); 449 } 450 451 @Override 452 public synchronized MouseInfoPeer getMouseInfoPeer() { 453 if (mouseInfoPeer == null) { 454 mouseInfoPeer = createMouseInfoPeerImpl(); 455 } 456 return mouseInfoPeer; 457 } 458 459 protected MouseInfoPeer createMouseInfoPeerImpl() { 460 return new LWMouseInfoPeer(); 461 } 462 463 public PrintJob getPrintJob(Frame frame, String doctitle, Properties props) { 464 return getPrintJob(frame, doctitle, null, null); 465 } 466 467 public PrintJob getPrintJob(Frame frame, String doctitle, JobAttributes jobAttributes, PageAttributes pageAttributes) { 468 if (GraphicsEnvironment.isHeadless()) { 469 throw new IllegalArgumentException(); 470 } 471 472 PrintJob2D printJob = new PrintJob2D(frame, doctitle, jobAttributes, pageAttributes); 473 474 if (printJob.printDialog() == false) { 475 printJob = null; 476 } 477 478 return printJob; 479 } 480 481 @Override 482 public RobotPeer createRobot(Robot target, GraphicsDevice screen) { 483 throw new RuntimeException("not implemented"); 484 } 485 486 @Override 487 public boolean isTraySupported() { 488 throw new RuntimeException("not implemented"); 489 } 490 491 @Override 492 public SystemTrayPeer createSystemTray(SystemTray target) { 493 throw new RuntimeException("not implemented"); 494 } 495 496 @Override 497 public TrayIconPeer createTrayIcon(TrayIcon target) { 498 throw new RuntimeException("not implemented"); 499 } 500 501 @Override 502 public Clipboard getSystemClipboard() { 503 SecurityManager security = System.getSecurityManager(); 504 if (security != null) { 505 security.checkSystemClipboardAccess(); 506 } 507 508 synchronized (this) { 509 if (clipboard == null) { 510 clipboard = createPlatformClipboard(); 511 } 512 } 513 return clipboard; 514 } 515 516 protected abstract SecurityWarningWindow createSecurityWarning(Window ownerWindow, LWWindowPeer ownerPeer); 517 518 // ---- DELEGATES ---- // 519 520 public abstract Clipboard createPlatformClipboard(); 521 522 /* 523 * Creates a delegate for the given peer type (window, frame, dialog, etc.) 524 */ 525 protected abstract PlatformWindow createPlatformWindow(LWWindowPeer.PeerType peerType); 526 527 protected abstract PlatformComponent createPlatformComponent(); 528 529 protected abstract PlatformComponent createLwPlatformComponent(); 530 531 protected abstract FileDialogPeer createFileDialogPeer(FileDialog target); 532 533 // ---- UTILITY METHODS ---- // 534 535 /* 536 * Expose non-public targetToPeer() method. 537 */ 538 public final static Object targetToPeer(Object target) { 539 return SunToolkit.targetToPeer(target); 540 } 541 542 /* 543 * Expose non-public targetDisposedPeer() method. 544 */ 545 public final static void targetDisposedPeer(Object target, Object peer) { 546 SunToolkit.targetDisposedPeer(target, peer); 547 } 548 549 /* 550 * Returns the current cursor manager. 551 */ 552 public abstract LWCursorManager getCursorManager(); 553 554 public static void postEvent(AWTEvent event) { 555 postEvent(targetToAppContext(event.getSource()), event); 556 } 557 558 @Override 559 public void grab(final Window w) { 560 final Object peer = AWTAccessor.getComponentAccessor().getPeer(w); 561 if (peer != null) { 562 ((LWWindowPeer) peer).grab(); 563 } 564 } 565 566 @Override 567 public void ungrab(final Window w) { 568 final Object peer = AWTAccessor.getComponentAccessor().getPeer(w); 569 if (peer != null) { 570 ((LWWindowPeer) peer).ungrab(false); 571 } 572 } 573 574 @Override 575 protected final Object lazilyLoadDesktopProperty(final String name) { 576 if (name.equals("awt.dynamicLayoutSupported")) { 577 return isDynamicLayoutSupported(); 578 } 579 return super.lazilyLoadDesktopProperty(name); 580 } 581 582 @Override 583 public final void setDynamicLayout(final boolean dynamic) { 584 dynamicLayoutSetting = dynamic; 585 } 586 587 @Override 588 protected final boolean isDynamicLayoutSet() { 589 return dynamicLayoutSetting; 590 } 591 592 @Override 593 public final boolean isDynamicLayoutActive() { 594 // "Live resizing" is active by default and user's data is ignored. 595 return isDynamicLayoutSupported(); 596 } 597 598 /** 599 * Returns true if dynamic layout of Containers on resize is supported by 600 * the underlying operating system and/or window manager. 601 */ 602 protected final boolean isDynamicLayoutSupported() { 603 // "Live resizing" is supported by default. 604 return true; 605 } 606 }