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 @Override 222 public WindowPeer createWindow(Window target) { 223 PlatformComponent platformComponent = createPlatformComponent(); 224 PlatformWindow platformWindow = createPlatformWindow(LWWindowPeer.PeerType.SIMPLEWINDOW); 225 return createDelegatedPeer(target, platformComponent, platformWindow, LWWindowPeer.PeerType.SIMPLEWINDOW); 226 } 227 228 @Override 229 public FramePeer createFrame(Frame target) { 230 PlatformComponent platformComponent = createPlatformComponent(); 231 PlatformWindow platformWindow = createPlatformWindow(LWWindowPeer.PeerType.FRAME); 232 return createDelegatedPeer(target, platformComponent, platformWindow, LWWindowPeer.PeerType.FRAME); 233 } 234 235 public LWWindowPeer createEmbeddedFrame(CEmbeddedFrame target) { 236 PlatformComponent platformComponent = createPlatformComponent(); 237 PlatformWindow platformWindow = createPlatformWindow(LWWindowPeer.PeerType.EMBEDDED_FRAME); 238 return createDelegatedPeer(target, platformComponent, platformWindow, LWWindowPeer.PeerType.EMBEDDED_FRAME); 239 } 240 241 public LWWindowPeer createEmbeddedFrame(CViewEmbeddedFrame target) { 242 PlatformComponent platformComponent = createPlatformComponent(); 243 PlatformWindow platformWindow = createPlatformWindow(LWWindowPeer.PeerType.VIEW_EMBEDDED_FRAME); 244 return createDelegatedPeer(target, platformComponent, platformWindow, LWWindowPeer.PeerType.VIEW_EMBEDDED_FRAME); 245 } 246 247 248 CPrinterDialogPeer createCPrinterDialog(CPrinterDialog target) { 249 PlatformComponent platformComponent = createPlatformComponent(); 250 PlatformWindow platformWindow = createPlatformWindow(LWWindowPeer.PeerType.DIALOG); 251 CPrinterDialogPeer peer = new CPrinterDialogPeer(target, platformComponent, platformWindow); 252 targetCreatedPeer(target, peer); 253 return peer; 254 } 255 256 @Override 257 public DialogPeer createDialog(Dialog target) { 258 if (target instanceof CPrinterDialog) { 259 return createCPrinterDialog((CPrinterDialog)target); 260 } 261 262 PlatformComponent platformComponent = createPlatformComponent(); 263 PlatformWindow platformWindow = createPlatformWindow(LWWindowPeer.PeerType.DIALOG); 264 return createDelegatedPeer(target, platformComponent, platformWindow, LWWindowPeer.PeerType.DIALOG); 265 } 266 267 @Override 268 public FileDialogPeer createFileDialog(FileDialog target) { 269 FileDialogPeer peer = createFileDialogPeer(target); 270 targetCreatedPeer(target, peer); 271 return peer; 272 } 273 274 // ---- LIGHTWEIGHT COMPONENT PEERS ---- // 275 276 @Override 277 public ButtonPeer createButton(Button target) { 278 PlatformComponent platformComponent = createPlatformComponent(); 279 LWButtonPeer peer = new LWButtonPeer(target, platformComponent); 280 targetCreatedPeer(target, peer); 281 peer.initialize(); 282 return peer; 283 } 284 285 @Override 286 public CheckboxPeer createCheckbox(Checkbox target) { 287 PlatformComponent platformComponent = createPlatformComponent(); 288 LWCheckboxPeer peer = new LWCheckboxPeer(target, platformComponent); 289 targetCreatedPeer(target, peer); 290 peer.initialize(); 291 return peer; 292 } 293 294 @Override 295 public CheckboxMenuItemPeer createCheckboxMenuItem(CheckboxMenuItem target) { 296 throw new RuntimeException("not implemented"); 297 } 298 299 @Override 300 public ChoicePeer createChoice(Choice target) { 301 PlatformComponent platformComponent = createPlatformComponent(); 302 LWChoicePeer peer = new LWChoicePeer(target, platformComponent); 303 targetCreatedPeer(target, peer); 304 peer.initialize(); 305 return peer; 306 } 307 308 @Override 309 public LabelPeer createLabel(Label target) { 310 PlatformComponent platformComponent = createPlatformComponent(); 311 LWLabelPeer peer = new LWLabelPeer(target, platformComponent); 312 targetCreatedPeer(target, peer); 313 peer.initialize(); 314 return peer; 315 } 316 317 @Override 318 public CanvasPeer createCanvas(Canvas target) { 319 PlatformComponent platformComponent = createPlatformComponent(); 320 LWCanvasPeer<?, ?> peer = new LWCanvasPeer<>(target, platformComponent); 321 targetCreatedPeer(target, peer); 322 peer.initialize(); 323 return peer; 324 } 325 326 @Override 327 public ListPeer createList(List target) { 328 PlatformComponent platformComponent = createPlatformComponent(); 329 LWListPeer peer = new LWListPeer(target, platformComponent); 330 targetCreatedPeer(target, peer); 331 peer.initialize(); 332 return peer; 333 } 334 335 @Override 336 public MenuPeer createMenu(Menu target) { 337 throw new RuntimeException("not implemented"); 338 } 339 340 @Override 341 public MenuBarPeer createMenuBar(MenuBar target) { 342 throw new RuntimeException("not implemented"); 343 } 344 345 @Override 346 public MenuItemPeer createMenuItem(MenuItem target) { 347 throw new RuntimeException("not implemented"); 348 } 349 350 @Override 351 public PanelPeer createPanel(Panel target) { 352 PlatformComponent platformComponent = createPlatformComponent(); 353 LWPanelPeer peer = new LWPanelPeer(target, platformComponent); 354 targetCreatedPeer(target, peer); 355 peer.initialize(); 356 return peer; 357 } 358 359 @Override 360 public PopupMenuPeer createPopupMenu(PopupMenu target) { 361 throw new RuntimeException("not implemented"); 362 } 363 364 @Override 365 public ScrollPanePeer createScrollPane(ScrollPane target) { 366 PlatformComponent platformComponent = createPlatformComponent(); 367 LWScrollPanePeer peer = new LWScrollPanePeer(target, platformComponent); 368 targetCreatedPeer(target, peer); 369 peer.initialize(); 370 return peer; 371 } 372 373 @Override 374 public ScrollbarPeer createScrollbar(Scrollbar target) { 375 PlatformComponent platformComponent = createPlatformComponent(); 376 LWScrollBarPeer peer = new LWScrollBarPeer(target, platformComponent); 377 targetCreatedPeer(target, peer); 378 peer.initialize(); 379 return peer; 380 } 381 382 @Override 383 public TextAreaPeer createTextArea(TextArea target) { 384 PlatformComponent platformComponent = createPlatformComponent(); 385 LWTextAreaPeer peer = new LWTextAreaPeer(target, platformComponent); 386 targetCreatedPeer(target, peer); 387 peer.initialize(); 388 return peer; 389 } 390 391 @Override 392 public TextFieldPeer createTextField(TextField target) { 393 PlatformComponent platformComponent = createPlatformComponent(); 394 LWTextFieldPeer peer = new LWTextFieldPeer(target, platformComponent); 395 targetCreatedPeer(target, peer); 396 peer.initialize(); 397 return peer; 398 } 399 400 // ---- NON-COMPONENT PEERS ---- // 401 402 @Override 403 public ColorModel getColorModel() throws HeadlessException { 404 return GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration().getColorModel(); 405 } 406 407 @Override 408 public boolean isDesktopSupported() { 409 return true; 410 } 411 412 @Override 413 protected DesktopPeer createDesktopPeer(Desktop target) { 414 return new CDesktopPeer(); 415 } 416 417 @Override 418 public DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent dge) { 419 DragSourceContextPeer dscp = CDragSourceContextPeer.createDragSourceContextPeer(dge); 420 421 return dscp; 422 } 423 424 @Override 425 public KeyboardFocusManagerPeer getKeyboardFocusManagerPeer() { 426 return LWKeyboardFocusManagerPeer.getInstance(); 427 } 428 429 @Override 430 public synchronized MouseInfoPeer getMouseInfoPeer() { 431 if (mouseInfoPeer == null) { 432 mouseInfoPeer = createMouseInfoPeerImpl(); 433 } 434 return mouseInfoPeer; 435 } 436 437 protected MouseInfoPeer createMouseInfoPeerImpl() { 438 return new LWMouseInfoPeer(); 439 } 440 441 public PrintJob getPrintJob(Frame frame, String doctitle, Properties props) { 442 return getPrintJob(frame, doctitle, null, null); 443 } 444 445 public PrintJob getPrintJob(Frame frame, String doctitle, JobAttributes jobAttributes, PageAttributes pageAttributes) { 446 if (GraphicsEnvironment.isHeadless()) { 447 throw new IllegalArgumentException(); 448 } 449 450 PrintJob2D printJob = new PrintJob2D(frame, doctitle, jobAttributes, pageAttributes); 451 452 if (printJob.printDialog() == false) { 453 printJob = null; 454 } 455 456 return printJob; 457 } 458 459 @Override 460 public RobotPeer createRobot(Robot target, GraphicsDevice screen) { 461 throw new RuntimeException("not implemented"); 462 } 463 464 @Override 465 public boolean isTraySupported() { 466 throw new RuntimeException("not implemented"); 467 } 468 469 @Override 470 public SystemTrayPeer createSystemTray(SystemTray target) { 471 throw new RuntimeException("not implemented"); 472 } 473 474 @Override 475 public TrayIconPeer createTrayIcon(TrayIcon target) { 476 throw new RuntimeException("not implemented"); 477 } 478 479 @Override 480 public Clipboard getSystemClipboard() { 481 SecurityManager security = System.getSecurityManager(); 482 if (security != null) { 483 security.checkSystemClipboardAccess(); 484 } 485 486 synchronized (this) { 487 if (clipboard == null) { 488 clipboard = createPlatformClipboard(); 489 } 490 } 491 return clipboard; 492 } 493 494 // ---- DELEGATES ---- // 495 496 public abstract Clipboard createPlatformClipboard(); 497 498 /* 499 * Creates a delegate for the given peer type (window, frame, dialog, etc.) 500 */ 501 protected abstract PlatformWindow createPlatformWindow(LWWindowPeer.PeerType peerType); 502 503 protected abstract PlatformComponent createPlatformComponent(); 504 505 protected abstract FileDialogPeer createFileDialogPeer(FileDialog target); 506 507 // ---- UTILITY METHODS ---- // 508 509 /* 510 * Expose non-public targetToPeer() method. 511 */ 512 public final static Object targetToPeer(Object target) { 513 return SunToolkit.targetToPeer(target); 514 } 515 516 /* 517 * Expose non-public targetDisposedPeer() method. 518 */ 519 public final static void targetDisposedPeer(Object target, Object peer) { 520 SunToolkit.targetDisposedPeer(target, peer); 521 } 522 523 /* 524 * Returns the current cursor manager. 525 */ 526 public abstract LWCursorManager getCursorManager(); 527 528 public static void postEvent(AWTEvent event) { 529 postEvent(targetToAppContext(event.getSource()), event); 530 } 531 532 @Override 533 public void grab(Window w) { 534 if (w.getPeer() != null) { 535 ((LWWindowPeer)w.getPeer()).grab(); 536 } 537 } 538 539 @Override 540 public void ungrab(Window w) { 541 if (w.getPeer() != null) { 542 ((LWWindowPeer)w.getPeer()).ungrab(false); 543 } 544 } 545 }