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 }