JOGL v2.6.0-rc-20250712
JOGL, High-Performance Graphics Binding for Java™ (public API).
SWTAccessor.java
Go to the documentation of this file.
1/**
2 * Copyright 2010 JogAmp Community. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without modification, are
5 * permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice, this list of
8 * conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11 * of conditions and the following disclaimer in the documentation and/or other materials
12 * provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
15 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
21 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
22 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 *
24 * The views and conclusions contained in the software and documentation are those of the
25 * authors and should not be interpreted as representing official policies, either expressed
26 * or implied, of JogAmp Community.
27 */
28package com.jogamp.nativewindow.swt;
29
30import com.jogamp.common.os.Platform;
31
32import java.io.PrintStream;
33import java.lang.reflect.Field;
34import java.lang.reflect.Method;
35import java.security.PrivilegedAction;
36
37import org.eclipse.swt.SWT;
38import org.eclipse.swt.graphics.GCData;
39import org.eclipse.swt.graphics.Point;
40import org.eclipse.swt.graphics.Rectangle;
41import org.eclipse.swt.internal.DPIUtil;
42import org.eclipse.swt.widgets.Control;
43import org.eclipse.swt.widgets.Display;
44import org.eclipse.swt.widgets.Scrollable;
45
46import com.jogamp.nativewindow.AbstractGraphicsScreen;
47import com.jogamp.nativewindow.NativeWindowException;
48import com.jogamp.nativewindow.AbstractGraphicsDevice;
49import com.jogamp.nativewindow.NativeWindowFactory;
50import com.jogamp.nativewindow.VisualIDHolder;
51import com.jogamp.common.util.ReflectionUtil;
52import com.jogamp.common.util.SecurityUtil;
53import com.jogamp.common.util.VersionNumber;
54import com.jogamp.nativewindow.macosx.MacOSXGraphicsDevice;
55import com.jogamp.nativewindow.windows.WindowsGraphicsDevice;
56import com.jogamp.nativewindow.x11.X11GraphicsDevice;
57
58import jogamp.nativewindow.macosx.OSXUtil;
59import jogamp.nativewindow.x11.X11Lib;
60import jogamp.nativewindow.Debug;
61
62public class SWTAccessor {
63 private static final boolean DEBUG = Debug.debug("SWT");
64
65 private static final Method swt_scrollable_clientAreaInPixels;
66 private static final Method swt_control_locationInPixels;
67 private static final Method swt_control_sizeInPixels;
68 private static final Method swt_dpiutil_getScalingFactor;
69
70 private static final Field swt_control_handle;
71 private static final boolean swt_uses_long_handles;
72
73 private static Object swt_osx_init = new Object();
74 private static Field swt_osx_control_view = null;
75 private static Field swt_osx_view_id = null;
76
77 private static final String nwt;
78 public static final boolean isOSX;
79 public static final boolean isWindows;
80 public static final boolean isX11;
81 public static final boolean isX11GTK;
82 public static final boolean useCairoAutoScale; // See SWT git commit 111b874343d65aaee4f13d74eda554bde1a740a7 (always true for GTK since version 4.36.0)
83
84 // X11/GTK, Windows/GDI, ..
85 private static final String str_handle = "handle";
86
87 // OSX/Cocoa
88 private static final String str_osx_view = "view"; // OSX
89 private static final String str_osx_id = "id"; // OSX
90 // static final String str_NSView = "org.eclipse.swt.internal.cocoa.NSView";
91
92 private static final Method swt_control_internal_new_GC;
93 private static final Method swt_control_internal_dispose_GC;
94 private static final String str_internal_new_GC = "internal_new_GC";
95 private static final String str_internal_dispose_GC = "internal_dispose_GC";
96
97 private static final String str_OS_gtk_class = "org.eclipse.swt.internal.gtk.OS"; // used by earlier versions of SWT
98 private static final String str_GTK_gtk_class = "org.eclipse.swt.internal.gtk.GTK"; // used by later versions of SWT
99 private static final String str_GTK3_gtk_class = "org.eclipse.swt.internal.gtk3.GTK3"; // used by later versions of SWT (4.21+)
100 private static final String str_GDK_gtk_class = "org.eclipse.swt.internal.gtk.GDK"; // used by later versions of SWT
101 public static final Class<?> OS_gtk_class;
102 private static final String str_OS_gtk_version = "GTK_VERSION";
103 public static final VersionNumber OS_gtk_version;
104
105 private static final Method OS_gtk_widget_realize;
106 private static final Method OS_gtk_widget_unrealize; // optional (removed in SWT 4.3)
107 private static final Method OS_GTK_WIDGET_WINDOW;
108 private static final Method OS_gtk_widget_get_window;
109 private static final Method OS_gdk_x11_drawable_get_xdisplay;
110 private static final Method OS_gdk_x11_display_get_xdisplay;
111 private static final Method OS_gdk_window_get_display;
112 private static final Method OS_gdk_x11_drawable_get_xid;
113 private static final Method OS_gdk_x11_window_get_xid;
114
115 private static final String str_gtk_widget_realize = "gtk_widget_realize";
116 private static final String str_gtk_widget_unrealize = "gtk_widget_unrealize";
117 private static final String str_GTK_WIDGET_WINDOW = "GTK_WIDGET_WINDOW";
118 private static final String str_gtk_widget_get_window = "gtk_widget_get_window";
119 private static final String str_gdk_x11_drawable_get_xdisplay = "gdk_x11_drawable_get_xdisplay";
120 private static final String str_gdk_x11_display_get_xdisplay = "gdk_x11_display_get_xdisplay";
121 private static final String str_gdk_window_get_display = "gdk_window_get_display";
122 private static final String str_gdk_x11_drawable_get_xid = "gdk_x11_drawable_get_xid";
123 private static final String str_gdk_x11_window_get_xid = "gdk_x11_window_get_xid";
124
125 private static final VersionNumber GTK_VERSION_2_14_0 = new VersionNumber(2, 14, 0);
126 private static final VersionNumber GTK_VERSION_2_24_0 = new VersionNumber(2, 24, 0);
127 // private static final VersionNumber GTK_VERSION_2_90_0 = new VersionNumber(2, 90, 0);
128 private static final VersionNumber GTK_VERSION_3_0_0 = new VersionNumber(3, 0, 0);
129 // private static final VersionNumber GTK_VERSION_4_0_0 = new VersionNumber(4, 0, 0);
130
131 private static VersionNumber GTK_VERSION(final int version) {
132 // return (major << 16) + (minor << 8) + micro;
133 final int micro = ( version ) & 0xff;
134 final int minor = ( version >> 8 ) & 0xff;
135 final int major = ( version >> 16 ) & 0xff;
136 return new VersionNumber(major, minor, micro);
137 }
138
139 static {
140 final int SWT_VERSION_4_20 = 4944;
141 // final int SWT_VERSION_4_26 = 4956;
142 // major * 1000 + minor;
143
144 SecurityUtil.doPrivileged(new PrivilegedAction<Object>() {
145 @Override
146 public Object run() {
147 NativeWindowFactory.initSingleton(); // last resort ..
148 return null;
149 } } );
150
151 nwt = NativeWindowFactory.getNativeWindowType(false);
152 isOSX = NativeWindowFactory.TYPE_MACOSX == nwt;
153 isWindows = NativeWindowFactory.TYPE_WINDOWS == nwt;
154 isX11 = NativeWindowFactory.TYPE_X11 == nwt;
155 final int swt_version = SWT.getVersion();
156
157 if( DEBUG ) {
158 System.err.println("SWT: Platform: "+SWT.getPlatform()+", Version: "+swt_version);
159 }
160
161 Method m = null;
162 try {
163 m = Control.class.getDeclaredMethod("getLocationInPixels");
164 m.setAccessible(true);
165 } catch (final Exception ex) {
166 m = null;
167 if( DEBUG ) {
168 System.err.println("SWT: getLocationInPixels not implemented: "+ex.getMessage());
169 }
170 }
171 swt_control_locationInPixels = m;
172
173 m = null;
174 try {
175 m = Control.class.getDeclaredMethod("getSizeInPixels");
176 m.setAccessible(true);
177 } catch (final Exception ex) {
178 m = null;
179 if( DEBUG ) {
180 System.err.println("SWT: getSizeInPixels not implemented: "+ex.getMessage());
181 }
182 }
183 swt_control_sizeInPixels = m;
184
185 m = null;
186 try {
187 m = Scrollable.class.getDeclaredMethod("getClientAreaInPixels");
188 m.setAccessible(true);
189 } catch (final Exception ex) {
190 m = null;
191 if( DEBUG ) {
192 System.err.println("SWT: getClientAreaInPixels not implemented: "+ex.getMessage());
193 }
194 }
195 swt_scrollable_clientAreaInPixels = m;
196
197 m = null;
198 try {
199 m = DPIUtil.class.getDeclaredMethod("getScalingFactor");
200 m.setAccessible(true);
201 } catch (final Exception ex) {
202 m = null;
203 if( DEBUG ) {
204 System.err.println("SWT: getScalingFactor not implemented: "+ex.getMessage());
205 }
206 }
207 swt_dpiutil_getScalingFactor = m;
208
209 Field f = null;
210 if( !isOSX ) {
211 try {
212 f = Control.class.getField(str_handle);
213 } catch (final Exception ex) {
214 throw new NativeWindowException(ex);
215 }
216 }
217 swt_control_handle = f; // maybe null !
218
219 boolean ulh;
220 if (null != swt_control_handle) {
221 ulh = swt_control_handle.getGenericType().toString().equals(long.class.toString());
222 } else {
223 ulh = Platform.is64Bit();
224 }
225 swt_uses_long_handles = ulh;
226 // System.err.println("SWT long handles: " + swt_uses_long_handles);
227 // System.err.println("Platform 64bit: "+Platform.is64Bit());
228
229 m=null;
230 try {
231 m = ReflectionUtil.getMethod(Control.class, str_internal_new_GC, new Class[] { GCData.class });
232 } catch (final Exception ex) {
233 throw new NativeWindowException(ex);
234 }
235 swt_control_internal_new_GC = m;
236
237 m=null;
238 try {
239 if(swt_uses_long_handles) {
240 m = Control.class.getDeclaredMethod(str_internal_dispose_GC, new Class[] { long.class, GCData.class });
241 } else {
242 m = Control.class.getDeclaredMethod(str_internal_dispose_GC, new Class[] { int.class, GCData.class });
243 }
244 } catch (final NoSuchMethodException ex) {
245 throw new NativeWindowException(ex);
246 }
247 swt_control_internal_dispose_GC = m;
248
249 Class<?> cGTK=null;
250 VersionNumber _gtk_version = new VersionNumber(0, 0, 0);
251 Method m1=null, m2=null, m3=null, m4=null, m5=null, m6=null, m7=null, m8=null, m9=null;
252 final Class<?> handleType = swt_uses_long_handles ? long.class : int.class ;
253 if( isX11 ) {
254 // mandatory
255 try {
256 final ClassLoader cl = SWTAccessor.class.getClassLoader();
257 cGTK = ReflectionUtil.getClass(str_OS_gtk_class, false, cl);
258 Field field_OS_gtk_version;
259 Class<?> cGDK=cGTK; // used for newer versions of SWT that have a org.eclipse.swt.internal.gtk.GDK object
260 try {
261 field_OS_gtk_version = cGTK.getField(str_OS_gtk_version);
262 } catch (final NoSuchFieldException ex) {
263 // if the GTK_VERSION field didn't exist in org.eclipse.swt.internal.gtk.OS, then look for
264 // it in org.eclipse.swt.internal.gtk.GTK, where it was moved in later versions of SWT
265 cGTK = ReflectionUtil.getClass(str_GTK_gtk_class, false, cl);
266 field_OS_gtk_version = cGTK.getField(str_OS_gtk_version);
267 cGDK = ReflectionUtil.getClass(str_GDK_gtk_class, false, cl);
268 }
269 _gtk_version = GTK_VERSION(field_OS_gtk_version.getInt(null));
270 if( DEBUG ) {
271 System.err.println("SWT: GTK Version: "+_gtk_version.toString());
272 }
273 m1 = cGTK.getDeclaredMethod(str_gtk_widget_realize, handleType);
274 if (_gtk_version.compareTo(GTK_VERSION_2_14_0) >= 0) {
275 if (swt_version < SWT_VERSION_4_20) {
276 m4 = cGTK.getDeclaredMethod(str_gtk_widget_get_window, handleType);
277 } else {
278 final Class<?> cGTK3 = ReflectionUtil.getClass(str_GTK3_gtk_class, false, cl);
279 m4 = cGTK3.getDeclaredMethod(str_gtk_widget_get_window, handleType);
280 }
281 } else {
282 m3 = cGTK.getDeclaredMethod(str_GTK_WIDGET_WINDOW, handleType);
283 }
284 if (_gtk_version.compareTo(GTK_VERSION_2_24_0) >= 0) {
285 m6 = cGDK.getDeclaredMethod(str_gdk_x11_display_get_xdisplay, handleType);
286 m7 = cGDK.getDeclaredMethod(str_gdk_window_get_display, handleType);
287 } else {
288 m5 = cGTK.getDeclaredMethod(str_gdk_x11_drawable_get_xdisplay, handleType);
289 }
290 if (_gtk_version.compareTo(GTK_VERSION_3_0_0) >= 0) {
291 m9 = cGDK.getDeclaredMethod(str_gdk_x11_window_get_xid, handleType);
292 } else {
293 m8 = cGTK.getDeclaredMethod(str_gdk_x11_drawable_get_xid, handleType);
294 }
295 } catch (final Exception ex) { throw new NativeWindowException(ex); }
296 // optional
297 try {
298 m2 = cGTK.getDeclaredMethod(str_gtk_widget_unrealize, handleType);
299 } catch (final Exception ex) { }
300 }
301 OS_gtk_class = cGTK;
302 OS_gtk_version = _gtk_version;
303 OS_gtk_widget_realize = m1;
304 OS_gtk_widget_unrealize = m2;
305 OS_GTK_WIDGET_WINDOW = m3;
306 OS_gtk_widget_get_window = m4;
307 OS_gdk_x11_drawable_get_xdisplay = m5;
308 OS_gdk_x11_display_get_xdisplay = m6;
309 OS_gdk_window_get_display = m7;
310 OS_gdk_x11_drawable_get_xid = m8;
311 OS_gdk_x11_window_get_xid = m9;
312
313 isX11GTK = isX11 && null != OS_gtk_class;
315 if( DEBUG ) {
316 printInfo(System.err, null);
317 }
318 }
319
320 /**
321 * Call this method, if this class shall be initialized before any other of its methods are called
322 * within the regular workflow.
323 *
324 * This could be desired to ensure initialization before AWT.
325 *
326 * This method does nothing, but initializes this class's static SWT accessors if using this class for the first time.
327 */
328 public static void initSingleton() {}
329
330 private static Number getIntOrLong(final long arg) {
331 if(swt_uses_long_handles) {
332 return Long.valueOf(arg);
333 }
334 return Integer.valueOf((int) arg);
335 }
336
337 private static void callStaticMethodL2V(final Method m, final long arg) {
338 ReflectionUtil.callMethod(null, m, new Object[] { getIntOrLong(arg) });
339 }
340
341 @SuppressWarnings("unused")
342 private static void callStaticMethodLL2V(final Method m, final long arg0, final long arg1) {
343 ReflectionUtil.callMethod(null, m, new Object[] { getIntOrLong(arg0), getIntOrLong(arg1) });
344 }
345
346 @SuppressWarnings("unused")
347 private static void callStaticMethodLLZ2V(final Method m, final long arg0, final long arg1, final boolean arg3) {
348 ReflectionUtil.callMethod(null, m, new Object[] { getIntOrLong(arg0), getIntOrLong(arg1), Boolean.valueOf(arg3) });
349 }
350
351 private static long callStaticMethodL2L(final Method m, final long arg) {
352 final Object o = ReflectionUtil.callMethod(null, m, new Object[] { getIntOrLong(arg) });
353 if(o instanceof Number) {
354 return ((Number)o).longValue();
355 } else {
356 throw new InternalError("SWT method "+m.getName()+" didn't return int or long but "+o.getClass());
357 }
358 }
359
360 //
361 // Public properties
362 //
363
364 public static boolean isUsingLongHandles() {
365 return swt_uses_long_handles;
366 }
367
368 public static boolean useX11GTK() { return isX11GTK; }
369 public static VersionNumber GTK_VERSION() { return OS_gtk_version; }
370
371 //
372 // Common GTK
373 //
374
375 public static long gdk_widget_get_window(final long handle) {
376 final long window;
377 if (OS_gtk_version.compareTo(GTK_VERSION_2_14_0) >= 0) {
378 window = callStaticMethodL2L(OS_gtk_widget_get_window, handle);
379 } else {
380 window = callStaticMethodL2L(OS_GTK_WIDGET_WINDOW, handle);
381 }
382 if(0 == window) {
383 throw new NativeWindowException("Null gtk-window-handle of SWT handle 0x"+Long.toHexString(handle));
384 }
385 return window;
386 }
387
388 public static long gdk_window_get_xdisplay(final long window) {
389 final long xdisplay;
390 if (OS_gtk_version.compareTo(GTK_VERSION_2_24_0) >= 0) {
391 final long display = callStaticMethodL2L(OS_gdk_window_get_display, window);
392 if(0 == display) {
393 throw new NativeWindowException("Null display-handle of gtk-window-handle 0x"+Long.toHexString(window));
394 }
395 xdisplay = callStaticMethodL2L(OS_gdk_x11_display_get_xdisplay, display);
396 } else {
397 xdisplay = callStaticMethodL2L(OS_gdk_x11_drawable_get_xdisplay, window);
398 }
399 if(0 == xdisplay) {
400 throw new NativeWindowException("Null x11-display-handle of gtk-window-handle 0x"+Long.toHexString(window));
401 }
402 return xdisplay;
403 }
404
405 public static long gdk_window_get_xwindow(final long window) {
406 final long xWindow;
407 if (OS_gtk_version.compareTo(GTK_VERSION_3_0_0) >= 0) {
408 xWindow = callStaticMethodL2L(OS_gdk_x11_window_get_xid, window);
409 } else {
410 xWindow = callStaticMethodL2L(OS_gdk_x11_drawable_get_xid, window);
411 }
412 if(0 == xWindow) {
413 throw new NativeWindowException("Null x11-window-handle of gtk-window-handle 0x"+Long.toHexString(window));
414 }
415 return xWindow;
416 }
417
418 //
419 // Common any toolkit
420 //
421 public static void printInfo(final PrintStream out, final Display d) {
422 out.println("SWT: Platform: "+SWT.getPlatform()+", Version "+SWT.getVersion());
423 out.println("SWT: isX11 "+isX11+", isX11GTK "+isX11GTK+" (GTK Version: "+OS_gtk_version+")");
424 out.println("SWT: isOSX "+isOSX+", isWindows "+isWindows);
425 out.println("SWT: DeviceZoom: "+DPIUtil.getDeviceZoom()+", deviceZoomScalingFactor "+getDeviceZoomScalingFactor());
426 final Point dpi = null != d ? d.getDPI() : null;
427 out.println("SWT: Display.DPI "+dpi+"; DPIUtil: autoScalingFactor "+
428 getAutoScalingFactor()+" (use-swt "+(null != swt_dpiutil_getScalingFactor)+
429 "), useCairoAutoScale "+useCairoAutoScale);
430 }
431
432 //
433 // SWT DPIUtil Compatible auto-scale functionality
434 //
435 /**
436 * Returns SWT compatible auto scale-factor, used by {@link DPIUtil}
437 * <p>
438 * We need to keep track of SWT's implementation in this regard!
439 * </p>
440 */
441 public static float getAutoScalingFactor() throws NativeWindowException {
442 if( null != swt_dpiutil_getScalingFactor ) {
443 try {
444 return (float) swt_dpiutil_getScalingFactor.invoke(null);
445 } catch (final Throwable e) {
446 throw new NativeWindowException(e);
447 }
448 }
449 // Mimick original code ..
450 final int deviceZoom = DPIUtil.getDeviceZoom();
451 if ( 100 == deviceZoom || useCairoAutoScale ) {
452 return 1f;
453 }
454 return deviceZoom/100f;
455 }
456 /**
457 * Returns SWT auto scaled-up value {@code v}, compatible with {@link DPIUtil#autoScaleUp(int)}
458 * <p>
459 * We need to keep track of SWT's implementation in this regard!
460 * </p>
461 */
462 public static int autoScaleUp (final int v) {
463 final int deviceZoom = DPIUtil.getDeviceZoom();
464 if (100 == deviceZoom || useCairoAutoScale) {
465 return v;
466 }
467 final float scaleFactor = deviceZoom/100f;
468 return Math.round (v * scaleFactor);
469 }
470 /**
471 * Returns SWT auto scaled-down value {@code v}, compatible with {@link DPIUtil#autoScaleDown(int)}
472 * <p>
473 * We need to keep track of SWT's implementation in this regard!
474 * </p>
475 */
476 public static int autoScaleDown (final int v) {
477 final int deviceZoom = DPIUtil.getDeviceZoom();
478 if (100 == deviceZoom || useCairoAutoScale) {
479 return v;
480 }
481 final float scaleFactor = deviceZoom/100f;
482 return Math.round (v / scaleFactor);
483 }
484
485 //
486 // SWT DPIUtil derived deviceZoom scale functionality,
487 // not considering the higher-toolkit's compensation like 'DPIUtil.useCairoAutoScale()'
488 //
489 /**
490 * Returns SWT derived scale-factor based on {@link DPIUtil#getDeviceZoom()}
491 * only, not considering higher-toolkit's compensation like {@link DPIUtil#useCairoAutoScale()}.
492 * <p>
493 * This method should be used instead of {@link #getAutoScalingFactor()}
494 * for native toolkits not caring about DPI scaling like X11 or GDI.
495 * </p>
496 * <p>
497 * We need to keep track of SWT's implementation in this regard!
498 * </p>
499 */
500 public static float getDeviceZoomScalingFactor() {
501 final int deviceZoom = DPIUtil.getDeviceZoom();
502 if ( 100 == deviceZoom ) {
503 return 1f;
504 }
505 return deviceZoom/100f;
506 }
507 /**
508 * Returns SWT derived scaled-up value {@code v}, based on {@link DPIUtil#getDeviceZoom()}
509 * only, not considering higher-toolkit's compensation like {@link DPIUtil#useCairoAutoScale()}.
510 * <p>
511 * This method should be used instead of {@link #autoScaleUp(int)}
512 * for native toolkits not caring about DPI scaling like X11 or GDI.
513 * </p>
514 * <p>
515 * We need to keep track of SWT's implementation in this regard!
516 * </p>
517 */
518 public static int deviceZoomScaleUp (final int v) {
519 final int deviceZoom = DPIUtil.getDeviceZoom();
520 if (100 == deviceZoom) {
521 return v;
522 }
523 final float scaleFactor = deviceZoom/100f;
524 return Math.round (v * scaleFactor);
525 }
526 /**
527 * Returns SWT derived scaled-down value {@code v}, based on {@link DPIUtil#getDeviceZoom()}
528 * only, not considering higher-toolkit's compensation like {@link DPIUtil#useCairoAutoScale()}.
529 * <p>
530 * This method should be used instead of {@link #autoScaleDown(int)}
531 * for native toolkits not caring about DPI scaling like X11 or GDI.
532 * </p>
533 * <p>
534 * We need to keep track of SWT's implementation in this regard!
535 * </p>
536 */
537 public static int deviceZoomScaleDown (final int v) {
538 final int deviceZoom = DPIUtil.getDeviceZoom();
539 if (100 == deviceZoom) {
540 return v;
541 }
542 final float scaleFactor = deviceZoom/100f;
543 return Math.round (v / scaleFactor);
544 }
545 /**
546 * Returns SWT derived scaled-up value {@code v}, based on {@link DPIUtil#getDeviceZoom()}
547 * only, not considering higher-toolkit's compensation like {@link DPIUtil#useCairoAutoScale()}.
548 * <p>
549 * This method should be used instead of {@link #autoScaleUp(com.jogamp.nativewindow.util.Point)}
550 * for native toolkits not caring about DPI scaling like X11 or GDI.
551 * </p>
552 * <p>
553 * We need to keep track of SWT's implementation in this regard!
554 * </p>
555 */
556 public static com.jogamp.nativewindow.util.Point deviceZoomScaleUp (final com.jogamp.nativewindow.util.Point v) {
557 final int deviceZoom = DPIUtil.getDeviceZoom();
558 if (100 == deviceZoom || null == v) {
559 return v;
560 }
561 final float scaleFactor = deviceZoom/100f;
562 return v.set(Math.round(v.getX() * scaleFactor), Math.round(v.getY() * scaleFactor));
563 }
564 /**
565 * Returns SWT derived scaled-down value {@code v}, based on {@link DPIUtil#getDeviceZoom()}
566 * only, not considering higher-toolkit's compensation like {@link DPIUtil#useCairoAutoScale()}.
567 * <p>
568 * This method should be used instead of {@link #autoScaleDown(com.jogamp.nativewindow.util.Point)}
569 * for native toolkits not caring about DPI scaling like X11 or GDI.
570 * </p>
571 * <p>
572 * We need to keep track of SWT's implementation in this regard!
573 * </p>
574 */
575 public static com.jogamp.nativewindow.util.Point deviceZoomScaleDown (final com.jogamp.nativewindow.util.Point v) {
576 final int deviceZoom = DPIUtil.getDeviceZoom();
577 if (100 == deviceZoom || null == v) {
578 return v;
579 }
580 final float scaleFactor = deviceZoom/100f;
581 return v.set(Math.round(v.getX() / scaleFactor), Math.round(v.getY() / scaleFactor));
582 }
583
584 /**
585 * Returns the unscaled {@link Scrollable#getClientArea()} in pixels.
586 * <p>
587 * If the package restricted method {@link Scrollable#getClientAreaInPixels()}
588 * is implemented, we return its result.
589 * </p>
590 * <p>
591 * Fallback is to return {@link DPIUtil#autoScaleUp(Rectangle) DPIUtil#autoScaleUp}({@link Scrollable#getClientArea()}),
592 * reverting {@link Scrollable#getClientArea()}'s {@link DPIUtil#autoScaleDown(Rectangle)}.
593 * </p>
594 * <p>
595 * Note to SWT's API spec writers: You need to allow access to the unscaled value, scale properties and define what is being scaled (fonts, images, ..).
596 * Further more the scale should be separate for x/y coordinates, as DPI differs here.
597 * </p>
598 * <p>
599 * Note to Eclipse authors: Scaling up the fonts and images hardly works on GTK/SWT/Eclipse.
600 * GDK_SCALE, GDK_DPI_SCALE and swt.autoScale produce inconsistent results with Eclipse.
601 * Broken High-DPI for .. some years now.
602 * This is especially true for using native high-dpi w/ scaling-factor 1f.
603 * </p>
604 *
605 * Requires SWT >= 3.105 (DPIUtil)
606 *
607 * @param s the {@link Scrollable} instance
608 * @return unscaled client area in pixels, see above
609 * @throws NativeWindowException during invocation of the method, if any
610 */
611 public static Rectangle getClientAreaInPixels(final Scrollable s) throws NativeWindowException {
612 if( null == swt_scrollable_clientAreaInPixels ) {
613 return DPIUtil.autoScaleUp(s.getClientArea());
614 }
615 try {
616 return (Rectangle) swt_scrollable_clientAreaInPixels.invoke(s);
617 } catch (final Throwable e) {
618 throw new NativeWindowException(e);
619 }
620 }
621
622 public static Point getLocationInPixels(final Control c) throws NativeWindowException {
623 if( null == swt_control_locationInPixels ) {
624 return DPIUtil.autoScaleUp(c.getLocation());
625 }
626 try {
627 return (Point) swt_control_locationInPixels.invoke(c);
628 } catch (final Throwable e) {
629 throw new NativeWindowException(e);
630 }
631 }
632 public static Point getSizeInPixels(final Control c) throws NativeWindowException {
633 if( null == swt_control_sizeInPixels ) {
634 return DPIUtil.autoScaleUp(c.getSize());
635 }
636 try {
637 return (Point) swt_control_sizeInPixels.invoke(c);
638 } catch (final Throwable e) {
639 throw new NativeWindowException(e);
640 }
641 }
642
643 /**
644 * @param swtControl the SWT Control to retrieve the native widget-handle from
645 * @return the native widget-handle
646 * @throws NativeWindowException if the widget handle is null
647 */
648 public static long getHandle(final Control swtControl) throws NativeWindowException {
649 long h = 0;
650 if( isOSX ) {
651 synchronized(swt_osx_init) {
652 try {
653 if(null == swt_osx_view_id) {
654 swt_osx_control_view = Control.class.getField(str_osx_view);
655 final Object view = swt_osx_control_view.get(swtControl);
656 swt_osx_view_id = view.getClass().getField(str_osx_id);
657 h = swt_osx_view_id.getLong(view);
658 } else {
659 h = swt_osx_view_id.getLong( swt_osx_control_view.get(swtControl) );
660 }
661 } catch (final Exception ex) {
662 throw new NativeWindowException(ex);
663 }
664 }
665 } else {
666 try {
667 h = swt_control_handle.getLong(swtControl);
668 } catch (final Exception ex) {
669 throw new NativeWindowException(ex);
670 }
671 }
672 if(0 == h) {
673 throw new NativeWindowException("Null widget-handle of SWT "+swtControl.getClass().getName()+": "+swtControl.toString());
674 }
675 return h;
676 }
677
678 public static void setRealized(final Control swtControl, final boolean realize)
680 {
681 if(!realize && swtControl.isDisposed()) {
682 return;
683 }
684 final long handle = getHandle(swtControl);
685
686 if(null != OS_gtk_class) {
687 invokeOnOSTKThread(true, new Runnable() {
688 @Override
689 public void run() {
690 if(realize) {
691 callStaticMethodL2V(OS_gtk_widget_realize, handle);
692 } else if(null != OS_gtk_widget_unrealize) {
693 callStaticMethodL2V(OS_gtk_widget_unrealize, handle);
694 }
695 }
696 });
697 }
698 }
699
700 /**
701 * @param swtControl the SWT Control to retrieve the native device handle from
702 * @return the AbstractGraphicsDevice w/ the native device handle
703 * @throws NativeWindowException if the widget handle is null
704 * @throws UnsupportedOperationException if the windowing system is not supported
705 */
706 public static AbstractGraphicsDevice getDevice(final Control swtControl) throws NativeWindowException, UnsupportedOperationException {
707 final long handle = getHandle(swtControl);
708 if( isX11GTK ) {
709 final long xdisplay0 = gdk_window_get_xdisplay( gdk_widget_get_window( handle ) );
710 return new X11GraphicsDevice(xdisplay0, AbstractGraphicsDevice.DEFAULT_UNIT, false /* owner */);
711 }
712 if( isWindows ) {
714 }
715 if( isOSX ) {
717 }
718 throw new UnsupportedOperationException("n/a for this windowing system: "+nwt);
719 }
720
721 /**
722 * @param device
723 * @param screen -1 is default screen of the given device, e.g. maybe 0 or determined by native API. >= 0 is specific screen
724 * @return
725 */
726 public static AbstractGraphicsScreen getScreen(final AbstractGraphicsDevice device, final int screen) {
727 return NativeWindowFactory.createScreen(device, screen);
728 }
729
730 public static int getNativeVisualID(final AbstractGraphicsDevice device, final long windowHandle) {
731 if( isX11 ) {
732 return X11Lib.GetVisualIDFromWindow(device.getHandle(), windowHandle);
733 }
734 if( isWindows || isOSX ) {
736 }
737 throw new UnsupportedOperationException("n/a for this windowing system: "+nwt);
738 }
739
740 /**
741 * @param swtControl the SWT Control to retrieve the native window handle from
742 * @return the native window handle
743 * @throws NativeWindowException if the widget handle is null
744 * @throws UnsupportedOperationException if the windowing system is not supported
745 */
746 public static long getWindowHandle(final Control swtControl) throws NativeWindowException, UnsupportedOperationException {
747 final long handle = getHandle(swtControl);
748 if(0 == handle) {
749 throw new NativeWindowException("Null SWT handle of SWT control "+swtControl);
750 }
751 if( isX11GTK ) {
753 }
754 if( isWindows || isOSX ) {
755 return handle;
756 }
757 throw new UnsupportedOperationException("n/a for this windowing system: "+nwt);
758 }
759
760 public static long newGC(final Control swtControl, final GCData gcData) {
761 final Object[] o = new Object[1];
762 invokeOnOSTKThread(true, new Runnable() {
763 @Override
764 public void run() {
765 o[0] = ReflectionUtil.callMethod(swtControl, swt_control_internal_new_GC, new Object[] { gcData });
766 }
767 });
768 if(o[0] instanceof Number) {
769 return ((Number)o[0]).longValue();
770 } else {
771 throw new InternalError("SWT internal_new_GC did not return int or long but "+o[0].getClass());
772 }
773 }
774
775 public static void disposeGC(final Control swtControl, final long gc, final GCData gcData) {
776 invokeOnOSTKThread(true, new Runnable() {
777 @Override
778 public void run() {
779 if(swt_uses_long_handles) {
780 ReflectionUtil.callMethod(swtControl, swt_control_internal_dispose_GC, new Object[] { Long.valueOf(gc), gcData });
781 } else {
782 ReflectionUtil.callMethod(swtControl, swt_control_internal_dispose_GC, new Object[] { Integer.valueOf((int)gc), gcData });
783 }
784 }
785 });
786 }
787
788 /**
789 * Runs the specified action in an SWT compatible OS toolkit thread, which is:
790 * <ul>
791 * <li>Mac OSX
792 * <ul>
793 * <li><i>Main Thread</i>: Run on OSX UI main thread. 'wait' is implemented on Java site via lock/wait on {@link RunnableTask} to not freeze OSX main thread.</li>
794 * </ul></li>
795 * <li>Linux, Windows, ..
796 * <ul>
797 * <li>Current thread.</li>
798 * </ul></li>
799 * </ul>
800 * @see Platform#AWT_AVAILABLE
801 * @see Platform#getOSType()
802 */
803 public static void invokeOnOSTKThread(final boolean blocking, final Runnable runnable) {
804 if( isOSX ) {
805 // Use SWT main thread! Only reliable config w/ -XstartOnFirstThread - or - AWT enabled, i.e. `-Djava.awt.headless=false`
806 OSXUtil.RunOnMainThread(blocking, false, runnable);
807 } else {
808 runnable.run();
809 }
810 }
811
812 /**
813 * Runs the specified action on the SWT UI thread.
814 * <p>
815 * If {@code blocking} is {@code true} implementation uses {@link org.eclipse.swt.widgets.Display#syncExec(Runnable)},
816 * otherwise {@link org.eclipse.swt.widgets.Display#asyncExec(Runnable)}.
817 * <p>
818 * If <code>display</code> is {@code null} or disposed or the current thread is the SWT UI thread
819 * {@link #invokeOnOSTKThread(boolean, Runnable)} is being used.
820 * @see #invokeOnOSTKThread(boolean, Runnable)
821 */
822 public static void invokeOnSWTThread(final org.eclipse.swt.widgets.Display display, final boolean blocking, final Runnable runnable) {
823 if( null == display || display.isDisposed() || Thread.currentThread() == display.getThread() ) {
824 invokeOnOSTKThread(blocking, runnable);
825 } else if( blocking ) {
826 display.syncExec(runnable);
827 } else {
828 display.asyncExec(runnable);
829 }
830 }
831
832 /** Return true if the current thread is the SWT UI thread, otherwise false. */
833 public static boolean isOnSWTThread(final org.eclipse.swt.widgets.Display display) {
834 return null != display && Thread.currentThread() == display.getThread();
835 }
836
837 //
838 // Specific X11 GTK ChildWindow - Using plain X11 native parenting (works well)
839 //
840
841 public static long createCompatibleX11ChildWindow(final AbstractGraphicsScreen screen, final Control swtControl, final int visualID, final int width, final int height) {
842 final long handle = getHandle(swtControl);
843 final long parentWindow = gdk_widget_get_window( handle );
844 // gdk_window_set_back_pixmap(parentWindow, 0, false);
845
846 final long x11ParentHandle = gdk_window_get_xwindow(parentWindow);
847 final long x11WindowHandle = X11Lib.CreateWindow(x11ParentHandle, screen.getDevice().getHandle(), screen.getIndex(), visualID, width, height, true, true);
848
849 return x11WindowHandle;
850 }
851
852 public static void resizeX11Window(final AbstractGraphicsDevice device, final Rectangle clientArea, final long x11Window) {
853 X11Lib.SetWindowPosSize(device.getHandle(), x11Window, clientArea.x, clientArea.y, clientArea.width, clientArea.height);
854 }
855 public static void destroyX11Window(final AbstractGraphicsDevice device, final long x11Window) {
856 X11Lib.DestroyWindow(device.getHandle(), x11Window);
857 }
858
859 //
860 // Specific X11 SWT/GTK ChildWindow - Using SWT/GTK native parenting (buggy - sporadic resize flickering, sporadic drop of rendering)
861 //
862 // FIXME: Need to use reflection for 32bit access as well !
863 //
864
865 // public static final int GDK_WA_TYPE_HINT = 1 << 9;
866 // public static final int GDK_WA_VISUAL = 1 << 6;
867
868 public static long createCompatibleGDKChildWindow(final Control swtControl, final int visualID, final int width, final int height) {
869 return 0;
870 /**
871 final long handle = SWTAccessor.getHandle(swtControl);
872 final long parentWindow = gdk_widget_get_window( handle );
873
874 final long screen = OS.gdk_screen_get_default ();
875 final long gdkvisual = OS.gdk_x11_screen_lookup_visual (screen, visualID);
876
877 final GdkWindowAttr attrs = new GdkWindowAttr();
878 attrs.width = width > 0 ? width : 1;
879 attrs.height = height > 0 ? height : 1;
880 attrs.event_mask = OS.GDK_KEY_PRESS_MASK | OS.GDK_KEY_RELEASE_MASK |
881 OS.GDK_FOCUS_CHANGE_MASK | OS.GDK_POINTER_MOTION_MASK |
882 OS.GDK_BUTTON_PRESS_MASK | OS.GDK_BUTTON_RELEASE_MASK |
883 OS.GDK_ENTER_NOTIFY_MASK | OS.GDK_LEAVE_NOTIFY_MASK |
884 OS.GDK_EXPOSURE_MASK | OS.GDK_VISIBILITY_NOTIFY_MASK |
885 OS.GDK_POINTER_MOTION_HINT_MASK;
886 attrs.window_type = OS.GDK_WINDOW_CHILD;
887 attrs.visual = gdkvisual;
888
889 final long childWindow = OS.gdk_window_new (parentWindow, attrs, OS.GDK_WA_VISUAL|GDK_WA_TYPE_HINT);
890 OS.gdk_window_set_user_data (childWindow, handle);
891 OS.gdk_window_set_back_pixmap (parentWindow, 0, false);
892
893 OS.gdk_window_show (childWindow);
894 OS.gdk_flush();
895 return childWindow; */
896 }
897
898 public static void showGDKWindow(final long gdkWindow) {
899 /* OS.gdk_window_show (gdkWindow);
900 OS.gdk_flush(); */
901 }
902 public static void focusGDKWindow(final long gdkWindow) {
903 /*
904 OS.gdk_window_show (gdkWindow);
905 OS.gdk_window_focus(gdkWindow, 0);
906 OS.gdk_flush(); */
907 }
908 public static void resizeGDKWindow(final Rectangle clientArea, final long gdkWindow) {
909 /**
910 OS.gdk_window_move (gdkWindow, clientArea.x, clientArea.y);
911 OS.gdk_window_resize (gdkWindow, clientArea.width, clientArea.height);
912 OS.gdk_flush(); */
913 }
914
915 public static void destroyGDKWindow(final long gdkWindow) {
916 // OS.gdk_window_destroy (gdkWindow);
917 }
918}
A generic exception for OpenGL errors used throughout the binding as a substitute for RuntimeExceptio...
Provides a pluggable mechanism for arbitrary window toolkits to adapt their components to the NativeW...
static synchronized void initSingleton()
Static one time initialization of this factory.
static AbstractGraphicsScreen createScreen(final AbstractGraphicsDevice device, int screen)
Encapsulates a graphics device on MacOSX platforms.
static boolean isOnSWTThread(final org.eclipse.swt.widgets.Display display)
Return true if the current thread is the SWT UI thread, otherwise false.
static void showGDKWindow(final long gdkWindow)
static void destroyGDKWindow(final long gdkWindow)
static long createCompatibleGDKChildWindow(final Control swtControl, final int visualID, final int width, final int height)
static int autoScaleUp(final int v)
Returns SWT auto scaled-up value v, compatible with DPIUtil#autoScaleUp(int).
static long createCompatibleX11ChildWindow(final AbstractGraphicsScreen screen, final Control swtControl, final int visualID, final int width, final int height)
static void invokeOnOSTKThread(final boolean blocking, final Runnable runnable)
Runs the specified action in an SWT compatible OS toolkit thread, which is:
static void initSingleton()
Call this method, if this class shall be initialized before any other of its methods are called withi...
static long newGC(final Control swtControl, final GCData gcData)
static long getWindowHandle(final Control swtControl)
static long getHandle(final Control swtControl)
static void resizeGDKWindow(final Rectangle clientArea, final long gdkWindow)
static int deviceZoomScaleDown(final int v)
Returns SWT derived scaled-down value v, based on DPIUtil#getDeviceZoom() only, not considering highe...
static void destroyX11Window(final AbstractGraphicsDevice device, final long x11Window)
static Rectangle getClientAreaInPixels(final Scrollable s)
Returns the unscaled Scrollable#getClientArea() in pixels.
static void invokeOnSWTThread(final org.eclipse.swt.widgets.Display display, final boolean blocking, final Runnable runnable)
Runs the specified action on the SWT UI thread.
static int deviceZoomScaleUp(final int v)
Returns SWT derived scaled-up value v, based on DPIUtil#getDeviceZoom() only, not considering higher-...
static com.jogamp.nativewindow.util.Point deviceZoomScaleDown(final com.jogamp.nativewindow.util.Point v)
Returns SWT derived scaled-down value v, based on DPIUtil#getDeviceZoom() only, not considering highe...
static float getDeviceZoomScalingFactor()
Returns SWT derived scale-factor based on DPIUtil#getDeviceZoom() only, not considering higher-toolki...
static Point getLocationInPixels(final Control c)
static Point getSizeInPixels(final Control c)
static void focusGDKWindow(final long gdkWindow)
static com.jogamp.nativewindow.util.Point deviceZoomScaleUp(final com.jogamp.nativewindow.util.Point v)
Returns SWT derived scaled-up value v, based on DPIUtil#getDeviceZoom() only, not considering higher-...
static void disposeGC(final Control swtControl, final long gc, final GCData gcData)
static AbstractGraphicsDevice getDevice(final Control swtControl)
static AbstractGraphicsScreen getScreen(final AbstractGraphicsDevice device, final int screen)
static void printInfo(final PrintStream out, final Display d)
static void resizeX11Window(final AbstractGraphicsDevice device, final Rectangle clientArea, final long x11Window)
static long gdk_widget_get_window(final long handle)
static int getNativeVisualID(final AbstractGraphicsDevice device, final long windowHandle)
static long gdk_window_get_xdisplay(final long window)
static void setRealized(final Control swtControl, final boolean realize)
static long gdk_window_get_xwindow(final long window)
static int autoScaleDown(final int v)
Returns SWT auto scaled-down value v, compatible with DPIUtil#autoScaleDown(int).
static final VersionNumber OS_gtk_version
static float getAutoScalingFactor()
Returns SWT compatible auto scale-factor, used by DPIUtil.
Encapsulates a graphics device on Windows platforms.
Encapsulates a graphics device on X11 platforms.
A interface describing a graphics device in a toolkit-independent manner.
long getHandle()
Returns the native handle of the underlying native device, if such thing exist.
static int DEFAULT_UNIT
Default unit id for the 1st device: 0.
A interface describing a graphics screen in a toolkit-independent manner.
int getIndex()
Returns the screen index this graphics screen is valid for.
AbstractGraphicsDevice getDevice()
Return the device this graphics configuration is valid for.
static final int VID_UNDEFINED
getVisualID(VIDType) result indicating an undefined value, which could be cause by an unsupported que...