rev 10880 : 8198654: Switch FX's default GTK version to 3 Reviewed-by:
1 /* 2 * Copyright (c) 2010, 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 package com.sun.glass.ui.gtk; 26 27 import com.sun.glass.ui.Application; 28 import com.sun.glass.ui.CommonDialogs.ExtensionFilter; 29 import com.sun.glass.ui.CommonDialogs.FileChooserResult; 30 import com.sun.glass.ui.Cursor; 31 import com.sun.glass.ui.InvokeLaterDispatcher; 32 import com.sun.glass.ui.Pixels; 33 import com.sun.glass.ui.Robot; 34 import com.sun.glass.ui.Screen; 35 import com.sun.glass.ui.Size; 36 import com.sun.glass.ui.Timer; 37 import com.sun.glass.ui.View; 38 import com.sun.glass.ui.Window; 39 import com.sun.javafx.util.Logging; 40 import com.sun.glass.utils.NativeLibLoader; 41 import com.sun.prism.impl.PrismSettings; 42 import sun.util.logging.PlatformLogger; 43 44 import java.io.File; 45 import java.lang.reflect.Method; 46 import java.nio.ByteBuffer; 47 import java.nio.IntBuffer; 48 import java.security.AccessController; 49 import java.security.PrivilegedAction; 50 import java.util.Map; 51 import java.util.concurrent.CountDownLatch; 52 import java.lang.annotation.Native; 53 54 final class GtkApplication extends Application implements 55 InvokeLaterDispatcher.InvokeLaterSubmitter { 56 private static final String SWT_INTERNAL_CLASS = 57 "org.eclipse.swt.internal.gtk.OS"; 58 private static final int forcedGtkVersion; 59 60 61 static { 62 //check for SWT-GTK lib presence 63 Class<?> OS = AccessController. 64 doPrivileged((PrivilegedAction<Class<?>>) () -> { 65 try { 66 return Class.forName(SWT_INTERNAL_CLASS, true, 67 ClassLoader.getSystemClassLoader()); 68 } catch (Exception e) {} 69 try { 70 return Class.forName(SWT_INTERNAL_CLASS, true, 71 Thread.currentThread().getContextClassLoader()); 72 } catch (Exception e) {} 73 return null; 74 }); 75 if (OS != null) { 76 PlatformLogger logger = Logging.getJavaFXLogger(); 77 logger.fine("SWT-GTK library found. Try to obtain GTK version."); 78 Method method = AccessController. 79 doPrivileged((PrivilegedAction<Method>) () -> { 80 try { 81 return OS.getMethod("gtk_major_version"); 82 } catch (Exception e) { 83 return null; 84 } 85 }); 86 int ver = 0; 87 if (method != null) { 88 try { 89 ver = ((Number)method.invoke(OS)).intValue(); 90 } catch (Exception e) { 91 logger.warning("Method gtk_major_version() of " + 92 "the org.eclipse.swt.internal.gtk.OS class " + 93 "returns error. SWT GTK version cannot be detected. " + 94 "GTK3 will be used as default."); 95 ver = 3; 96 } 97 } 98 if (ver < 2 || ver > 3) { 99 logger.warning("SWT-GTK uses unsupported major GTK version " 100 + ver + ". GTK3 will be used as default."); 101 ver = 3; 102 } 103 forcedGtkVersion = ver; 104 } else { 105 forcedGtkVersion = 0; 106 } 107 108 AccessController.doPrivileged((PrivilegedAction<Void>) () -> { 109 Application.loadNativeLibrary(); 110 return null; 111 }); 112 } 113 114 public static int screen = -1; 115 public static long display = 0; 116 public static long visualID = 0; 117 118 static float overrideUIScale; 119 120 private final InvokeLaterDispatcher invokeLaterDispatcher; 121 122 private static float getFloat(String propname, float defval, String description) { 123 String str = System.getProperty(propname); 124 if (str == null) { 125 str = System.getenv(propname); 126 } 127 if (str == null) { 128 return defval; 129 } 130 str = str.trim(); 131 float val; 132 if (str.endsWith("%")) { 133 val = Integer.parseInt(str.substring(0, str.length()-1)) / 100.0f; 134 } else if (str.endsWith("DPI") || str.endsWith("dpi")) { 135 val = Integer.parseInt(str.substring(0, str.length()-3)) / 96.0f; 136 } else { 137 val = Float.parseFloat(str); 138 } 139 if (PrismSettings.verbose) { 140 System.out.println(description+val); 141 } 142 return val; 143 } 144 145 GtkApplication() { 146 147 final int gtkVersion = forcedGtkVersion == 0 ? 148 AccessController.doPrivileged((PrivilegedAction<Integer>) () -> { 149 String v = System.getProperty("jdk.gtk.version","2"); 150 int ret = 0; 151 if ("3".equals(v) || v.startsWith("3.")) { 152 ret = 3; 153 } else if ("2".equals(v) || v.startsWith("2.")) { 154 ret = 2; 155 } 156 return ret; 157 }) : forcedGtkVersion; 158 boolean gtkVersionVerbose = 159 AccessController.doPrivileged((PrivilegedAction<Boolean>) () -> { 160 return Boolean.getBoolean("jdk.gtk.verbose"); 161 }); 162 if (PrismSettings.allowHiDPIScaling) { 163 overrideUIScale = AccessController.doPrivileged((PrivilegedAction<Float>) () -> 164 getFloat("glass.gtk.uiScale", -1.0f, "Forcing UI scaling factor: ")); 165 } else { 166 overrideUIScale = -1.0f; 167 } 168 169 int libraryToLoad = _queryLibrary(gtkVersion, gtkVersionVerbose); 170 171 AccessController.doPrivileged((PrivilegedAction<Void>) () -> { 172 if (libraryToLoad == QUERY_NO_DISPLAY) { 173 throw new UnsupportedOperationException("Unable to open DISPLAY"); 174 } else if (libraryToLoad == QUERY_USE_CURRENT) { 175 if (gtkVersionVerbose) { 176 System.out.println("Glass GTK library to load is already loaded"); 177 } 178 } else if (libraryToLoad == QUERY_LOAD_GTK2) { 179 if (gtkVersionVerbose) { 180 System.out.println("Glass GTK library to load is glassgtk2"); 181 } 182 NativeLibLoader.loadLibrary("glassgtk2"); 183 } else if (libraryToLoad == QUERY_LOAD_GTK3) { 184 if (gtkVersionVerbose) { 185 System.out.println("Glass GTK library to load is glassgtk3"); 186 } 187 NativeLibLoader.loadLibrary("glassgtk3"); 188 } else { 189 throw new UnsupportedOperationException("Internal Error"); 190 } 191 return null; 192 }); 193 194 int version = _initGTK(gtkVersion, gtkVersionVerbose, overrideUIScale); 195 196 if (version == -1) { 197 throw new RuntimeException("Error loading GTK libraries"); 198 } 199 200 // Embedded in SWT, with shared event thread 201 boolean isEventThread = AccessController 202 .doPrivileged((PrivilegedAction<Boolean>) () -> Boolean.getBoolean("javafx.embed.isEventThread")); 203 if (!isEventThread) { 204 invokeLaterDispatcher = new InvokeLaterDispatcher(this); 205 invokeLaterDispatcher.start(); 206 } else { 207 invokeLaterDispatcher = null; 208 } 209 } 210 211 @Native private static final int QUERY_ERROR = -2; 212 @Native private static final int QUERY_NO_DISPLAY = -1; 213 @Native private static final int QUERY_USE_CURRENT = 1; 214 @Native private static final int QUERY_LOAD_GTK2 = 2; 215 @Native private static final int QUERY_LOAD_GTK3 = 3; 216 /* 217 * check the system and return an indication of which library to load 218 * return values are the QUERY_ constants 219 */ 220 private static native int _queryLibrary(int version, boolean verbose); 221 222 private static native int _initGTK(int version, boolean verbose, float overrideUIScale); 223 224 private void initDisplay() { 225 Map ds = getDeviceDetails(); 226 if (ds != null) { 227 Object value; 228 value = ds.get("XDisplay"); 229 if (value != null) { 230 display = (Long)value; 231 } 232 value = ds.get("XVisualID"); 233 if (value != null) { 234 visualID = (Long)value; 235 } 236 value = ds.get("XScreenID"); 237 if (value != null) { 238 screen = (Integer)value; 239 } 240 } 241 } 242 243 private void init() { 244 initDisplay(); 245 long eventProc = 0; 246 Map map = getDeviceDetails(); 247 if (map != null) { 248 Long result = (Long) map.get("javafx.embed.eventProc"); 249 eventProc = result == null ? 0 : result; 250 } 251 252 final boolean disableGrab = AccessController.doPrivileged((PrivilegedAction<Boolean>) () -> Boolean.getBoolean("sun.awt.disablegrab") || 253 Boolean.getBoolean("glass.disableGrab")); 254 255 _init(eventProc, disableGrab); 256 } 257 258 @Override 259 protected void runLoop(final Runnable launchable) { 260 // Embedded in SWT, with shared event thread 261 final boolean isEventThread = AccessController 262 .doPrivileged((PrivilegedAction<Boolean>) () -> Boolean.getBoolean("javafx.embed.isEventThread")); 263 264 if (isEventThread) { 265 init(); 266 setEventThread(Thread.currentThread()); 267 launchable.run(); 268 return; 269 } 270 271 final boolean noErrorTrap = AccessController 272 .doPrivileged((PrivilegedAction<Boolean>) () -> Boolean.getBoolean("glass.noErrorTrap")); 273 274 final Thread toolkitThread = 275 AccessController.doPrivileged((PrivilegedAction<Thread>) () -> new Thread(() -> { 276 init(); 277 _runLoop(launchable, noErrorTrap); 278 }, "GtkNativeMainLoopThread")); 279 setEventThread(toolkitThread); 280 toolkitThread.start(); 281 } 282 283 @Override 284 protected void finishTerminating() { 285 final Thread toolkitThread = getEventThread(); 286 if (toolkitThread != null) { 287 _terminateLoop(); 288 setEventThread(null); 289 } 290 super.finishTerminating(); 291 } 292 293 @Override public boolean shouldUpdateWindow() { 294 return true; 295 } 296 297 private native void _terminateLoop(); 298 299 private native void _init(long eventProc, boolean disableGrab); 300 301 private native void _runLoop(Runnable launchable, boolean noErrorTrap); 302 303 @Override 304 protected void _invokeAndWait(final Runnable runnable) { 305 if (invokeLaterDispatcher != null) { 306 invokeLaterDispatcher.invokeAndWait(runnable); 307 } else { 308 final CountDownLatch latch = new CountDownLatch(1); 309 submitForLaterInvocation(() -> { 310 if (runnable != null) runnable.run(); 311 latch.countDown(); 312 }); 313 try { 314 latch.await(); 315 } catch (InterruptedException e) { 316 //FAIL SILENTLY 317 } 318 } 319 } 320 321 private native void _submitForLaterInvocation(Runnable r); 322 // InvokeLaterDispatcher.InvokeLaterSubmitter 323 @Override public void submitForLaterInvocation(Runnable r) { 324 _submitForLaterInvocation(r); 325 } 326 327 @Override protected void _invokeLater(Runnable runnable) { 328 if (invokeLaterDispatcher != null) { 329 invokeLaterDispatcher.invokeLater(runnable); 330 } else { 331 submitForLaterInvocation(runnable); 332 } 333 } 334 335 private Object eventLoopExitEnterPassValue; 336 337 private native void enterNestedEventLoopImpl(); 338 339 private native void leaveNestedEventLoopImpl(); 340 341 @Override 342 protected Object _enterNestedEventLoop() { 343 if (invokeLaterDispatcher != null) { 344 invokeLaterDispatcher.notifyEnteringNestedEventLoop(); 345 } 346 try { 347 enterNestedEventLoopImpl(); 348 final Object retValue = eventLoopExitEnterPassValue; 349 eventLoopExitEnterPassValue = null; 350 return retValue; 351 } finally { 352 if (invokeLaterDispatcher != null) { 353 invokeLaterDispatcher.notifyLeftNestedEventLoop(); 354 } 355 } 356 } 357 358 @Override 359 protected void _leaveNestedEventLoop(Object retValue) { 360 if (invokeLaterDispatcher != null) { 361 invokeLaterDispatcher.notifyLeavingNestedEventLoop(); 362 } 363 eventLoopExitEnterPassValue = retValue; 364 leaveNestedEventLoopImpl(); 365 } 366 367 @Override 368 public Window createWindow(Window owner, Screen screen, int styleMask) { 369 return new GtkWindow(owner, screen, styleMask); 370 } 371 372 @Override 373 public Window createWindow(long parent) { 374 return new GtkChildWindow(parent); 375 } 376 377 @Override 378 public View createView() { 379 return new GtkView(); 380 } 381 382 @Override 383 public Cursor createCursor(int type) { 384 return new GtkCursor(type); 385 } 386 387 @Override 388 public Cursor createCursor(int x, int y, Pixels pixels) { 389 return new GtkCursor(x, y, pixels); 390 } 391 392 @Override 393 protected void staticCursor_setVisible(boolean visible) { 394 } 395 396 @Override 397 protected Size staticCursor_getBestSize(int width, int height) { 398 return GtkCursor._getBestSize(width, height); 399 } 400 401 @Override 402 public Pixels createPixels(int width, int height, ByteBuffer data) { 403 return new GtkPixels(width, height, data); 404 } 405 406 @Override 407 public Pixels createPixels(int width, int height, IntBuffer data) { 408 return new GtkPixels(width, height, data); 409 } 410 411 @Override 412 public Pixels createPixels(int width, int height, IntBuffer data, float scalex, float scaley) { 413 return new GtkPixels(width, height, data, scalex, scaley); 414 } 415 416 @Override 417 protected int staticPixels_getNativeFormat() { 418 return Pixels.Format.BYTE_BGRA_PRE; // TODO 419 } 420 421 @Override 422 public Robot createRobot() { 423 return new GtkRobot(); 424 } 425 426 @Override 427 public Timer createTimer(Runnable runnable) { 428 return new GtkTimer(runnable); 429 } 430 431 @Override 432 protected native int staticTimer_getMinPeriod(); 433 434 @Override 435 protected native int staticTimer_getMaxPeriod(); 436 437 @Override protected double staticScreen_getVideoRefreshPeriod() { 438 return 0.0; // indicate millisecond resolution 439 } 440 441 @Override native protected Screen[] staticScreen_getScreens(); 442 443 @Override 444 protected FileChooserResult staticCommonDialogs_showFileChooser( 445 Window owner, String folder, String filename, String title, 446 int type, boolean multipleMode, ExtensionFilter[] extensionFilters, int defaultFilterIndex) { 447 448 return GtkCommonDialogs.showFileChooser(owner, folder, filename, title, 449 type, multipleMode, extensionFilters, defaultFilterIndex); 450 } 451 452 @Override 453 protected File staticCommonDialogs_showFolderChooser(Window owner, String folder, String title) { 454 return GtkCommonDialogs.showFolderChooser(owner, folder, title); 455 } 456 457 @Override 458 protected native long staticView_getMultiClickTime(); 459 460 @Override 461 protected native int staticView_getMultiClickMaxX(); 462 463 @Override 464 protected native int staticView_getMultiClickMaxY(); 465 466 @Override 467 protected boolean _supportsInputMethods() { 468 return true; 469 } 470 471 @Override 472 protected native boolean _supportsTransparentWindows(); 473 474 @Override protected boolean _supportsUnifiedWindows() { 475 return false; 476 } 477 478 @Override 479 protected native int _getKeyCodeForChar(char c); 480 481 } --- EOF ---