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