1 /*
   2  * Copyright (c) 2010, 2017, 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 package com.sun.glass.ui.win;
  26 
  27 import com.sun.glass.ui.*;
  28 import com.sun.glass.ui.CommonDialogs.ExtensionFilter;
  29 import com.sun.glass.ui.CommonDialogs.FileChooserResult;
  30 import com.sun.prism.impl.PrismSettings;
  31 import com.sun.javafx.tk.Toolkit;
  32 
  33 import java.io.File;
  34 import java.nio.ByteBuffer;
  35 import java.nio.IntBuffer;
  36 import java.security.AccessController;
  37 import java.security.PrivilegedAction;
  38 
  39 final class WinApplication extends Application implements InvokeLaterDispatcher.InvokeLaterSubmitter {
  40     static float   overrideUIScale;
  41 
  42     private static boolean getBoolean(String propname, boolean defval, String description) {
  43         String str = System.getProperty(propname);
  44         if (str == null) {
  45             str = System.getenv(propname);
  46         }
  47         if (str == null) {
  48             return defval;
  49         }
  50         Boolean ret = Boolean.parseBoolean(str);
  51         if (PrismSettings.verbose) {
  52             System.out.println((ret ? "" : "not ")+description);
  53         }
  54         return ret;
  55     }
  56 
  57     private static float getFloat(String propname, float defval, String description) {
  58         String str = System.getProperty(propname);
  59         if (str == null) {
  60             str = System.getenv(propname);
  61         }
  62         if (str == null) {
  63             return defval;
  64         }
  65         str = str.trim();
  66         float val;
  67         if (str.endsWith("%")) {
  68             val = Integer.parseInt(str.substring(0, str.length()-1)) / 100.0f;
  69         } else if (str.endsWith("DPI") || str.endsWith("dpi")) {
  70             val = Integer.parseInt(str.substring(0, str.length()-3)) / 96.0f;
  71         } else {
  72             val = Float.parseFloat(str);
  73         }
  74         if (PrismSettings.verbose) {
  75             System.out.println(description+val);
  76         }
  77         return val;
  78     }
  79 
  80     private static native void initIDs(float overrideUIScale);
  81     static {
  82         AccessController.doPrivileged(new PrivilegedAction<Void>() {
  83             public Void run() {
  84                 verbose = Boolean.getBoolean("javafx.verbose");
  85                 if (PrismSettings.allowHiDPIScaling) {
  86                     overrideUIScale = getFloat("glass.win.uiScale", -1.0f, "Forcing UI scaling factor: ");
  87                     // We only parse these if verbose, to inform the user...
  88                     if (PrismSettings.verbose) {
  89                         getFloat("glass.win.renderScale", -1.0f,
  90                                  "(No longer supported) Rendering scaling factor: ");
  91                         getFloat("glass.win.minHiDPI", 1.5f,
  92                                  "(No longer supported) UI scaling threshold: ");
  93                         getBoolean("glass.win.forceIntegerRenderScale", true,
  94                                    "(No longer supported) force integer rendering scale");
  95                     }
  96                 } else {
  97                     overrideUIScale = 1.0f;
  98                 }
  99                 // This loading of msvcp140.dll and vcruntime140.dll (VS2017) is required on Windows platforms
 100                 Toolkit.loadMSWindowsLibraries();
 101                 Application.loadNativeLibrary();
 102                 return null;
 103             }
 104         });
 105         initIDs(overrideUIScale);
 106     }
 107 
 108     private final InvokeLaterDispatcher invokeLaterDispatcher;
 109     WinApplication() {
 110         // Embedded in SWT, with shared event thread
 111         boolean isEventThread = AccessController
 112                 .doPrivileged((PrivilegedAction<Boolean>) () -> Boolean.getBoolean("javafx.embed.isEventThread"));
 113         if (!isEventThread) {
 114             invokeLaterDispatcher = new InvokeLaterDispatcher(this);
 115             invokeLaterDispatcher.start();
 116         } else {
 117             invokeLaterDispatcher = null;
 118         }
 119     }
 120 
 121     private static boolean verbose;
 122 
 123     // returng toolkit window HWND
 124     private native long _init(int awarenessRequested);
 125     private native void _setClassLoader(ClassLoader classLoader);
 126     private native void _runLoop(Runnable launchable);
 127     private native void _terminateLoop();
 128 
 129     private static final int Process_DPI_Unaware            = 0;
 130     private static final int Process_System_DPI_Aware       = 1;
 131     private static final int Process_Per_Monitor_DPI_Aware  = 2;
 132 
 133     private static int getDesiredAwarenesslevel() {
 134         if (!PrismSettings.allowHiDPIScaling) {
 135             return Process_DPI_Unaware;
 136         }
 137         String awareRequested = AccessController
 138             .doPrivileged((PrivilegedAction<String>) () ->
 139                           System.getProperty("javafx.glass.winDPIawareness"));
 140         if (awareRequested != null) {
 141             awareRequested = awareRequested.toLowerCase();
 142             if (awareRequested.equals("aware")) {
 143                 return Process_System_DPI_Aware;
 144             } else if (awareRequested.equals("permonitor")) {
 145                 return Process_Per_Monitor_DPI_Aware;
 146             } else {
 147                 if (!awareRequested.equals("unaware")) {
 148                     System.err.println("unrecognized DPI awareness request, defaulting to unaware: "+awareRequested);
 149                 }
 150                 return Process_DPI_Unaware;
 151             }
 152         }
 153         return Process_Per_Monitor_DPI_Aware;
 154     }
 155 
 156     @Override
 157     protected void runLoop(final Runnable launchable) {
 158         boolean isEventThread = AccessController
 159             .doPrivileged((PrivilegedAction<Boolean>) () -> Boolean.getBoolean("javafx.embed.isEventThread"));
 160         int awareness = getDesiredAwarenesslevel();
 161 
 162         ClassLoader classLoader = WinApplication.class.getClassLoader();
 163         _setClassLoader(classLoader);
 164 
 165         if (isEventThread) {
 166             _init(awareness);
 167             setEventThread(Thread.currentThread());
 168             launchable.run();
 169             return;
 170         }
 171         final Thread toolkitThread =
 172             AccessController.doPrivileged((PrivilegedAction<Thread>) () -> new Thread(() -> {
 173                 _init(awareness);
 174                 _runLoop(launchable);
 175             }, "WindowsNativeRunloopThread"));
 176         setEventThread(toolkitThread);
 177         toolkitThread.start();
 178     }
 179 
 180     @Override protected void finishTerminating() {
 181         final Thread toolkitThread = getEventThread();
 182         if (toolkitThread != null) {
 183             _terminateLoop();
 184             setEventThread(null);
 185         }
 186         super.finishTerminating();
 187     }
 188 
 189     @Override public boolean shouldUpdateWindow() {
 190         return true;
 191     }
 192 
 193     native private Object _enterNestedEventLoopImpl();
 194     native private void _leaveNestedEventLoopImpl(Object retValue);
 195 
 196     @Override protected Object _enterNestedEventLoop() {
 197         if (invokeLaterDispatcher != null) {
 198             invokeLaterDispatcher.notifyEnteringNestedEventLoop();
 199         }
 200         try {
 201             return _enterNestedEventLoopImpl();
 202         } finally {
 203             if (invokeLaterDispatcher != null) {
 204                 invokeLaterDispatcher.notifyLeftNestedEventLoop();
 205             }
 206         }
 207     }
 208 
 209     @Override protected void _leaveNestedEventLoop(Object retValue) {
 210         if (invokeLaterDispatcher != null) {
 211             invokeLaterDispatcher.notifyLeavingNestedEventLoop();
 212         }
 213         _leaveNestedEventLoopImpl(retValue);
 214     }
 215 
 216     // FACTORY METHODS
 217 
 218     @Override public Window createWindow(Window owner, Screen screen, int styleMask) {
 219         return new WinWindow(owner, screen, styleMask);
 220     }
 221 
 222     @Override public Window createWindow(long parent) {
 223         return new WinChildWindow(parent);
 224     }
 225 
 226     @Override public View createView() {
 227         return new WinView();
 228     }
 229 
 230     @Override public Cursor createCursor(int type) {
 231         return new WinCursor(type);
 232     }
 233 
 234     @Override public Cursor createCursor(int x, int y, Pixels pixels) {
 235         return new WinCursor(x, y, pixels);
 236     }
 237 
 238     @Override protected void staticCursor_setVisible(boolean visible) {
 239         WinCursor.setVisible_impl(visible);
 240     }
 241 
 242     @Override protected Size staticCursor_getBestSize(int width, int height) {
 243         return WinCursor.getBestSize_impl(width, height);
 244     }
 245 
 246     @Override public Pixels createPixels(int width, int height, ByteBuffer data) {
 247         return new WinPixels(width, height, data);
 248     }
 249 
 250     @Override public Pixels createPixels(int width, int height, IntBuffer data) {
 251         return new WinPixels(width, height, data);
 252     }
 253 
 254     @Override
 255     public Pixels createPixels(int width, int height, IntBuffer data, float scalex, float scaley) {
 256         return new WinPixels(width, height, data, scalex, scaley);
 257     }
 258 
 259     @Override protected int staticPixels_getNativeFormat() {
 260         return WinPixels.getNativeFormat_impl();
 261     }
 262 
 263     @Override public GlassRobot createRobot() {
 264         return new WinRobot();
 265     }
 266 
 267     @Override protected double staticScreen_getVideoRefreshPeriod() {
 268         return 0.0;     // indicate millisecond resolution
 269     }
 270 
 271     @Override native protected Screen[] staticScreen_getScreens();
 272 
 273     @Override public Timer createTimer(Runnable runnable) {
 274         return new WinTimer(runnable);
 275     }
 276 
 277     @Override protected int staticTimer_getMinPeriod() {
 278         return WinTimer.getMinPeriod_impl();
 279     }
 280 
 281     @Override protected int staticTimer_getMaxPeriod() {
 282         return WinTimer.getMaxPeriod_impl();
 283     }
 284 
 285     @Override public Accessible createAccessible() {
 286         return new WinAccessible();
 287     }
 288 
 289     @Override protected FileChooserResult staticCommonDialogs_showFileChooser(Window owner, String folder, String filename, String title, int type,
 290                                              boolean multipleMode, ExtensionFilter[] extensionFilters, int defaultFilterIndex) {
 291         if (invokeLaterDispatcher != null) {
 292             invokeLaterDispatcher.notifyEnteringNestedEventLoop();
 293         }
 294         return WinCommonDialogs.showFileChooser_impl(owner, folder, filename, title, type, multipleMode, extensionFilters, defaultFilterIndex);
 295     }
 296 
 297     @Override protected File staticCommonDialogs_showFolderChooser(Window owner, String folder, String title) {
 298         if (invokeLaterDispatcher != null) {
 299             invokeLaterDispatcher.notifyEnteringNestedEventLoop();
 300         }
 301         return WinCommonDialogs.showFolderChooser_impl(owner, folder, title);
 302     }
 303 
 304     @Override protected long staticView_getMultiClickTime() {
 305         return WinView.getMultiClickTime_impl();
 306     }
 307 
 308     @Override protected int staticView_getMultiClickMaxX() {
 309         return WinView.getMultiClickMaxX_impl();
 310     }
 311 
 312     @Override protected int staticView_getMultiClickMaxY() {
 313         return WinView.getMultiClickMaxY_impl();
 314     }
 315 
 316     @Override native protected void _invokeAndWait(Runnable runnable);
 317 
 318     native private void _submitForLaterInvocation(Runnable r);
 319     // InvokeLaterDispatcher.InvokeLaterSubmitter
 320     @Override public void submitForLaterInvocation(Runnable r) {
 321         _submitForLaterInvocation(r);
 322     }
 323 
 324     @Override protected void _invokeLater(Runnable runnable) {
 325         if (invokeLaterDispatcher != null) {
 326             invokeLaterDispatcher.invokeLater(runnable);
 327         } else {
 328             submitForLaterInvocation(runnable);
 329         }
 330     }
 331 
 332     private native String _getHighContrastTheme();
 333     @Override public String getHighContrastTheme() {
 334         checkEventThread();
 335         return _getHighContrastTheme();
 336     }
 337 
 338     @Override
 339     protected boolean _supportsInputMethods() {
 340         return true;
 341     }
 342 
 343     @Override
 344     protected boolean _supportsTransparentWindows() {
 345         return true;
 346     }
 347 
 348     @Override native protected boolean _supportsUnifiedWindows();
 349 
 350     public String getDataDirectory() {
 351         checkEventThread();
 352         String baseDirectory = AccessController.doPrivileged((PrivilegedAction<String>) () -> System.getenv("APPDATA"));
 353         if (baseDirectory == null || baseDirectory.length() == 0) {
 354             return super.getDataDirectory();
 355         }
 356         return baseDirectory + File.separator + name + File.separator;
 357     }
 358 
 359     @Override
 360     protected native int _getKeyCodeForChar(char c);
 361 }