1 /*
2 * Copyright (c) 1996, 2014, 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.awt.windows;
27
28 import java.awt.*;
29 import java.awt.im.InputMethodHighlight;
30 import java.awt.im.spi.InputMethodDescriptor;
31 import java.awt.image.*;
32 import java.awt.peer.*;
33 import java.awt.event.KeyEvent;
34 import java.awt.datatransfer.Clipboard;
35 import java.awt.TrayIcon;
36 import java.beans.PropertyChangeListener;
37 import java.security.AccessController;
38 import java.security.PrivilegedAction;
39 import sun.awt.AWTAutoShutdown;
40 import sun.awt.AWTPermissions;
41 import sun.awt.LightweightFrame;
42 import sun.awt.SunToolkit;
43 import sun.awt.util.ThreadGroupUtils;
44 import sun.awt.Win32GraphicsDevice;
45 import sun.awt.Win32GraphicsEnvironment;
46 import sun.awt.datatransfer.DataTransferer;
47 import sun.java2d.d3d.D3DRenderQueue;
48 import sun.java2d.opengl.OGLRenderQueue;
49
50 import sun.print.PrintJob2D;
51
52 import java.awt.dnd.DragSource;
53 import java.awt.dnd.DragGestureListener;
54 import java.awt.dnd.DragGestureEvent;
55 import java.awt.dnd.DragGestureRecognizer;
56 import java.awt.dnd.MouseDragGestureRecognizer;
57 import java.awt.dnd.InvalidDnDOperationException;
58 import java.awt.dnd.peer.DragSourceContextPeer;
59
60 import java.util.Hashtable;
61 import java.util.Locale;
62 import java.util.Map;
63 import java.util.Properties;
64
65 import sun.font.FontManager;
66 import sun.font.FontManagerFactory;
67 import sun.font.SunFontManager;
68 import sun.misc.PerformanceLogger;
69 import sun.util.logging.PlatformLogger;
70
71 public final class WToolkit extends SunToolkit implements Runnable {
72
73 private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.windows.WToolkit");
74
75 static GraphicsConfiguration config;
76
77 // System clipboard.
78 WClipboard clipboard;
79
80 // cache of font peers
81 private Hashtable<String,FontPeer> cacheFontPeer;
82
83 // Windows properties
84 private WDesktopProperties wprops;
85
86 // Dynamic Layout Resize client code setting
87 protected boolean dynamicLayoutSetting = false;
88
89 //Is it allowed to generate events assigned to extra mouse buttons.
90 //Set to true by default.
91 private static boolean areExtraMouseButtonsEnabled = true;
92
93 /**
94 * Initialize JNI field and method IDs
95 */
96 private static native void initIDs();
97 private static boolean loaded = false;
98 public static void loadLibraries() {
99 if (!loaded) {
100 java.security.AccessController.doPrivileged(
101 new java.security.PrivilegedAction<Void>() {
102 @Override
103 public Void run() {
104 System.loadLibrary("awt");
105 return null;
106 }
107 });
108 loaded = true;
109 }
110 }
111
112 private static native String getWindowsVersion();
113
114 static {
115 loadLibraries();
116 initIDs();
117
118 // Print out which version of Windows is running
119 if (log.isLoggable(PlatformLogger.Level.FINE)) {
120 log.fine("Win version: " + getWindowsVersion());
121 }
122
123 AccessController.doPrivileged(
124 new PrivilegedAction <Void> ()
125 {
126 @Override
127 public Void run() {
128 String browserProp = System.getProperty("browser");
129 if (browserProp != null && browserProp.equals("sun.plugin")) {
130 disableCustomPalette();
131 }
132 return null;
133 }
134 });
135 }
136
137 private static native void disableCustomPalette();
138
139 /*
140 * Reset the static GraphicsConfiguration to the default. Called on
141 * startup and when display settings have changed.
142 */
143 public static void resetGC() {
144 if (GraphicsEnvironment.isHeadless()) {
145 config = null;
146 } else {
147 config = (GraphicsEnvironment
148 .getLocalGraphicsEnvironment()
149 .getDefaultScreenDevice()
150 .getDefaultConfiguration());
151 }
152 }
153
154 /*
155 * NOTE: The following embedded*() methods are non-public API intended
156 * for internal use only. The methods are unsupported and could go
157 * away in future releases.
158 *
159 * New hook functions for using the AWT as an embedded service. These
160 * functions replace the global C function AwtInit() which was previously
161 * exported by awt.dll.
162 *
163 * When used as an embedded service, the AWT does NOT have its own
164 * message pump. It instead relies on the parent application to provide
165 * this functionality. embeddedInit() assumes that the thread on which it
166 * is called is the message pumping thread. Violating this assumption
167 * will lead to undefined behavior.
168 *
169 * embeddedInit must be called before the WToolkit() constructor.
170 * embeddedDispose should be called before the applicaton terminates the
171 * Java VM. It is currently unsafe to reinitialize the toolkit again
172 * after it has been disposed. Instead, awt.dll must be reloaded and the
173 * class loader which loaded WToolkit must be finalized before it is
174 * safe to reuse AWT. Dynamic reusability may be added to the toolkit in
175 * the future.
176 */
177
178 /**
179 * Initializes the Toolkit for use in an embedded environment.
180 *
181 * @return true if the the initialization succeeded; false if it failed.
182 * The function will fail if the Toolkit was already initialized.
183 * @since 1.3
184 */
185 public static native boolean embeddedInit();
186
187 /**
188 * Disposes the Toolkit in an embedded environment. This method should
189 * not be called on exit unless the Toolkit was constructed with
190 * embeddedInit.
191 *
192 * @return true if the disposal succeeded; false if it failed. The
193 * function will fail if the calling thread is not the same
194 * thread which called embeddedInit(), or if the Toolkit was
195 * already disposed.
196 * @since 1.3
197 */
198 public static native boolean embeddedDispose();
199
200 /**
201 * To be called after processing the event queue by users of the above
202 * embeddedInit() function. The reason for this additional call is that
203 * there are some operations performed during idle time in the AwtToolkit
204 * event loop which should also be performed during idle time in any
205 * other native event loop. Failure to do so could result in
206 * deadlocks.
207 *
208 * This method was added at the last minute of the jdk1.4 release
209 * to work around a specific customer problem. As with the above
210 * embedded*() class, this method is non-public and should not be
211 * used by external applications.
212 *
213 * See bug #4526587 for more information.
214 */
215 public native void embeddedEventLoopIdleProcessing();
216
217 static class ToolkitDisposer implements sun.java2d.DisposerRecord {
218 @Override
219 public void dispose() {
220 WToolkit.postDispose();
221 }
222 }
223
224 private final Object anchor = new Object();
225
226 private static native void postDispose();
227
228 private static native boolean startToolkitThread(Runnable thread, ThreadGroup rootThreadGroup);
229
230 public WToolkit() {
231 // Startup toolkit threads
232 if (PerformanceLogger.loggingEnabled()) {
233 PerformanceLogger.setTime("WToolkit construction");
234 }
235
236 sun.java2d.Disposer.addRecord(anchor, new ToolkitDisposer());
237
238 /*
239 * Fix for 4701990.
240 * AWTAutoShutdown state must be changed before the toolkit thread
241 * starts to avoid race condition.
242 */
243 AWTAutoShutdown.notifyToolkitThreadBusy();
244
245 // Find a root TG and attach Appkit thread to it
246 ThreadGroup rootTG = AccessController.doPrivileged(
247 (PrivilegedAction<ThreadGroup>) ThreadGroupUtils::getRootThreadGroup);
248 if (!startToolkitThread(this, rootTG)) {
249 Thread toolkitThread = new Thread(rootTG, this, "AWT-Windows");
250 toolkitThread.setDaemon(true);
251 toolkitThread.start();
252 }
253
254 try {
255 synchronized(this) {
256 while(!inited) {
257 wait();
258 }
259 }
260 } catch (InterruptedException x) {
261 // swallow the exception
262 }
263
264 // Enabled "live resizing" by default. It remains controlled
265 // by the native system though.
266 setDynamicLayout(true);
267
268 areExtraMouseButtonsEnabled = Boolean.parseBoolean(System.getProperty("sun.awt.enableExtraMouseButtons", "true"));
269 //set system property if not yet assigned
270 System.setProperty("sun.awt.enableExtraMouseButtons", ""+areExtraMouseButtonsEnabled);
271 setExtraMouseButtonsEnabledNative(areExtraMouseButtonsEnabled);
272 }
273
274 private final void registerShutdownHook() {
275 AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
276 Thread shutdown = new Thread(ThreadGroupUtils.getRootThreadGroup(), this::shutdown);
277 shutdown.setContextClassLoader(null);
278 Runtime.getRuntime().addShutdownHook(shutdown);
279 return null;
280 });
281 }
282
283 @Override
284 public void run() {
285 AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
286 Thread.currentThread().setContextClassLoader(null);
287 return null;
288 });
289 Thread.currentThread().setPriority(Thread.NORM_PRIORITY + 1);
290 boolean startPump = init();
291
292 if (startPump) {
293 registerShutdownHook();
294 }
295
296 synchronized(this) {
297 inited = true;
298 notifyAll();
299 }
300
301 if (startPump) {
302 eventLoop(); // will Dispose Toolkit when shutdown hook executes
303 }
304 }
305
306 /*
307 * eventLoop() begins the native message pump which retrieves and processes
308 * native events.
309 *
310 * When shutdown() is called by the ShutdownHook added in run(), a
311 * WM_QUIT message is posted to the Toolkit thread indicating that
312 * eventLoop() should Dispose the toolkit and exit.
313 */
314 private native boolean init();
315 private boolean inited = false;
316
317 private native void eventLoop();
318 private native void shutdown();
319
320 /*
321 * Instead of blocking the "AWT-Windows" thread uselessly on a semaphore,
322 * use these functions. startSecondaryEventLoop() corresponds to wait()
323 * and quitSecondaryEventLoop() corresponds to notify.
324 *
325 * These functions simulate blocking while allowing the AWT to continue
326 * processing native events, eliminating a potential deadlock situation
327 * with SendMessage.
328 *
329 * WARNING: startSecondaryEventLoop must only be called from the "AWT-
330 * Windows" thread.
331 */
332 static native void startSecondaryEventLoop();
333 static native void quitSecondaryEventLoop();
334
335 /*
336 * Create peer objects.
337 */
338
339 @Override
340 public ButtonPeer createButton(Button target) {
341 ButtonPeer peer = new WButtonPeer(target);
342 targetCreatedPeer(target, peer);
343 return peer;
344 }
345
346 @Override
347 public TextFieldPeer createTextField(TextField target) {
348 TextFieldPeer peer = new WTextFieldPeer(target);
349 targetCreatedPeer(target, peer);
350 return peer;
351 }
352
353 @Override
354 public LabelPeer createLabel(Label target) {
355 LabelPeer peer = new WLabelPeer(target);
356 targetCreatedPeer(target, peer);
357 return peer;
358 }
359
360 @Override
361 public ListPeer createList(List target) {
362 ListPeer peer = new WListPeer(target);
363 targetCreatedPeer(target, peer);
364 return peer;
365 }
366
367 @Override
368 public CheckboxPeer createCheckbox(Checkbox target) {
369 CheckboxPeer peer = new WCheckboxPeer(target);
370 targetCreatedPeer(target, peer);
371 return peer;
372 }
373
374 @Override
375 public ScrollbarPeer createScrollbar(Scrollbar target) {
376 ScrollbarPeer peer = new WScrollbarPeer(target);
377 targetCreatedPeer(target, peer);
378 return peer;
379 }
380
381 @Override
382 public ScrollPanePeer createScrollPane(ScrollPane target) {
383 ScrollPanePeer peer = new WScrollPanePeer(target);
384 targetCreatedPeer(target, peer);
385 return peer;
386 }
387
388 @Override
389 public TextAreaPeer createTextArea(TextArea target) {
390 TextAreaPeer peer = new WTextAreaPeer(target);
391 targetCreatedPeer(target, peer);
392 return peer;
393 }
394
395 @Override
396 public ChoicePeer createChoice(Choice target) {
397 ChoicePeer peer = new WChoicePeer(target);
398 targetCreatedPeer(target, peer);
399 return peer;
400 }
401
402 @Override
403 public FramePeer createFrame(Frame target) {
404 FramePeer peer = new WFramePeer(target);
405 targetCreatedPeer(target, peer);
406 return peer;
407 }
408
409 @Override
410 public FramePeer createLightweightFrame(LightweightFrame target) {
411 FramePeer peer = new WLightweightFramePeer(target);
412 targetCreatedPeer(target, peer);
413 return peer;
414 }
415
416 @Override
417 public CanvasPeer createCanvas(Canvas target) {
418 CanvasPeer peer = new WCanvasPeer(target);
419 targetCreatedPeer(target, peer);
420 return peer;
421 }
422
423 @Override
424 @SuppressWarnings("deprecation")
425 public void disableBackgroundErase(Canvas canvas) {
426 WCanvasPeer peer = (WCanvasPeer)canvas.getPeer();
427 if (peer == null) {
428 throw new IllegalStateException("Canvas must have a valid peer");
429 }
430 peer.disableBackgroundErase();
431 }
432
433 @Override
434 public PanelPeer createPanel(Panel target) {
435 PanelPeer peer = new WPanelPeer(target);
436 targetCreatedPeer(target, peer);
437 return peer;
438 }
439
440 @Override
441 public WindowPeer createWindow(Window target) {
442 WindowPeer peer = new WWindowPeer(target);
443 targetCreatedPeer(target, peer);
444 return peer;
445 }
446
447 @Override
448 public DialogPeer createDialog(Dialog target) {
449 DialogPeer peer = new WDialogPeer(target);
450 targetCreatedPeer(target, peer);
451 return peer;
452 }
453
454 @Override
455 public FileDialogPeer createFileDialog(FileDialog target) {
456 FileDialogPeer peer = new WFileDialogPeer(target);
457 targetCreatedPeer(target, peer);
458 return peer;
459 }
460
461 @Override
462 public MenuBarPeer createMenuBar(MenuBar target) {
463 MenuBarPeer peer = new WMenuBarPeer(target);
464 targetCreatedPeer(target, peer);
465 return peer;
466 }
467
468 @Override
469 public MenuPeer createMenu(Menu target) {
470 MenuPeer peer = new WMenuPeer(target);
471 targetCreatedPeer(target, peer);
472 return peer;
473 }
474
475 @Override
476 public PopupMenuPeer createPopupMenu(PopupMenu target) {
477 PopupMenuPeer peer = new WPopupMenuPeer(target);
478 targetCreatedPeer(target, peer);
479 return peer;
480 }
481
482 @Override
483 public MenuItemPeer createMenuItem(MenuItem target) {
484 MenuItemPeer peer = new WMenuItemPeer(target);
485 targetCreatedPeer(target, peer);
486 return peer;
487 }
488
489 @Override
490 public CheckboxMenuItemPeer createCheckboxMenuItem(CheckboxMenuItem target) {
491 CheckboxMenuItemPeer peer = new WCheckboxMenuItemPeer(target);
492 targetCreatedPeer(target, peer);
493 return peer;
494 }
495
496 @Override
497 public RobotPeer createRobot(Robot target, GraphicsDevice screen) {
498 // (target is unused for now)
499 // Robot's don't need to go in the peer map since
500 // they're not Component's
501 return new WRobotPeer(screen);
502 }
503
504 public WEmbeddedFramePeer createEmbeddedFrame(WEmbeddedFrame target) {
505 WEmbeddedFramePeer peer = new WEmbeddedFramePeer(target);
506 targetCreatedPeer(target, peer);
507 return peer;
508 }
509
510 WPrintDialogPeer createWPrintDialog(WPrintDialog target) {
511 WPrintDialogPeer peer = new WPrintDialogPeer(target);
512 targetCreatedPeer(target, peer);
513 return peer;
514 }
515
516 WPageDialogPeer createWPageDialog(WPageDialog target) {
517 WPageDialogPeer peer = new WPageDialogPeer(target);
518 targetCreatedPeer(target, peer);
519 return peer;
520 }
521
522 @Override
523 public TrayIconPeer createTrayIcon(TrayIcon target) {
524 WTrayIconPeer peer = new WTrayIconPeer(target);
525 targetCreatedPeer(target, peer);
526 return peer;
527 }
528
529 @Override
530 public SystemTrayPeer createSystemTray(SystemTray target) {
531 return new WSystemTrayPeer(target);
532 }
533
534 @Override
535 public boolean isTraySupported() {
536 return true;
537 }
538
539 @Override
540 public DataTransferer getDataTransferer() {
541 return WDataTransferer.getInstanceImpl();
542 }
543
544 @Override
545 public KeyboardFocusManagerPeer getKeyboardFocusManagerPeer()
546 throws HeadlessException
547 {
548 return WKeyboardFocusManagerPeer.getInstance();
549 }
550
551 private native void setDynamicLayoutNative(boolean b);
552
553 @Override
554 public void setDynamicLayout(boolean b) {
555 if (b == dynamicLayoutSetting) {
556 return;
557 }
558
559 dynamicLayoutSetting = b;
560 setDynamicLayoutNative(b);
561 }
562
563 @Override
564 protected boolean isDynamicLayoutSet() {
565 return dynamicLayoutSetting;
566 }
567
568 /*
569 * Called from lazilyLoadDynamicLayoutSupportedProperty because
570 * Windows doesn't always send WM_SETTINGCHANGE when it should.
571 */
572 private native boolean isDynamicLayoutSupportedNative();
573
574 @Override
575 public boolean isDynamicLayoutActive() {
576 return (isDynamicLayoutSet() && isDynamicLayoutSupported());
577 }
578
579 /**
580 * Returns <code>true</code> if this frame state is supported.
581 */
582 @Override
583 public boolean isFrameStateSupported(int state) {
584 switch (state) {
585 case Frame.NORMAL:
586 case Frame.ICONIFIED:
587 case Frame.MAXIMIZED_BOTH:
588 return true;
589 default:
590 return false;
591 }
592 }
593
594 static native ColorModel makeColorModel();
595 static ColorModel screenmodel;
596
597 static ColorModel getStaticColorModel() {
598 if (GraphicsEnvironment.isHeadless()) {
599 throw new IllegalArgumentException();
600 }
601 if (config == null) {
602 resetGC();
603 }
604 return config.getColorModel();
605 }
606
607 @Override
608 public ColorModel getColorModel() {
609 return getStaticColorModel();
610 }
611
612 @Override
613 public Insets getScreenInsets(GraphicsConfiguration gc)
614 {
615 return getScreenInsets(((Win32GraphicsDevice) gc.getDevice()).getScreen());
616 }
617
618 @Override
619 public int getScreenResolution() {
620 Win32GraphicsEnvironment ge = (Win32GraphicsEnvironment)
621 GraphicsEnvironment.getLocalGraphicsEnvironment();
622 return ge.getXResolution();
623 }
624 @Override
625 protected native int getScreenWidth();
626 @Override
627 protected native int getScreenHeight();
628 private native Insets getScreenInsets(int screen);
629
630
631 @Override
632 public FontMetrics getFontMetrics(Font font) {
633 // This is an unsupported hack, but left in for a customer.
634 // Do not remove.
635 FontManager fm = FontManagerFactory.getInstance();
636 if (fm instanceof SunFontManager
637 && ((SunFontManager) fm).usePlatformFontMetrics()) {
638 return WFontMetrics.getFontMetrics(font);
639 }
640 return super.getFontMetrics(font);
641 }
642
643 @Override
644 public FontPeer getFontPeer(String name, int style) {
645 FontPeer retval = null;
646 String lcName = name.toLowerCase();
647 if (null != cacheFontPeer) {
648 retval = cacheFontPeer.get(lcName + style);
649 if (null != retval) {
650 return retval;
651 }
652 }
653 retval = new WFontPeer(name, style);
654 if (retval != null) {
655 if (null == cacheFontPeer) {
656 cacheFontPeer = new Hashtable<>(5, 0.9f);
657 }
658 if (null != cacheFontPeer) {
659 cacheFontPeer.put(lcName + style, retval);
660 }
661 }
662 return retval;
663 }
664
665 private native void nativeSync();
666
667 @Override
668 public void sync() {
669 // flush the GDI/DD buffers
670 nativeSync();
671 // now flush the OGL pipeline (this is a no-op if OGL is not enabled)
672 OGLRenderQueue.sync();
673 // now flush the D3D pipeline (this is a no-op if D3D is not enabled)
674 D3DRenderQueue.sync();
675 }
676
677 @Override
678 public PrintJob getPrintJob(Frame frame, String doctitle,
679 Properties props) {
680 return getPrintJob(frame, doctitle, null, null);
681 }
682
683 @Override
684 public PrintJob getPrintJob(Frame frame, String doctitle,
685 JobAttributes jobAttributes,
686 PageAttributes pageAttributes)
687 {
688 if (frame == null) {
689 throw new NullPointerException("frame must not be null");
690 }
691
692 PrintJob2D printJob = new PrintJob2D(frame, doctitle,
693 jobAttributes, pageAttributes);
694
695 if (printJob.printDialog() == false) {
696 printJob = null;
697 }
698
699 return printJob;
700 }
701
702 @Override
703 public native void beep();
704
705 @Override
706 public boolean getLockingKeyState(int key) {
707 if (! (key == KeyEvent.VK_CAPS_LOCK || key == KeyEvent.VK_NUM_LOCK ||
708 key == KeyEvent.VK_SCROLL_LOCK || key == KeyEvent.VK_KANA_LOCK)) {
709 throw new IllegalArgumentException("invalid key for Toolkit.getLockingKeyState");
710 }
711 return getLockingKeyStateNative(key);
712 }
713
714 private native boolean getLockingKeyStateNative(int key);
715
716 @Override
717 public void setLockingKeyState(int key, boolean on) {
718 if (! (key == KeyEvent.VK_CAPS_LOCK || key == KeyEvent.VK_NUM_LOCK ||
719 key == KeyEvent.VK_SCROLL_LOCK || key == KeyEvent.VK_KANA_LOCK)) {
720 throw new IllegalArgumentException("invalid key for Toolkit.setLockingKeyState");
721 }
722 setLockingKeyStateNative(key, on);
723 }
724
725 private native void setLockingKeyStateNative(int key, boolean on);
726
727 @Override
728 public Clipboard getSystemClipboard() {
729 SecurityManager security = System.getSecurityManager();
730 if (security != null) {
731 security.checkPermission(AWTPermissions.ACCESS_CLIPBOARD_PERMISSION);
732 }
733 synchronized (this) {
734 if (clipboard == null) {
735 clipboard = new WClipboard();
736 }
737 }
738 return clipboard;
739 }
740
741 @Override
742 protected native void loadSystemColors(int[] systemColors);
743
744 public static final Object targetToPeer(Object target) {
745 return SunToolkit.targetToPeer(target);
746 }
747
748 public static final void targetDisposedPeer(Object target, Object peer) {
749 SunToolkit.targetDisposedPeer(target, peer);
750 }
751
752 /**
753 * Returns a new input method adapter descriptor for native input methods.
754 */
755 @Override
756 public InputMethodDescriptor getInputMethodAdapterDescriptor() {
757 return new WInputMethodDescriptor();
758 }
759
760 /**
761 * Returns a style map for the input method highlight.
762 */
763 @Override
764 public Map<java.awt.font.TextAttribute,?> mapInputMethodHighlight(
765 InputMethodHighlight highlight)
766 {
767 return WInputMethod.mapInputMethodHighlight(highlight);
768 }
769
770 /**
771 * Returns whether enableInputMethods should be set to true for peered
772 * TextComponent instances on this platform.
773 */
774 @Override
775 public boolean enableInputMethodsForTextComponent() {
776 return true;
777 }
778
779 /**
780 * Returns the default keyboard locale of the underlying operating system
781 */
782 @Override
783 public Locale getDefaultKeyboardLocale() {
784 Locale locale = WInputMethod.getNativeLocale();
785
786 if (locale == null) {
787 return super.getDefaultKeyboardLocale();
788 } else {
789 return locale;
790 }
791 }
792
793 /**
794 * Returns a new custom cursor.
795 */
796 @Override
797 public Cursor createCustomCursor(Image cursor, Point hotSpot, String name)
798 throws IndexOutOfBoundsException {
799 return new WCustomCursor(cursor, hotSpot, name);
800 }
801
802 /**
803 * Returns the supported cursor size (Win32 only has one).
804 */
805 @Override
806 public Dimension getBestCursorSize(int preferredWidth, int preferredHeight) {
807 return new Dimension(WCustomCursor.getCursorWidth(),
808 WCustomCursor.getCursorHeight());
809 }
810
811 @Override
812 public native int getMaximumCursorColors();
813
814 static void paletteChanged() {
815 ((Win32GraphicsEnvironment)GraphicsEnvironment
816 .getLocalGraphicsEnvironment())
817 .paletteChanged();
818 }
819
820 /*
821 * Called from Toolkit native code when a WM_DISPLAYCHANGE occurs.
822 * Have Win32GraphicsEnvironment execute the display change code on the
823 * Event thread.
824 */
825 static public void displayChanged() {
826 EventQueue.invokeLater(new Runnable() {
827 @Override
828 public void run() {
829 ((Win32GraphicsEnvironment)GraphicsEnvironment
830 .getLocalGraphicsEnvironment())
831 .displayChanged();
832 }
833 });
834 }
835
836 /**
837 * create the peer for a DragSourceContext
838 */
839
840 @Override
841 public DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent dge) throws InvalidDnDOperationException {
842 return WDragSourceContextPeer.createDragSourceContextPeer(dge);
843 }
844
845 @Override
846 public <T extends DragGestureRecognizer> T
847 createDragGestureRecognizer(Class<T> abstractRecognizerClass,
848 DragSource ds, Component c, int srcActions,
849 DragGestureListener dgl)
850 {
851 if (MouseDragGestureRecognizer.class.equals(abstractRecognizerClass))
852 return (T)new WMouseDragGestureRecognizer(ds, c, srcActions, dgl);
853 else
854 return null;
855 }
856
857 /**
858 *
859 */
860
861 private static final String prefix = "DnD.Cursor.";
862 private static final String postfix = ".32x32";
863 private static final String awtPrefix = "awt.";
864 private static final String dndPrefix = "DnD.";
865
866 @Override
867 protected Object lazilyLoadDesktopProperty(String name) {
868 if (name.startsWith(prefix)) {
869 String cursorName = name.substring(prefix.length(), name.length()) + postfix;
870
871 try {
872 return Cursor.getSystemCustomCursor(cursorName);
873 } catch (AWTException awte) {
874 throw new RuntimeException("cannot load system cursor: " + cursorName, awte);
875 }
876 }
877
878 if (name.equals("awt.dynamicLayoutSupported")) {
879 return Boolean.valueOf(isDynamicLayoutSupported());
880 }
881
882 if (WDesktopProperties.isWindowsProperty(name) ||
883 name.startsWith(awtPrefix) || name.startsWith(dndPrefix))
884 {
885 synchronized(this) {
886 lazilyInitWProps();
887 return desktopProperties.get(name);
888 }
889 }
890
891 return super.lazilyLoadDesktopProperty(name);
892 }
893
894 private synchronized void lazilyInitWProps() {
895 if (wprops == null) {
896 wprops = new WDesktopProperties(this);
897 updateProperties();
898 }
899 }
900
901 /*
902 * Called from lazilyLoadDesktopProperty because Windows doesn't
903 * always send WM_SETTINGCHANGE when it should.
904 */
905 private synchronized boolean isDynamicLayoutSupported() {
906 boolean nativeDynamic = isDynamicLayoutSupportedNative();
907 lazilyInitWProps();
908 Boolean prop = (Boolean) desktopProperties.get("awt.dynamicLayoutSupported");
909
910 if (log.isLoggable(PlatformLogger.Level.FINER)) {
911 log.finer("In WTK.isDynamicLayoutSupported()" +
912 " nativeDynamic == " + nativeDynamic +
913 " wprops.dynamic == " + prop);
914 }
915
916 if ((prop == null) || (nativeDynamic != prop.booleanValue())) {
917 // We missed the WM_SETTINGCHANGE, so we pretend
918 // we just got one - fire the propertyChange, etc.
919 windowsSettingChange();
920 return nativeDynamic;
921 }
922
923 return prop.booleanValue();
924 }
925
926 /*
927 * Called from native toolkit code when WM_SETTINGCHANGE message received
928 * Also called from lazilyLoadDynamicLayoutSupportedProperty because
929 * Windows doesn't always send WM_SETTINGCHANGE when it should.
930 */
931 private void windowsSettingChange() {
932 EventQueue.invokeLater(new Runnable() {
933 @Override
934 public void run() {
935 updateProperties();
936 }
937 });
938 }
939
940 private synchronized void updateProperties() {
941 if (null == wprops) {
942 // wprops has not been initialized, so we have nothing to update
943 return;
944 }
945
946 Map<String, Object> props = wprops.getProperties();
947 for (String propName : props.keySet()) {
948 Object val = props.get(propName);
949 if (log.isLoggable(PlatformLogger.Level.FINER)) {
950 log.finer("changed " + propName + " to " + val);
951 }
952 setDesktopProperty(propName, val);
953 }
954 }
955
956 @Override
957 public synchronized void addPropertyChangeListener(String name, PropertyChangeListener pcl) {
958 if (name == null) {
959 // See JavaDoc for the Toolkit.addPropertyChangeListener() method
960 return;
961 }
962 if ( WDesktopProperties.isWindowsProperty(name)
963 || name.startsWith(awtPrefix)
964 || name.startsWith(dndPrefix))
965 {
966 // someone is interested in Windows-specific desktop properties
967 // we should initialize wprops
968 lazilyInitWProps();
969 }
970 super.addPropertyChangeListener(name, pcl);
971 }
972
973 /*
974 * initialize only static props here and do not try to initialize props which depends on wprops,
975 * this should be done in lazilyLoadDesktopProperty() only.
976 */
977 @Override
978 protected synchronized void initializeDesktopProperties() {
979 desktopProperties.put("DnD.Autoscroll.initialDelay",
980 Integer.valueOf(50));
981 desktopProperties.put("DnD.Autoscroll.interval",
982 Integer.valueOf(50));
983 desktopProperties.put("DnD.isDragImageSupported",
984 Boolean.TRUE);
985 desktopProperties.put("Shell.shellFolderManager",
986 "sun.awt.shell.Win32ShellFolderManager2");
987 }
988
989 /*
990 * This returns the value for the desktop property "awt.font.desktophints"
991 * This requires that the Windows properties have already been gathered.
992 */
993 @Override
994 protected synchronized RenderingHints getDesktopAAHints() {
995 if (wprops == null) {
996 return null;
997 } else {
998 return wprops.getDesktopAAHints();
999 }
1000 }
1001
1002 @Override
1003 public boolean isModalityTypeSupported(Dialog.ModalityType modalityType) {
1004 return (modalityType == null) ||
1005 (modalityType == Dialog.ModalityType.MODELESS) ||
1006 (modalityType == Dialog.ModalityType.DOCUMENT_MODAL) ||
1007 (modalityType == Dialog.ModalityType.APPLICATION_MODAL) ||
1008 (modalityType == Dialog.ModalityType.TOOLKIT_MODAL);
1009 }
1010
1011 @Override
1012 public boolean isModalExclusionTypeSupported(Dialog.ModalExclusionType exclusionType) {
1013 return (exclusionType == null) ||
1014 (exclusionType == Dialog.ModalExclusionType.NO_EXCLUDE) ||
1015 (exclusionType == Dialog.ModalExclusionType.APPLICATION_EXCLUDE) ||
1016 (exclusionType == Dialog.ModalExclusionType.TOOLKIT_EXCLUDE);
1017 }
1018
1019 public static WToolkit getWToolkit() {
1020 WToolkit toolkit = (WToolkit)Toolkit.getDefaultToolkit();
1021 return toolkit;
1022 }
1023
1024 /**
1025 * There are two reasons why we don't use buffer per window when
1026 * Vista's DWM (aka Aero) is enabled:
1027 * - since with DWM all windows are already double-buffered, the application
1028 * doesn't get expose events so we don't get to use our true back-buffer,
1029 * wasting memory and performance (this is valid for both d3d and gdi
1030 * pipelines)
1031 * - in some cases with buffer per window enabled it is possible for the
1032 * paint manager to redirect rendering to the screen for some operations
1033 * (like copyArea), and since bpw uses its own BufferStrategy the
1034 * d3d onscreen rendering support is disabled and rendering goes through
1035 * GDI. This doesn't work well with Vista's DWM since one
1036 * can not perform GDI and D3D operations on the same surface
1037 * (see 6630702 for more info)
1038 *
1039 * Note: even though DWM composition state can change during the lifetime
1040 * of the application it is a rare event, and it is more often that it
1041 * is temporarily disabled (because of some app) than it is getting
1042 * permanently enabled so we can live with this approach without the
1043 * complexity of dwm state listeners and such. This can be revisited if
1044 * proved otherwise.
1045 */
1046 @Override
1047 public boolean useBufferPerWindow() {
1048 return !Win32GraphicsEnvironment.isDWMCompositionEnabled();
1049 }
1050
1051 @Override
1052 @SuppressWarnings("deprecation")
1053 public void grab(Window w) {
1054 if (w.getPeer() != null) {
1055 ((WWindowPeer)w.getPeer()).grab();
1056 }
1057 }
1058
1059 @Override
1060 @SuppressWarnings("deprecation")
1061 public void ungrab(Window w) {
1062 if (w.getPeer() != null) {
1063 ((WWindowPeer)w.getPeer()).ungrab();
1064 }
1065 }
1066
1067 @Override
1068 public native boolean syncNativeQueue(final long timeout);
1069 @Override
1070 public boolean isDesktopSupported() {
1071 return true;
1072 }
1073
1074 @Override
1075 public DesktopPeer createDesktopPeer(Desktop target) {
1076 return new WDesktopPeer();
1077 }
1078
1079 private static native void setExtraMouseButtonsEnabledNative(boolean enable);
1080
1081 @Override
1082 public boolean areExtraMouseButtonsEnabled() throws HeadlessException {
1083 return areExtraMouseButtonsEnabled;
1084 }
1085
1086 private native synchronized int getNumberOfButtonsImpl();
1087
1088 @Override
1089 public int getNumberOfButtons(){
1090 if (numberOfButtons == 0) {
1091 numberOfButtons = getNumberOfButtonsImpl();
1092 }
1093 return (numberOfButtons > MAX_BUTTONS_SUPPORTED)? MAX_BUTTONS_SUPPORTED : numberOfButtons;
1094 }
1095
1096 @Override
1097 public boolean isWindowOpacitySupported() {
1098 // supported in Win2K and later
1099 return true;
1100 }
1101
1102 @Override
1103 public boolean isWindowShapingSupported() {
1104 return true;
1105 }
1106
1107 @Override
1108 public boolean isWindowTranslucencySupported() {
1109 // supported in Win2K and later
1110 return true;
1111 }
1112
1113 @Override
1114 public boolean isTranslucencyCapable(GraphicsConfiguration gc) {
1115 //XXX: worth checking if 8-bit? Anyway, it doesn't hurt.
1116 return true;
1117 }
1118
1119 // On MS Windows one must use the peer.updateWindow() to implement
1120 // non-opaque windows.
1121 @Override
1122 public boolean needUpdateWindow() {
1123 return true;
1124 }
1125 }
--- EOF ---