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