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 }