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