Print this page
*** NO COMMENTS ***
Split |
Close |
Expand all |
Collapse all |
--- old/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java
+++ new/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java
1 1 /*
2 2 * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
3 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 4 *
5 5 * This code is free software; you can redistribute it and/or modify it
6 6 * under the terms of the GNU General Public License version 2 only, as
7 7 * published by the Free Software Foundation. Oracle designates this
8 8 * particular file as subject to the "Classpath" exception as provided
9 9 * by Oracle in the LICENSE file that accompanied this code.
10 10 *
11 11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 14 * version 2 for more details (a copy is included in the LICENSE file that
15 15 * accompanied this code).
16 16 *
17 17 * You should have received a copy of the GNU General Public License version
18 18 * 2 along with this work; if not, write to the Free Software Foundation,
19 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 20 *
21 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 22 * or visit www.oracle.com if you need additional information or have any
23 23 * questions.
24 24 */
25 25
26 26 package sun.lwawt.macosx;
27 27
28 28 import java.awt.*;
29 29 import java.awt.datatransfer.Clipboard;
30 30 import java.awt.dnd.*;
31 31 import java.awt.dnd.peer.DragSourceContextPeer;
32 32 import java.awt.event.InputEvent;
33 33 import java.awt.event.InvocationEvent;
34 34 import java.awt.event.KeyEvent;
35 35 import java.awt.font.TextAttribute;
36 36 import java.awt.im.InputMethodHighlight;
37 37 import java.awt.im.spi.InputMethodDescriptor;
38 38 import java.awt.peer.*;
39 39 import java.lang.reflect.*;
40 40 import java.net.URL;
41 41 import java.security.*;
42 42 import java.util.*;
43 43 import java.util.concurrent.Callable;
44 44 import java.net.MalformedURLException;
45 45
46 46 import sun.awt.*;
47 47 import sun.awt.datatransfer.DataTransferer;
48 48 import sun.awt.util.ThreadGroupUtils;
49 49 import sun.java2d.opengl.OGLRenderQueue;
50 50 import sun.lwawt.*;
51 51 import sun.lwawt.LWWindowPeer.PeerType;
52 52 import sun.security.action.GetBooleanAction;
53 53
54 54 import sun.util.CoreResourceBundleControl;
55 55
56 56 @SuppressWarnings("serial") // JDK implementation class
57 57 final class NamedCursor extends Cursor {
58 58 NamedCursor(String name) {
59 59 super(name);
60 60 }
61 61 }
62 62
63 63 /**
64 64 * Mac OS X Cocoa-based AWT Toolkit.
65 65 */
66 66 public final class LWCToolkit extends LWToolkit {
67 67 // While it is possible to enumerate all mouse devices
68 68 // and query them for the number of buttons, the code
69 69 // that does it is rather complex. Instead, we opt for
70 70 // the easy way and just support up to 5 mouse buttons,
71 71 // like Windows.
72 72 private static final int BUTTONS = 5;
73 73
74 74 private static native void initIDs();
75 75 private static native void initAppkit(ThreadGroup appKitThreadGroup, boolean headless);
76 76 private static CInputMethodDescriptor sInputMethodDescriptor;
77 77
78 78 static {
79 79 System.err.flush();
80 80
81 81 ResourceBundle platformResources = java.security.AccessController.doPrivileged(
82 82 new java.security.PrivilegedAction<ResourceBundle>() {
83 83 @Override
84 84 public ResourceBundle run() {
85 85 ResourceBundle platformResources = null;
86 86 try {
87 87 platformResources =
88 88 ResourceBundle.getBundle("sun.awt.resources.awtosx",
89 89 CoreResourceBundleControl.getRBControlInstance());
90 90 } catch (MissingResourceException e) {
91 91 // No resource file; defaults will be used.
92 92 }
93 93
94 94 System.loadLibrary("awt");
95 95 System.loadLibrary("fontmanager");
96 96
97 97 return platformResources;
98 98 }
99 99 });
100 100
101 101 AWTAccessor.getToolkitAccessor().setPlatformResources(platformResources);
102 102
103 103 if (!GraphicsEnvironment.isHeadless()) {
104 104 initIDs();
105 105 }
106 106 inAWT = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
107 107 @Override
108 108 public Boolean run() {
109 109 return !Boolean.parseBoolean(System.getProperty("javafx.embed.singleThread", "false"));
110 110 }
111 111 });
112 112 }
113 113
114 114 /*
115 115 * If true we operate in normal mode and nested runloop is executed in JavaRunLoopMode
116 116 * If false we operate in singleThreaded FX/AWT interop mode and nested loop uses NSDefaultRunLoopMode
117 117 */
118 118 private static final boolean inAWT;
119 119
120 120 public LWCToolkit() {
121 121 areExtraMouseButtonsEnabled = Boolean.parseBoolean(System.getProperty("sun.awt.enableExtraMouseButtons", "true"));
122 122 //set system property if not yet assigned
123 123 System.setProperty("sun.awt.enableExtraMouseButtons", ""+areExtraMouseButtonsEnabled);
124 124 initAppkit(ThreadGroupUtils.getRootThreadGroup(), GraphicsEnvironment.isHeadless());
125 125 }
126 126
127 127 /*
128 128 * System colors with default initial values, overwritten by toolkit if system values differ and are available.
129 129 */
130 130 private final static int NUM_APPLE_COLORS = 3;
131 131 public final static int KEYBOARD_FOCUS_COLOR = 0;
132 132 public final static int INACTIVE_SELECTION_BACKGROUND_COLOR = 1;
133 133 public final static int INACTIVE_SELECTION_FOREGROUND_COLOR = 2;
134 134 private static int[] appleColors = {
135 135 0xFF808080, // keyboardFocusColor = Color.gray;
136 136 0xFFC0C0C0, // secondarySelectedControlColor
137 137 0xFF303030, // controlDarkShadowColor
138 138 };
139 139
140 140 private native void loadNativeColors(final int[] systemColors, final int[] appleColors);
141 141
142 142 @Override
143 143 protected void loadSystemColors(final int[] systemColors) {
144 144 if (systemColors == null) return;
145 145 loadNativeColors(systemColors, appleColors);
146 146 }
147 147
148 148 @SuppressWarnings("serial") // JDK implementation class
149 149 private static class AppleSpecificColor extends Color {
150 150 private final int index;
151 151 AppleSpecificColor(int index) {
152 152 super(appleColors[index]);
153 153 this.index = index;
154 154 }
155 155
156 156 @Override
157 157 public int getRGB() {
158 158 return appleColors[index];
159 159 }
160 160 }
161 161
162 162 /**
163 163 * Returns Apple specific colors that we may expose going forward.
164 164 */
165 165 public static Color getAppleColor(int color) {
166 166 return new AppleSpecificColor(color);
167 167 }
168 168
169 169 // This is only called from native code.
170 170 static void systemColorsChanged() {
171 171 EventQueue.invokeLater(() -> {
172 172 AccessController.doPrivileged( (PrivilegedAction<Object>) () -> {
173 173 AWTAccessor.getSystemColorAccessor().updateSystemColors();
174 174 return null;
175 175 });
176 176 });
177 177 }
178 178
179 179 public static LWCToolkit getLWCToolkit() {
180 180 return (LWCToolkit)Toolkit.getDefaultToolkit();
181 181 }
182 182
183 183 @Override
184 184 protected PlatformWindow createPlatformWindow(PeerType peerType) {
185 185 if (peerType == PeerType.EMBEDDED_FRAME) {
186 186 return new CPlatformEmbeddedFrame();
187 187 } else if (peerType == PeerType.VIEW_EMBEDDED_FRAME) {
188 188 return new CViewPlatformEmbeddedFrame();
189 189 } else if (peerType == PeerType.LW_FRAME) {
190 190 return new CPlatformLWWindow();
191 191 } else {
192 192 assert (peerType == PeerType.SIMPLEWINDOW
193 193 || peerType == PeerType.DIALOG
194 194 || peerType == PeerType.FRAME);
195 195 return new CPlatformWindow();
196 196 }
197 197 }
198 198
199 199 LWWindowPeer createEmbeddedFrame(CEmbeddedFrame target) {
200 200 PlatformComponent platformComponent = createPlatformComponent();
201 201 PlatformWindow platformWindow = createPlatformWindow(PeerType.EMBEDDED_FRAME);
202 202 return createDelegatedPeer(target, platformComponent, platformWindow, PeerType.EMBEDDED_FRAME);
203 203 }
204 204
205 205 LWWindowPeer createEmbeddedFrame(CViewEmbeddedFrame target) {
206 206 PlatformComponent platformComponent = createPlatformComponent();
207 207 PlatformWindow platformWindow = createPlatformWindow(PeerType.VIEW_EMBEDDED_FRAME);
208 208 return createDelegatedPeer(target, platformComponent, platformWindow, PeerType.VIEW_EMBEDDED_FRAME);
209 209 }
210 210
211 211 private CPrinterDialogPeer createCPrinterDialog(CPrinterDialog target) {
212 212 PlatformComponent platformComponent = createPlatformComponent();
213 213 PlatformWindow platformWindow = createPlatformWindow(PeerType.DIALOG);
214 214 CPrinterDialogPeer peer = new CPrinterDialogPeer(target, platformComponent, platformWindow);
215 215 targetCreatedPeer(target, peer);
216 216 return peer;
217 217 }
218 218
219 219 @Override
220 220 public DialogPeer createDialog(Dialog target) {
221 221 if (target instanceof CPrinterDialog) {
222 222 return createCPrinterDialog((CPrinterDialog)target);
223 223 }
224 224 return super.createDialog(target);
225 225 }
226 226
227 227 @Override
228 228 protected SecurityWarningWindow createSecurityWarning(Window ownerWindow,
229 229 LWWindowPeer ownerPeer) {
230 230 return new CWarningWindow(ownerWindow, ownerPeer);
231 231 }
232 232
233 233 @Override
234 234 protected PlatformComponent createPlatformComponent() {
235 235 return new CPlatformComponent();
236 236 }
237 237
238 238 @Override
239 239 protected PlatformComponent createLwPlatformComponent() {
240 240 return new CPlatformLWComponent();
241 241 }
242 242
243 243 @Override
244 244 protected FileDialogPeer createFileDialogPeer(FileDialog target) {
245 245 return new CFileDialog(target);
246 246 }
247 247
248 248 @Override
249 249 public MenuPeer createMenu(Menu target) {
250 250 MenuPeer peer = new CMenu(target);
251 251 targetCreatedPeer(target, peer);
252 252 return peer;
253 253 }
254 254
255 255 @Override
256 256 public MenuBarPeer createMenuBar(MenuBar target) {
257 257 MenuBarPeer peer = new CMenuBar(target);
258 258 targetCreatedPeer(target, peer);
259 259 return peer;
260 260 }
261 261
262 262 @Override
263 263 public MenuItemPeer createMenuItem(MenuItem target) {
264 264 MenuItemPeer peer = new CMenuItem(target);
265 265 targetCreatedPeer(target, peer);
266 266 return peer;
267 267 }
268 268
269 269 @Override
270 270 public CheckboxMenuItemPeer createCheckboxMenuItem(CheckboxMenuItem target) {
271 271 CheckboxMenuItemPeer peer = new CCheckboxMenuItem(target);
272 272 targetCreatedPeer(target, peer);
273 273 return peer;
274 274 }
275 275
276 276 @Override
277 277 public PopupMenuPeer createPopupMenu(PopupMenu target) {
278 278 PopupMenuPeer peer = new CPopupMenu(target);
279 279 targetCreatedPeer(target, peer);
280 280 return peer;
281 281 }
282 282
283 283 @Override
284 284 public SystemTrayPeer createSystemTray(SystemTray target) {
285 285 return new CSystemTray();
286 286 }
287 287
288 288 @Override
289 289 public TrayIconPeer createTrayIcon(TrayIcon target) {
290 290 TrayIconPeer peer = new CTrayIcon(target);
291 291 targetCreatedPeer(target, peer);
292 292 return peer;
293 293 }
294 294
295 295 @Override
296 296 protected DesktopPeer createDesktopPeer(Desktop target) {
297 297 return new CDesktopPeer();
298 298 }
299 299
300 300 @Override
301 301 public LWCursorManager getCursorManager() {
302 302 return CCursorManager.getInstance();
303 303 }
304 304
305 305 @Override
306 306 public Cursor createCustomCursor(final Image cursor, final Point hotSpot,
307 307 final String name)
308 308 throws IndexOutOfBoundsException, HeadlessException {
309 309 return new CCustomCursor(cursor, hotSpot, name);
310 310 }
311 311
312 312 @Override
313 313 public Dimension getBestCursorSize(final int preferredWidth,
314 314 final int preferredHeight)
315 315 throws HeadlessException {
316 316 return CCustomCursor.getBestCursorSize(preferredWidth, preferredHeight);
317 317 }
318 318
319 319 @Override
320 320 protected void platformCleanup() {
321 321 // TODO Auto-generated method stub
322 322 }
323 323
324 324 @Override
325 325 protected void platformInit() {
326 326 // TODO Auto-generated method stub
327 327 }
328 328
329 329 @Override
330 330 protected void platformRunMessage() {
331 331 // TODO Auto-generated method stub
332 332 }
333 333
334 334 @Override
335 335 protected void platformShutdown() {
336 336 // TODO Auto-generated method stub
337 337 }
338 338
339 339 class OSXPlatformFont extends sun.awt.PlatformFont
340 340 {
341 341 OSXPlatformFont(String name, int style)
342 342 {
343 343 super(name, style);
344 344 }
345 345 @Override
346 346 protected char getMissingGlyphCharacter()
347 347 {
348 348 // Follow up for real implementation
349 349 return (char)0xfff8; // see http://developer.apple.com/fonts/LastResortFont/
350 350 }
351 351 }
352 352 @Override
353 353 public FontPeer getFontPeer(String name, int style) {
354 354 return new OSXPlatformFont(name, style);
355 355 }
356 356
357 357 @Override
358 358 protected int getScreenHeight() {
359 359 return GraphicsEnvironment.getLocalGraphicsEnvironment()
360 360 .getDefaultScreenDevice().getDefaultConfiguration().getBounds().height;
361 361 }
362 362
363 363 @Override
364 364 protected int getScreenWidth() {
365 365 return GraphicsEnvironment.getLocalGraphicsEnvironment()
366 366 .getDefaultScreenDevice().getDefaultConfiguration().getBounds().width;
367 367 }
368 368
369 369 @Override
370 370 protected void initializeDesktopProperties() {
371 371 super.initializeDesktopProperties();
372 372 Map <Object, Object> fontHints = new HashMap<>();
373 373 fontHints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
374 374 fontHints.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
375 375 desktopProperties.put(SunToolkit.DESKTOPFONTHINTS, fontHints);
376 376 desktopProperties.put("awt.mouse.numButtons", BUTTONS);
377 377
378 378 // These DnD properties must be set, otherwise Swing ends up spewing NPEs
379 379 // all over the place. The values came straight off of MToolkit.
380 380 desktopProperties.put("DnD.Autoscroll.initialDelay", new Integer(50));
381 381 desktopProperties.put("DnD.Autoscroll.interval", new Integer(50));
382 382 desktopProperties.put("DnD.Autoscroll.cursorHysteresis", new Integer(5));
383 383
384 384 desktopProperties.put("DnD.isDragImageSupported", new Boolean(true));
385 385
386 386 // Register DnD cursors
387 387 desktopProperties.put("DnD.Cursor.CopyDrop", new NamedCursor("DnD.Cursor.CopyDrop"));
388 388 desktopProperties.put("DnD.Cursor.MoveDrop", new NamedCursor("DnD.Cursor.MoveDrop"));
389 389 desktopProperties.put("DnD.Cursor.LinkDrop", new NamedCursor("DnD.Cursor.LinkDrop"));
390 390 desktopProperties.put("DnD.Cursor.CopyNoDrop", new NamedCursor("DnD.Cursor.CopyNoDrop"));
391 391 desktopProperties.put("DnD.Cursor.MoveNoDrop", new NamedCursor("DnD.Cursor.MoveNoDrop"));
392 392 desktopProperties.put("DnD.Cursor.LinkNoDrop", new NamedCursor("DnD.Cursor.LinkNoDrop"));
393 393 }
394 394
395 395 @Override
396 396 protected boolean syncNativeQueue(long timeout) {
397 397 return nativeSyncQueue(timeout);
398 398 }
399 399
400 400 @Override
401 401 public native void beep();
402 402
403 403 @Override
404 404 public int getScreenResolution() throws HeadlessException {
405 405 return (int) ((CGraphicsDevice) GraphicsEnvironment
406 406 .getLocalGraphicsEnvironment().getDefaultScreenDevice())
407 407 .getXResolution();
408 408 }
409 409
410 410 @Override
411 411 public Insets getScreenInsets(final GraphicsConfiguration gc) {
412 412 return ((CGraphicsConfig) gc).getDevice().getScreenInsets();
413 413 }
414 414
415 415 @Override
416 416 public void sync() {
417 417 // flush the OGL pipeline (this is a no-op if OGL is not enabled)
418 418 OGLRenderQueue.sync();
419 419 // setNeedsDisplay() selector was sent to the appropriate CALayer so now
420 420 // we have to flush the native selectors queue.
421 421 flushNativeSelectors();
422 422 }
423 423
424 424 @Override
425 425 public RobotPeer createRobot(Robot target, GraphicsDevice screen) {
426 426 return new CRobot(target, (CGraphicsDevice)screen);
427 427 }
428 428
429 429 private native boolean isCapsLockOn();
430 430
431 431 /*
432 432 * NOTE: Among the keys this method is supposed to check,
433 433 * only Caps Lock works as a true locking key with OS X.
434 434 * There is no Scroll Lock key on modern Apple keyboards,
435 435 * and with a PC keyboard plugged in Scroll Lock is simply
436 436 * ignored: no LED lights up if you press it.
437 437 * The key located at the same position on Apple keyboards
438 438 * as Num Lock on PC keyboards is called Clear, doesn't lock
439 439 * anything and is used for entirely different purpose.
440 440 */
441 441 @Override
442 442 public boolean getLockingKeyState(int keyCode) throws UnsupportedOperationException {
443 443 switch (keyCode) {
444 444 case KeyEvent.VK_NUM_LOCK:
445 445 case KeyEvent.VK_SCROLL_LOCK:
446 446 case KeyEvent.VK_KANA_LOCK:
447 447 throw new UnsupportedOperationException("Toolkit.getLockingKeyState");
448 448
449 449 case KeyEvent.VK_CAPS_LOCK:
450 450 return isCapsLockOn();
451 451
452 452 default:
453 453 throw new IllegalArgumentException("invalid key for Toolkit.getLockingKeyState");
454 454 }
455 455 }
456 456
457 457 //Is it allowed to generate events assigned to extra mouse buttons.
458 458 //Set to true by default.
459 459 private static boolean areExtraMouseButtonsEnabled = true;
460 460
461 461 @Override
462 462 public boolean areExtraMouseButtonsEnabled() throws HeadlessException {
463 463 return areExtraMouseButtonsEnabled;
464 464 }
465 465
466 466 @Override
467 467 public int getNumberOfButtons(){
468 468 return BUTTONS;
469 469 }
470 470
471 471 @Override
472 472 public boolean isTraySupported() {
473 473 return true;
474 474 }
475 475
476 476 @Override
477 477 public DataTransferer getDataTransferer() {
478 478 return CDataTransferer.getInstanceImpl();
479 479 }
480 480
481 481 @Override
482 482 public boolean isAlwaysOnTopSupported() {
483 483 return true;
484 484 }
485 485
486 486 private static final String APPKIT_THREAD_NAME = "AppKit Thread";
487 487
488 488 // Intended to be called from the LWCToolkit.m only.
489 489 private static void installToolkitThreadInJava() {
490 490 Thread.currentThread().setName(APPKIT_THREAD_NAME);
491 491 AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
492 492 Thread.currentThread().setContextClassLoader(null);
493 493 return null;
494 494 });
495 495 }
496 496
497 497 @Override
498 498 public boolean isWindowOpacitySupported() {
499 499 return true;
500 500 }
501 501
502 502 @Override
503 503 public boolean isFrameStateSupported(int state) throws HeadlessException {
504 504 switch (state) {
505 505 case Frame.NORMAL:
506 506 case Frame.ICONIFIED:
507 507 case Frame.MAXIMIZED_BOTH:
508 508 return true;
509 509 default:
510 510 return false;
511 511 }
512 512 }
513 513
514 514 /**
515 515 * Determines which modifier key is the appropriate accelerator
516 516 * key for menu shortcuts.
517 517 * <p>
518 518 * Menu shortcuts, which are embodied in the
519 519 * <code>MenuShortcut</code> class, are handled by the
520 520 * <code>MenuBar</code> class.
521 521 * <p>
522 522 * By default, this method returns <code>Event.CTRL_MASK</code>.
523 523 * Toolkit implementations should override this method if the
524 524 * <b>Control</b> key isn't the correct key for accelerators.
525 525 * @return the modifier mask on the <code>Event</code> class
526 526 * that is used for menu shortcuts on this toolkit.
527 527 * @see java.awt.MenuBar
528 528 * @see java.awt.MenuShortcut
529 529 * @since 1.1
530 530 */
531 531 @Override
532 532 public int getMenuShortcutKeyMask() {
533 533 return Event.META_MASK;
534 534 }
535 535
536 536 @Override
537 537 public Image getImage(final String filename) {
538 538 final Image nsImage = checkForNSImage(filename);
539 539 if (nsImage != null) {
540 540 return nsImage;
541 541 }
542 542
543 543 if (imageCached(filename)) {
544 544 return super.getImage(filename);
545 545 }
546 546
547 547 String filename2x = getScaledImageName(filename);
548 548 return (imageExists(filename2x))
549 549 ? getImageWithResolutionVariant(filename, filename2x)
550 550 : super.getImage(filename);
551 551 }
552 552
553 553 @Override
554 554 public Image getImage(URL url) {
555 555
556 556 if (imageCached(url)) {
557 557 return super.getImage(url);
558 558 }
559 559
560 560 URL url2x = getScaledImageURL(url);
561 561 return (imageExists(url2x))
562 562 ? getImageWithResolutionVariant(url, url2x) : super.getImage(url);
563 563 }
564 564
565 565 private static final String nsImagePrefix = "NSImage://";
566 566 private Image checkForNSImage(final String imageName) {
567 567 if (imageName == null) return null;
568 568 if (!imageName.startsWith(nsImagePrefix)) return null;
569 569 return CImage.getCreator().createImageFromName(imageName.substring(nsImagePrefix.length()));
570 570 }
571 571
572 572 // Thread-safe Object.equals() called from native
573 573 public static boolean doEquals(final Object a, final Object b, Component c) {
574 574 if (a == b) return true;
575 575
576 576 final boolean[] ret = new boolean[1];
577 577
578 578 try { invokeAndWait(new Runnable() { public void run() { synchronized(ret) {
579 579 ret[0] = a.equals(b);
580 580 }}}, c); } catch (Exception e) { e.printStackTrace(); }
581 581
582 582 synchronized(ret) { return ret[0]; }
583 583 }
584 584
585 585 public static <T> T invokeAndWait(final Callable<T> callable,
586 586 Component component) throws Exception {
587 587 final CallableWrapper<T> wrapper = new CallableWrapper<>(callable);
588 588 invokeAndWait(wrapper, component);
589 589 return wrapper.getResult();
590 590 }
591 591
592 592 static final class CallableWrapper<T> implements Runnable {
593 593 final Callable<T> callable;
594 594 T object;
595 595 Exception e;
596 596
597 597 CallableWrapper(final Callable<T> callable) {
598 598 this.callable = callable;
599 599 }
600 600
601 601 @Override
602 602 public void run() {
603 603 try {
604 604 object = callable.call();
605 605 } catch (final Exception e) {
606 606 this.e = e;
607 607 }
608 608 }
609 609
610 610 public T getResult() throws Exception {
611 611 if (e != null) throw e;
612 612 return object;
613 613 }
614 614 }
615 615
616 616 /**
617 617 * Kicks an event over to the appropriate event queue and waits for it to
618 618 * finish To avoid deadlocking, we manually run the NSRunLoop while waiting
619 619 * Any selector invoked using ThreadUtilities performOnMainThread will be
620 620 * processed in doAWTRunLoop The InvocationEvent will call
621 621 * LWCToolkit.stopAWTRunLoop() when finished, which will stop our manual
622 622 * run loop. Does not dispatch native events while in the loop
623 623 */
624 624 public static void invokeAndWait(Runnable runnable, Component component)
625 625 throws InvocationTargetException {
626 626 Objects.requireNonNull(component, "Null component provided to invokeAndWait");
627 627
628 628 long mediator = createAWTRunLoopMediator();
629 629 InvocationEvent invocationEvent =
630 630 new InvocationEvent(component,
631 631 runnable,
632 632 () -> {
633 633 if (mediator != 0) {
634 634 stopAWTRunLoop(mediator);
635 635 }
636 636 },
637 637 true);
638 638
639 639 AppContext appContext = SunToolkit.targetToAppContext(component);
640 640 SunToolkit.postEvent(appContext, invocationEvent);
641 641 // 3746956 - flush events from PostEventQueue to prevent them from getting stuck and causing a deadlock
642 642 SunToolkit.flushPendingEvents(appContext);
643 643 doAWTRunLoop(mediator, false);
644 644
645 645 checkException(invocationEvent);
646 646 }
647 647
648 648 public static void invokeLater(Runnable event, Component component)
649 649 throws InvocationTargetException {
650 650 Objects.requireNonNull(component, "Null component provided to invokeLater");
651 651
652 652 InvocationEvent invocationEvent = new InvocationEvent(component, event);
653 653
654 654 AppContext appContext = SunToolkit.targetToAppContext(component);
655 655 SunToolkit.postEvent(SunToolkit.targetToAppContext(component), invocationEvent);
656 656 // 3746956 - flush events from PostEventQueue to prevent them from getting stuck and causing a deadlock
657 657 SunToolkit.flushPendingEvents(appContext);
658 658
659 659 checkException(invocationEvent);
660 660 }
661 661
662 662 /**
663 663 * Checks if exception occurred while {@code InvocationEvent} was processed and rethrows it as
664 664 * an {@code InvocationTargetException}
665 665 *
666 666 * @param event the event to check for an exception
667 667 * @throws InvocationTargetException if exception occurred when event was processed
668 668 */
669 669 private static void checkException(InvocationEvent event) throws InvocationTargetException {
670 670 Throwable eventException = event.getException();
671 671 if (eventException == null) return;
672 672
673 673 if (eventException instanceof UndeclaredThrowableException) {
674 674 eventException = ((UndeclaredThrowableException)eventException).getUndeclaredThrowable();
675 675 }
676 676 throw new InvocationTargetException(eventException);
677 677 }
678 678
679 679 /**
680 680 * Schedules a {@code Runnable} execution on the Appkit thread after a delay
681 681 * @param r a {@code Runnable} to execute
682 682 * @param delay a delay in milliseconds
683 683 */
684 684 native static void performOnMainThreadAfterDelay(Runnable r, long delay);
685 685
686 686 // DnD support
687 687
688 688 @Override
689 689 public DragSourceContextPeer createDragSourceContextPeer(
690 690 DragGestureEvent dge) throws InvalidDnDOperationException {
691 691 final LightweightFrame f = SunToolkit.getLightweightFrame(dge.getComponent());
692 692 if (f != null) {
693 693 return f.createDragSourceContextPeer(dge);
694 694 }
695 695
696 696 return CDragSourceContextPeer.createDragSourceContextPeer(dge);
697 697 }
698 698
699 699 @Override
700 700 @SuppressWarnings("unchecked")
701 701 public <T extends DragGestureRecognizer> T createDragGestureRecognizer(
702 702 Class<T> abstractRecognizerClass, DragSource ds, Component c,
703 703 int srcActions, DragGestureListener dgl) {
704 704 final LightweightFrame f = SunToolkit.getLightweightFrame(c);
705 705 if (f != null) {
706 706 return f.createDragGestureRecognizer(abstractRecognizerClass, ds, c, srcActions, dgl);
707 707 }
708 708
709 709 DragGestureRecognizer dgr = null;
710 710
711 711 // Create a new mouse drag gesture recognizer if we have a class match:
712 712 if (MouseDragGestureRecognizer.class.equals(abstractRecognizerClass))
713 713 dgr = new CMouseDragGestureRecognizer(ds, c, srcActions, dgl);
714 714
715 715 return (T)dgr;
716 716 }
717 717
718 718 @Override
719 719 protected PlatformDropTarget createDropTarget(DropTarget dropTarget,
720 720 Component component,
721 721 LWComponentPeer<?, ?> peer) {
722 722 return new CDropTarget(dropTarget, component, peer);
723 723 }
724 724
725 725 // InputMethodSupport Method
726 726 /**
727 727 * Returns the default keyboard locale of the underlying operating system
728 728 */
729 729 @Override
730 730 public Locale getDefaultKeyboardLocale() {
731 731 Locale locale = CInputMethod.getNativeLocale();
732 732
733 733 if (locale == null) {
734 734 return super.getDefaultKeyboardLocale();
735 735 }
736 736
737 737 return locale;
738 738 }
739 739
740 740 @Override
741 741 public InputMethodDescriptor getInputMethodAdapterDescriptor() {
742 742 if (sInputMethodDescriptor == null)
743 743 sInputMethodDescriptor = new CInputMethodDescriptor();
744 744
745 745 return sInputMethodDescriptor;
746 746 }
747 747
748 748 /**
749 749 * Returns a map of visual attributes for thelevel description
750 750 * of the given input method highlight, or null if no mapping is found.
751 751 * The style field of the input method highlight is ignored. The map
752 752 * returned is unmodifiable.
753 753 * @param highlight input method highlight
754 754 * @return style attribute map, or null
755 755 * @since 1.3
756 756 */
757 757 @Override
758 758 public Map<TextAttribute, ?> mapInputMethodHighlight(InputMethodHighlight highlight) {
759 759 return CInputMethod.mapInputMethodHighlight(highlight);
760 760 }
761 761
762 762 /**
763 763 * Returns key modifiers used by Swing to set up a focus accelerator key
764 764 * stroke.
765 765 */
766 766 @Override
767 767 public int getFocusAcceleratorKeyMask() {
768 768 return InputEvent.CTRL_MASK | InputEvent.ALT_MASK;
769 769 }
770 770
771 771 /**
772 772 * Tests whether specified key modifiers mask can be used to enter a
773 773 * printable character.
774 774 */
775 775 @Override
776 776 public boolean isPrintableCharacterModifiersMask(int mods) {
777 777 return ((mods & (InputEvent.META_MASK | InputEvent.CTRL_MASK)) == 0);
778 778 }
779 779
780 780 /**
781 781 * Returns whether popup is allowed to be shown above the task bar.
782 782 */
783 783 @Override
784 784 public boolean canPopupOverlapTaskBar() {
785 785 return false;
786 786 }
787 787
788 788 private static Boolean sunAwtDisableCALayers = null;
789 789
790 790 /**
791 791 * Returns the value of "sun.awt.disableCALayers" property. Default
792 792 * value is {@code false}.
793 793 */
794 794 public static synchronized boolean getSunAwtDisableCALayers() {
795 795 if (sunAwtDisableCALayers == null) {
796 796 sunAwtDisableCALayers = AccessController.doPrivileged(
797 797 new GetBooleanAction("sun.awt.disableCALayers"));
798 798 }
799 799 return sunAwtDisableCALayers;
800 800 }
801 801
802 802 /*
803 803 * Returns true if the application (one of its windows) owns keyboard focus.
804 804 */
805 805 native boolean isApplicationActive();
806 806
807 807 /**
808 808 * Returns true if AWT toolkit is embedded, false otherwise.
809 809 *
810 810 * @return true if AWT toolkit is embedded, false otherwise
811 811 */
812 812 public static native boolean isEmbedded();
813 813
814 814 /*
815 815 * Activates application ignoring other apps.
816 816 */
817 817 public native void activateApplicationIgnoringOtherApps();
818 818
819 819 /************************
820 820 * Native methods section
821 821 ************************/
822 822
823 823 static native long createAWTRunLoopMediator();
824 824 /**
825 825 * Method to run a nested run-loop. The nested loop is spinned in the javaRunLoop mode, so selectors sent
826 826 * by [JNFRunLoop performOnMainThreadWaiting] are processed.
827 827 * @param mediator a native pointer to the mediator object created by createAWTRunLoopMediator
828 828 * @param processEvents if true - dispatches event while in the nested loop. Used in DnD.
829 829 * Additional attention is needed when using this feature as we short-circuit normal event
830 830 * processing which could break Appkit.
831 831 * (One known example is when the window is resized with the mouse)
832 832 *
833 833 * if false - all events come after exit form the nested loop
834 834 */
835 835 static void doAWTRunLoop(long mediator, boolean processEvents) {
↓ open down ↓ |
835 lines elided |
↑ open up ↑ |
836 836 doAWTRunLoopImpl(mediator, processEvents, inAWT);
837 837 }
838 838 private static native void doAWTRunLoopImpl(long mediator, boolean processEvents, boolean inAWT);
839 839 static native void stopAWTRunLoop(long mediator);
840 840
841 841 private native boolean nativeSyncQueue(long timeout);
842 842
843 843 /**
844 844 * Just spin a single empty block synchronously.
845 845 */
846 - private static native void flushNativeSelectors();
846 + static native void flushNativeSelectors();
847 847
848 848 @Override
849 849 public Clipboard createPlatformClipboard() {
850 850 return new CClipboard("System");
851 851 }
852 852
853 853 @Override
854 854 public boolean isModalExclusionTypeSupported(Dialog.ModalExclusionType exclusionType) {
855 855 return (exclusionType == null) ||
856 856 (exclusionType == Dialog.ModalExclusionType.NO_EXCLUDE) ||
857 857 (exclusionType == Dialog.ModalExclusionType.APPLICATION_EXCLUDE) ||
858 858 (exclusionType == Dialog.ModalExclusionType.TOOLKIT_EXCLUDE);
859 859 }
860 860
861 861 @Override
862 862 public boolean isModalityTypeSupported(Dialog.ModalityType modalityType) {
863 863 //TODO: FileDialog blocks excluded windows...
864 864 //TODO: Test: 2 file dialogs, separate AppContexts: a) Dialog 1 blocked, shouldn't be. Frame 4 blocked (shouldn't be).
865 865 return (modalityType == null) ||
866 866 (modalityType == Dialog.ModalityType.MODELESS) ||
867 867 (modalityType == Dialog.ModalityType.DOCUMENT_MODAL) ||
868 868 (modalityType == Dialog.ModalityType.APPLICATION_MODAL) ||
869 869 (modalityType == Dialog.ModalityType.TOOLKIT_MODAL);
870 870 }
871 871
872 872 @Override
873 873 public boolean isWindowShapingSupported() {
874 874 return true;
875 875 }
876 876
877 877 @Override
878 878 public boolean isWindowTranslucencySupported() {
879 879 return true;
880 880 }
881 881
882 882 @Override
883 883 public boolean isTranslucencyCapable(GraphicsConfiguration gc) {
884 884 return true;
885 885 }
886 886
887 887 @Override
888 888 public boolean isSwingBackbufferTranslucencySupported() {
889 889 return true;
890 890 }
891 891
892 892 @Override
893 893 public boolean enableInputMethodsForTextComponent() {
894 894 return true;
895 895 }
896 896
897 897 private static URL getScaledImageURL(URL url) {
898 898 try {
899 899 String scaledImagePath = getScaledImageName(url.getPath());
900 900 return scaledImagePath == null ? null : new URL(url.getProtocol(),
901 901 url.getHost(), url.getPort(), scaledImagePath);
902 902 } catch (MalformedURLException e) {
903 903 return null;
904 904 }
905 905 }
906 906
907 907 private static String getScaledImageName(String path) {
908 908 if (!isValidPath(path)) {
909 909 return null;
910 910 }
911 911
912 912 int slash = path.lastIndexOf('/');
913 913 String name = (slash < 0) ? path : path.substring(slash + 1);
914 914
915 915 if (name.contains("@2x")) {
916 916 return null;
917 917 }
918 918
919 919 int dot = name.lastIndexOf('.');
920 920 String name2x = (dot < 0) ? name + "@2x"
921 921 : name.substring(0, dot) + "@2x" + name.substring(dot);
922 922 return (slash < 0) ? name2x : path.substring(0, slash + 1) + name2x;
923 923 }
924 924
925 925 private static boolean isValidPath(String path) {
926 926 return path != null &&
927 927 !path.isEmpty() &&
928 928 !path.endsWith("/") &&
929 929 !path.endsWith(".");
930 930 }
931 931 }
↓ open down ↓ |
75 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX