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