JOGL v2.6.0-rc-20250822
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
83 // X11/GTK, Windows/GDI, ..
84 private static final String str_handle = "handle";
85
86 // OSX/Cocoa
87 private static final String str_osx_view = "view"; // OSX
88 private static final String str_osx_id = "id"; // OSX
89 // static final String str_NSView = "org.eclipse.swt.internal.cocoa.NSView";
90
91 private static final Method swt_control_internal_new_GC;
92 private static final Method swt_control_internal_dispose_GC;
93 private static final String str_internal_new_GC = "internal_new_GC";
94 private static final String str_internal_dispose_GC = "internal_dispose_GC";
95
96 private static final String str_OS_gtk_class = "org.eclipse.swt.internal.gtk.OS"; // used by earlier versions of SWT
97 private static final String str_GTK_gtk_class = "org.eclipse.swt.internal.gtk.GTK"; // used by later versions of SWT
98 private static final String str_GTK3_gtk_class = "org.eclipse.swt.internal.gtk3.GTK3"; // used by later versions of SWT (4.21+)
99 private static final String str_GDK_gtk_class = "org.eclipse.swt.internal.gtk.GDK"; // used by later versions of SWT
100 public static final Class<?> OS_gtk_class;
101 private static final String str_OS_gtk_version = "GTK_VERSION";
102 public static final VersionNumber OS_gtk_version;
103
104 private static final Method OS_gtk_widget_realize;
105 private static final Method OS_gtk_widget_unrealize; // optional (removed in SWT 4.3)
106 private static final Method OS_GTK_WIDGET_WINDOW;
107 private static final Method OS_gtk_widget_get_window;
108 private static final Method OS_gdk_x11_drawable_get_xdisplay;
109 private static final Method OS_gdk_x11_display_get_xdisplay;
110 private static final Method OS_gdk_window_get_display;
111 private static final Method OS_gdk_x11_drawable_get_xid;
112 private static final Method OS_gdk_x11_window_get_xid;
113
114 private static final String str_gtk_widget_realize = "gtk_widget_realize";
115 private static final String str_gtk_widget_unrealize = "gtk_widget_unrealize";
116 private static final String str_GTK_WIDGET_WINDOW = "GTK_WIDGET_WINDOW";
117 private static final String str_gtk_widget_get_window = "gtk_widget_get_window";
118 private static final String str_gdk_x11_drawable_get_xdisplay = "gdk_x11_drawable_get_xdisplay";
119 private static final String str_gdk_x11_display_get_xdisplay = "gdk_x11_display_get_xdisplay";
120 private static final String str_gdk_window_get_display = "gdk_window_get_display";
121 private static final String str_gdk_x11_drawable_get_xid = "gdk_x11_drawable_get_xid";
122 private static final String str_gdk_x11_window_get_xid = "gdk_x11_window_get_xid";
123
124 private static final VersionNumber GTK_VERSION_2_14_0 = new VersionNumber(2, 14, 0);
125 private static final VersionNumber GTK_VERSION_2_24_0 = new VersionNumber(2, 24, 0);
126 // private static final VersionNumber GTK_VERSION_2_90_0 = new VersionNumber(2, 90, 0);
127 private static final VersionNumber GTK_VERSION_3_0_0 = new VersionNumber(3, 0, 0);
128 // private static final VersionNumber GTK_VERSION_4_0_0 = new VersionNumber(4, 0, 0);
129
130 private static VersionNumber GTK_VERSION(final int version) {
131 // return (major << 16) + (minor << 8) + micro;
132 final int micro = ( version ) & 0xff;
133 final int minor = ( version >> 8 ) & 0xff;
134 final int major = ( version >> 16 ) & 0xff;
135 return new VersionNumber(major, minor, micro);
136 }
137
138 static {
139 final int SWT_VERSION_4_20 = 4944;
140 // final int SWT_VERSION_4_26 = 4956;
141 // major * 1000 + minor;
142
143 SecurityUtil.doPrivileged(new PrivilegedAction<Object>() {
144 @Override
145 public Object run() {
146 NativeWindowFactory.initSingleton(); // last resort ..
147 return null;
148 } } );
149
150 nwt = NativeWindowFactory.getNativeWindowType(false);
151 isOSX = NativeWindowFactory.TYPE_MACOSX == nwt;
152 isWindows = NativeWindowFactory.TYPE_WINDOWS == nwt;
153 isX11 = NativeWindowFactory.TYPE_X11 == nwt;
154 final int swt_version = SWT.getVersion();
155
156 if( DEBUG ) {
157 System.err.println("SWT: Platform: "+SWT.getPlatform()+", Version: "+swt_version);
158 }
159
160 Method m = null;
161 try {
162 m = Control.class.getDeclaredMethod("getLocationInPixels");
163 m.setAccessible(true);
164 } catch (final Exception ex) {
165 m = null;
166 if( DEBUG ) {
167 System.err.println("SWT: getLocationInPixels not implemented: "+ex.getMessage());
168 }
169 }
170 swt_control_locationInPixels = m;
171
172 m = null;
173 try {
174 m = Control.class.getDeclaredMethod("getSizeInPixels");
175 m.setAccessible(true);
176 } catch (final Exception ex) {
177 m = null;
178 if( DEBUG ) {
179 System.err.println("SWT: getSizeInPixels not implemented: "+ex.getMessage());
180 }
181 }
182 swt_control_sizeInPixels = m;
183
184 m = null;
185 try {
186 m = Scrollable.class.getDeclaredMethod("getClientAreaInPixels");
187 m.setAccessible(true);
188 } catch (final Exception ex) {
189 m = null;
190 if( DEBUG ) {
191 System.err.println("SWT: getClientAreaInPixels not implemented: "+ex.getMessage());
192 }
193 }
194 swt_scrollable_clientAreaInPixels = m;
195
196 m = null;
197 try {
198 m = DPIUtil.class.getDeclaredMethod("getScalingFactor");
199 m.setAccessible(true);
200 } catch (final Exception ex) {
201 m = null;
202 if( DEBUG ) {
203 System.err.println("SWT: getScalingFactor not implemented: "+ex.getMessage());
204 }
205 }
206 swt_dpiutil_getScalingFactor = m;
207
208 Field f = null;
209 if( !isOSX ) {
210 try {
211 f = Control.class.getField(str_handle);
212 } catch (final Exception ex) {
213 throw new NativeWindowException(ex);
214 }
215 }
216 swt_control_handle = f; // maybe null !
217
218 boolean ulh;
219 if (null != swt_control_handle) {
220 ulh = swt_control_handle.getGenericType().toString().equals(long.class.toString());
221 } else {
222 ulh = Platform.is64Bit();
223 }
224 swt_uses_long_handles = ulh;
225 // System.err.println("SWT long handles: " + swt_uses_long_handles);
226 // System.err.println("Platform 64bit: "+Platform.is64Bit());
227
228 m=null;
229 try {
230 m = ReflectionUtil.getMethod(Control.class, str_internal_new_GC, new Class[] { GCData.class });
231 } catch (final Exception ex) {
232 throw new NativeWindowException(ex);
233 }
234 swt_control_internal_new_GC = m;
235
236 m=null;
237 try {
238 if(swt_uses_long_handles) {
239 m = Control.class.getDeclaredMethod(str_internal_dispose_GC, new Class[] { long.class, GCData.class });
240 } else {
241 m = Control.class.getDeclaredMethod(str_internal_dispose_GC, new Class[] { int.class, GCData.class });
242 }
243 } catch (final NoSuchMethodException ex) {
244 throw new NativeWindowException(ex);
245 }
246 swt_control_internal_dispose_GC = m;
247
248 Class<?> cGTK=null;
249 VersionNumber _gtk_version = new VersionNumber(0, 0, 0);
250 Method m1=null, m2=null, m3=null, m4=null, m5=null, m6=null, m7=null, m8=null, m9=null;
251 final Class<?> handleType = swt_uses_long_handles ? long.class : int.class ;
252 if( isX11 ) {
253 // mandatory
254 try {
255 final ClassLoader cl = SWTAccessor.class.getClassLoader();
256 cGTK = ReflectionUtil.getClass(str_OS_gtk_class, false, cl);
257 Field field_OS_gtk_version;
258 Class<?> cGDK=cGTK; // used for newer versions of SWT that have a org.eclipse.swt.internal.gtk.GDK object
259 try {
260 field_OS_gtk_version = cGTK.getField(str_OS_gtk_version);
261 } catch (final NoSuchFieldException ex) {
262 // if the GTK_VERSION field didn't exist in org.eclipse.swt.internal.gtk.OS, then look for
263 // it in org.eclipse.swt.internal.gtk.GTK, where it was moved in later versions of SWT
264 cGTK = ReflectionUtil.getClass(str_GTK_gtk_class, false, cl);
265 field_OS_gtk_version = cGTK.getField(str_OS_gtk_version);
266 cGDK = ReflectionUtil.getClass(str_GDK_gtk_class, false, cl);
267 }
268 _gtk_version = GTK_VERSION(field_OS_gtk_version.getInt(null));
269 if( DEBUG ) {
270 System.err.println("SWT: GTK Version: "+_gtk_version.toString());
271 }
272 m1 = cGTK.getDeclaredMethod(str_gtk_widget_realize, handleType);
273 if (_gtk_version.compareTo(GTK_VERSION_2_14_0) >= 0) {
274 if (swt_version < SWT_VERSION_4_20) {
275 m4 = cGTK.getDeclaredMethod(str_gtk_widget_get_window, handleType);
276 } else {
277 final Class<?> cGTK3 = ReflectionUtil.getClass(str_GTK3_gtk_class, false, cl);
278 m4 = cGTK3.getDeclaredMethod(str_gtk_widget_get_window, handleType);
279 }
280 } else {
281 m3 = cGTK.getDeclaredMethod(str_GTK_WIDGET_WINDOW, handleType);
282 }
283 if (_gtk_version.compareTo(GTK_VERSION_2_24_0) >= 0) {
284 m6 = cGDK.getDeclaredMethod(str_gdk_x11_display_get_xdisplay, handleType);
285 m7 = cGDK.getDeclaredMethod(str_gdk_window_get_display, handleType);
286 } else {
287 m5 = cGTK.getDeclaredMethod(str_gdk_x11_drawable_get_xdisplay, handleType);
288 }
289 if (_gtk_version.compareTo(GTK_VERSION_3_0_0) >= 0) {
290 m9 = cGDK.getDeclaredMethod(str_gdk_x11_window_get_xid, handleType);
291 } else {
292 m8 = cGTK.getDeclaredMethod(str_gdk_x11_drawable_get_xid, handleType);
293 }
294 } catch (final Exception ex) { throw new NativeWindowException(ex); }
295 // optional
296 try {
297 m2 = cGTK.getDeclaredMethod(str_gtk_widget_unrealize, handleType);
298 } catch (final Exception ex) { }
299 }
300 OS_gtk_class = cGTK;
301 OS_gtk_version = _gtk_version;
302 OS_gtk_widget_realize = m1;
303 OS_gtk_widget_unrealize = m2;
304 OS_GTK_WIDGET_WINDOW = m3;
305 OS_gtk_widget_get_window = m4;
306 OS_gdk_x11_drawable_get_xdisplay = m5;
307 OS_gdk_x11_display_get_xdisplay = m6;
308 OS_gdk_window_get_display = m7;
309 OS_gdk_x11_drawable_get_xid = m8;
310 OS_gdk_x11_window_get_xid = m9;
311
312 isX11GTK = isX11 && null != OS_gtk_class;
313 if( DEBUG ) {
314 printInfo(System.err, null);
315 }
316 }
317
318 /**
319 * Call this method, if this class shall be initialized before any other of its methods are called
320 * within the regular workflow.
321 *
322 * This could be desired to ensure initialization before AWT.
323 *
324 * This method does nothing, but initializes this class's static SWT accessors if using this class for the first time.
325 */
326 public static void initSingleton() {}
327
328 private static Number getIntOrLong(final long arg) {
329 if(swt_uses_long_handles) {
330 return Long.valueOf(arg);
331 }
332 return Integer.valueOf((int) arg);
333 }
334
335 private static void callStaticMethodL2V(final Method m, final long arg) {
336 ReflectionUtil.callMethod(null, m, new Object[] { getIntOrLong(arg) });
337 }
338
339 @SuppressWarnings("unused")
340 private static void callStaticMethodLL2V(final Method m, final long arg0, final long arg1) {
341 ReflectionUtil.callMethod(null, m, new Object[] { getIntOrLong(arg0), getIntOrLong(arg1) });
342 }
343
344 @SuppressWarnings("unused")
345 private static void callStaticMethodLLZ2V(final Method m, final long arg0, final long arg1, final boolean arg3) {
346 ReflectionUtil.callMethod(null, m, new Object[] { getIntOrLong(arg0), getIntOrLong(arg1), Boolean.valueOf(arg3) });
347 }
348
349 private static long callStaticMethodL2L(final Method m, final long arg) {
350 final Object o = ReflectionUtil.callMethod(null, m, new Object[] { getIntOrLong(arg) });
351 if(o instanceof Number) {
352 return ((Number)o).longValue();
353 } else {
354 throw new InternalError("SWT method "+m.getName()+" didn't return int or long but "+o.getClass());
355 }
356 }
357
358 //
359 // Public properties
360 //
361
362 public static boolean isUsingLongHandles() {
363 return swt_uses_long_handles;
364 }
365
366 public static boolean useX11GTK() { return isX11GTK; }
367 public static VersionNumber GTK_VERSION() { return OS_gtk_version; }
368
369 //
370 // Common GTK
371 //
372
373 public static long gdk_widget_get_window(final long handle) {
374 final long window;
375 if (OS_gtk_version.compareTo(GTK_VERSION_2_14_0) >= 0) {
376 window = callStaticMethodL2L(OS_gtk_widget_get_window, handle);
377 } else {
378 window = callStaticMethodL2L(OS_GTK_WIDGET_WINDOW, handle);
379 }
380 if(0 == window) {
381 throw new NativeWindowException("Null gtk-window-handle of SWT handle 0x"+Long.toHexString(handle));
382 }
383 return window;
384 }
385
386 public static long gdk_window_get_xdisplay(final long window) {
387 final long xdisplay;
388 if (OS_gtk_version.compareTo(GTK_VERSION_2_24_0) >= 0) {
389 final long display = callStaticMethodL2L(OS_gdk_window_get_display, window);
390 if(0 == display) {
391 throw new NativeWindowException("Null display-handle of gtk-window-handle 0x"+Long.toHexString(window));
392 }
393 xdisplay = callStaticMethodL2L(OS_gdk_x11_display_get_xdisplay, display);
394 } else {
395 xdisplay = callStaticMethodL2L(OS_gdk_x11_drawable_get_xdisplay, window);
396 }
397 if(0 == xdisplay) {
398 throw new NativeWindowException("Null x11-display-handle of gtk-window-handle 0x"+Long.toHexString(window));
399 }
400 return xdisplay;
401 }
402
403 public static long gdk_window_get_xwindow(final long window) {
404 final long xWindow;
405 if (OS_gtk_version.compareTo(GTK_VERSION_3_0_0) >= 0) {
406 xWindow = callStaticMethodL2L(OS_gdk_x11_window_get_xid, window);
407 } else {
408 xWindow = callStaticMethodL2L(OS_gdk_x11_drawable_get_xid, window);
409 }
410 if(0 == xWindow) {
411 throw new NativeWindowException("Null x11-window-handle of gtk-window-handle 0x"+Long.toHexString(window));
412 }
413 return xWindow;
414 }
415
416 //
417 // Common any toolkit
418 //
419 public static void printInfo(final PrintStream out, final Display d) {
420 out.println("SWT: Platform: "+SWT.getPlatform()+", Version "+SWT.getVersion());
421 out.println("SWT: isX11 "+isX11+", isX11GTK "+isX11GTK+" (GTK Version: "+OS_gtk_version+")");
422 out.println("SWT: isOSX "+isOSX+", isWindows "+isWindows);
423 out.println("SWT: deviceZoom "+DPIUtil.getDeviceZoom()+", deviceScalingFactor "+getDeviceScalingFactor());
424 final Point dpi = null != d ? d.getDPI() : null;
425 out.println("SWT: Display.DPI "+dpi);
426 out.println("SWT: swt_dpiutil_getScalingFactor "+(null != swt_dpiutil_getScalingFactor));
427 out.println("SWT: swt_scrollable_clientAreaInPixels "+(null != swt_scrollable_clientAreaInPixels));
428 }
429
430 //
431 // SWT DPIUtil derived deviceZoom scale functionality,
432 // not considering the higher-toolkit's compensation like 'DPIUtil.useCairoAutoScale()'
433 //
434
435 /**
436 * Returns SWT auto scaled-up value {@code v}, compatible with {@link DPIUtil#autoScaleUp(int)}
437 * <p>
438 * We need to keep track of SWT's implementation in this regard!
439 * </p>
440 */
441 public static int autoScaleUp (final int v) {
442 final int deviceZoom = DPIUtil.getDeviceZoom();
443 if (100 == deviceZoom) {
444 return v;
445 }
446 final float scaleFactor = deviceZoom/100f;
447 return Math.round (v * scaleFactor);
448 }
449 /**
450 * Returns SWT auto scaled-down value {@code v}, compatible with {@link DPIUtil#autoScaleDown(int)}
451 * <p>
452 * We need to keep track of SWT's implementation in this regard!
453 * </p>
454 */
455 public static int autoScaleDown (final int v) {
456 final int deviceZoom = DPIUtil.getDeviceZoom();
457 if (100 == deviceZoom) {
458 return v;
459 }
460 final float scaleFactor = deviceZoom/100f;
461 return Math.round (v / scaleFactor);
462 }
463
464 public static Rectangle autoScaleUp(final Rectangle rect) { return scaleUp(rect, DPIUtil.getDeviceZoom() ); }
465 public static Rectangle scaleUp(final Rectangle rect, final int zoom) {
466 if (zoom == 100 || rect == null) return rect;
467 final Rectangle scaledRect = new Rectangle(0,0,0,0);
468 final Point scaledTopLeft = scaleUp (new Point(rect.x, rect.y), zoom);
469 final Point scaledBottomRight = scaleUp (new Point(rect.x + rect.width, rect.y + rect.height), zoom);
470
471 scaledRect.x = scaledTopLeft.x;
472 scaledRect.y = scaledTopLeft.y;
473 scaledRect.width = scaledBottomRight.x - scaledTopLeft.x;
474 scaledRect.height = scaledBottomRight.y - scaledTopLeft.y;
475 return scaledRect;
476 }
477
478 public static Point autoScaleUp(final Point point) { return scaleUp(point, DPIUtil.getDeviceZoom() ); }
479 public static Point scaleUp(final Point point, final int zoom) {
480 if (zoom == 100 || point == null) return point;
481 final float scaleFactor = zoom <= 0 ? getDeviceScalingFactor() : zoom/100f;
482 final Point scaledPoint = new Point(0,0);
483 scaledPoint.x = Math.round (point.x * scaleFactor);
484 scaledPoint.y = Math.round (point.y * scaleFactor);
485 return scaledPoint;
486 }
487
488 /**
489 * Returns SWT derived scale-factor based on {@link DPIUtil#getDeviceZoom()}
490 * only, not considering higher-toolkit's compensation like {@link DPIUtil#useCairoAutoScale()}.
491 * <p>
492 * This method should be used instead of {@link #getAutoScalingFactor()}
493 * for native toolkits not caring about DPI scaling like X11 or GDI.
494 * </p>
495 * <p>
496 * We need to keep track of SWT's implementation in this regard!
497 * </p>
498 */
499 public static float getDeviceScalingFactor() {
500 final int deviceZoom = DPIUtil.getDeviceZoom();
501 if ( 100 == deviceZoom ) {
502 return 1f;
503 }
504 return deviceZoom/100f;
505 }
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 autoScaleUp(s.getClientArea());
614 }
615 try {
616 final Rectangle r = (Rectangle) swt_scrollable_clientAreaInPixels.invoke(s);
617 if( isX11GTK ) {
618 return autoScaleUp(r); // for GTK, getClientAreaInPixels() is not scaled!
619 }
620 return r;
621 } catch (final Throwable e) {
622 throw new NativeWindowException(e);
623 }
624 }
625
626 public static Point getLocationInPixels(final Control c) throws NativeWindowException {
627 if( null == swt_control_locationInPixels ) {
628 return autoScaleUp(c.getLocation());
629 }
630 try {
631 return (Point) swt_control_locationInPixels.invoke(c);
632 } catch (final Throwable e) {
633 throw new NativeWindowException(e);
634 }
635 }
636 public static Point getSizeInPixels(final Control c) throws NativeWindowException {
637 if( null == swt_control_sizeInPixels ) {
638 return autoScaleUp(c.getSize());
639 }
640 try {
641 return (Point) swt_control_sizeInPixels.invoke(c);
642 } catch (final Throwable e) {
643 throw new NativeWindowException(e);
644 }
645 }
646
647 /**
648 * @param swtControl the SWT Control to retrieve the native widget-handle from
649 * @return the native widget-handle
650 * @throws NativeWindowException if the widget handle is null
651 */
652 public static long getHandle(final Control swtControl) throws NativeWindowException {
653 long h = 0;
654 if( isOSX ) {
655 synchronized(swt_osx_init) {
656 try {
657 if(null == swt_osx_view_id) {
658 swt_osx_control_view = Control.class.getField(str_osx_view);
659 final Object view = swt_osx_control_view.get(swtControl);
660 swt_osx_view_id = view.getClass().getField(str_osx_id);
661 h = swt_osx_view_id.getLong(view);
662 } else {
663 h = swt_osx_view_id.getLong( swt_osx_control_view.get(swtControl) );
664 }
665 } catch (final Exception ex) {
666 throw new NativeWindowException(ex);
667 }
668 }
669 } else {
670 try {
671 h = swt_control_handle.getLong(swtControl);
672 } catch (final Exception ex) {
673 throw new NativeWindowException(ex);
674 }
675 }
676 if(0 == h) {
677 throw new NativeWindowException("Null widget-handle of SWT "+swtControl.getClass().getName()+": "+swtControl.toString());
678 }
679 return h;
680 }
681
682 public static void setRealized(final Control swtControl, final boolean realize)
684 {
685 if(!realize && swtControl.isDisposed()) {
686 return;
687 }
688 final long handle = getHandle(swtControl);
689
690 if(null != OS_gtk_class) {
691 invokeOnOSTKThread(true, new Runnable() {
692 @Override
693 public void run() {
694 if(realize) {
695 callStaticMethodL2V(OS_gtk_widget_realize, handle);
696 } else if(null != OS_gtk_widget_unrealize) {
697 callStaticMethodL2V(OS_gtk_widget_unrealize, handle);
698 }
699 }
700 });
701 }
702 }
703
704 /**
705 * @param swtControl the SWT Control to retrieve the native device handle from
706 * @return the AbstractGraphicsDevice w/ the native device handle
707 * @throws NativeWindowException if the widget handle is null
708 * @throws UnsupportedOperationException if the windowing system is not supported
709 */
710 public static AbstractGraphicsDevice getDevice(final Control swtControl) throws NativeWindowException, UnsupportedOperationException {
711 final long handle = getHandle(swtControl);
712 if( isX11GTK ) {
713 final long xdisplay0 = gdk_window_get_xdisplay( gdk_widget_get_window( handle ) );
714 return new X11GraphicsDevice(xdisplay0, AbstractGraphicsDevice.DEFAULT_UNIT, false /* owner */);
715 }
716 if( isWindows ) {
718 }
719 if( isOSX ) {
721 }
722 throw new UnsupportedOperationException("n/a for this windowing system: "+nwt);
723 }
724
725 /**
726 * @param device
727 * @param screen -1 is default screen of the given device, e.g. maybe 0 or determined by native API. >= 0 is specific screen
728 * @return
729 */
730 public static AbstractGraphicsScreen getScreen(final AbstractGraphicsDevice device, final int screen) {
731 return NativeWindowFactory.createScreen(device, screen);
732 }
733
734 public static int getNativeVisualID(final AbstractGraphicsDevice device, final long windowHandle) {
735 if( isX11 ) {
736 return X11Lib.GetVisualIDFromWindow(device.getHandle(), windowHandle);
737 }
738 if( isWindows || isOSX ) {
740 }
741 throw new UnsupportedOperationException("n/a for this windowing system: "+nwt);
742 }
743
744 /**
745 * @param swtControl the SWT Control to retrieve the native window handle from
746 * @return the native window handle
747 * @throws NativeWindowException if the widget handle is null
748 * @throws UnsupportedOperationException if the windowing system is not supported
749 */
750 public static long getWindowHandle(final Control swtControl) throws NativeWindowException, UnsupportedOperationException {
751 final long handle = getHandle(swtControl);
752 if(0 == handle) {
753 throw new NativeWindowException("Null SWT handle of SWT control "+swtControl);
754 }
755 if( isX11GTK ) {
757 }
758 if( isWindows || isOSX ) {
759 return handle;
760 }
761 throw new UnsupportedOperationException("n/a for this windowing system: "+nwt);
762 }
763
764 public static long newGC(final Control swtControl, final GCData gcData) {
765 final Object[] o = new Object[1];
766 invokeOnOSTKThread(true, new Runnable() {
767 @Override
768 public void run() {
769 o[0] = ReflectionUtil.callMethod(swtControl, swt_control_internal_new_GC, new Object[] { gcData });
770 }
771 });
772 if(o[0] instanceof Number) {
773 return ((Number)o[0]).longValue();
774 } else {
775 throw new InternalError("SWT internal_new_GC did not return int or long but "+o[0].getClass());
776 }
777 }
778
779 public static void disposeGC(final Control swtControl, final long gc, final GCData gcData) {
780 invokeOnOSTKThread(true, new Runnable() {
781 @Override
782 public void run() {
783 if(swt_uses_long_handles) {
784 ReflectionUtil.callMethod(swtControl, swt_control_internal_dispose_GC, new Object[] { Long.valueOf(gc), gcData });
785 } else {
786 ReflectionUtil.callMethod(swtControl, swt_control_internal_dispose_GC, new Object[] { Integer.valueOf((int)gc), gcData });
787 }
788 }
789 });
790 }
791
792 /**
793 * Runs the specified action in an SWT compatible OS toolkit thread, which is:
794 * <ul>
795 * <li>Mac OSX
796 * <ul>
797 * <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>
798 * </ul></li>
799 * <li>Linux, Windows, ..
800 * <ul>
801 * <li>Current thread.</li>
802 * </ul></li>
803 * </ul>
804 * @see Platform#AWT_AVAILABLE
805 * @see Platform#getOSType()
806 */
807 public static void invokeOnOSTKThread(final boolean blocking, final Runnable runnable) {
808 if( isOSX ) {
809 // Use SWT main thread! Only reliable config w/ -XstartOnFirstThread - or - AWT enabled, i.e. `-Djava.awt.headless=false`
810 OSXUtil.RunOnMainThread(blocking, false, runnable);
811 } else {
812 runnable.run();
813 }
814 }
815
816 /**
817 * Runs the specified action on the SWT UI thread.
818 * <p>
819 * If {@code blocking} is {@code true} implementation uses {@link org.eclipse.swt.widgets.Display#syncExec(Runnable)},
820 * otherwise {@link org.eclipse.swt.widgets.Display#asyncExec(Runnable)}.
821 * <p>
822 * If <code>display</code> is {@code null} or disposed or the current thread is the SWT UI thread
823 * {@link #invokeOnOSTKThread(boolean, Runnable)} is being used.
824 * @see #invokeOnOSTKThread(boolean, Runnable)
825 */
826 public static void invokeOnSWTThread(final org.eclipse.swt.widgets.Display display, final boolean blocking, final Runnable runnable) {
827 if( null == display || display.isDisposed() || Thread.currentThread() == display.getThread() ) {
828 invokeOnOSTKThread(blocking, runnable);
829 } else if( blocking ) {
830 display.syncExec(runnable);
831 } else {
832 display.asyncExec(runnable);
833 }
834 }
835
836 /** Return true if the current thread is the SWT UI thread, otherwise false. */
837 public static boolean isOnSWTThread(final org.eclipse.swt.widgets.Display display) {
838 return null != display && Thread.currentThread() == display.getThread();
839 }
840
841 //
842 // Specific X11 GTK ChildWindow - Using plain X11 native parenting (works well)
843 //
844
845 public static long createCompatibleX11ChildWindow(final AbstractGraphicsScreen screen, final Control swtControl, final int visualID, final int width, final int height) {
846 final long handle = getHandle(swtControl);
847 final long parentWindow = gdk_widget_get_window( handle );
848 // gdk_window_set_back_pixmap(parentWindow, 0, false);
849
850 final long x11ParentHandle = gdk_window_get_xwindow(parentWindow);
851 final long x11WindowHandle = X11Lib.CreateWindow(x11ParentHandle, screen.getDevice().getHandle(), screen.getIndex(), visualID, width, height, true, true);
852
853 return x11WindowHandle;
854 }
855
856 public static void resizeX11Window(final AbstractGraphicsDevice device, final Rectangle clientArea, final long x11Window) {
857 X11Lib.SetWindowPosSize(device.getHandle(), x11Window, clientArea.x, clientArea.y, clientArea.width, clientArea.height);
858 }
859 public static void destroyX11Window(final AbstractGraphicsDevice device, final long x11Window) {
860 X11Lib.DestroyWindow(device.getHandle(), x11Window);
861 }
862
863 //
864 // Specific X11 SWT/GTK ChildWindow - Using SWT/GTK native parenting (buggy - sporadic resize flickering, sporadic drop of rendering)
865 //
866 // FIXME: Need to use reflection for 32bit access as well !
867 //
868
869 // public static final int GDK_WA_TYPE_HINT = 1 << 9;
870 // public static final int GDK_WA_VISUAL = 1 << 6;
871
872 public static long createCompatibleGDKChildWindow(final Control swtControl, final int visualID, final int width, final int height) {
873 return 0;
874 /**
875 final long handle = SWTAccessor.getHandle(swtControl);
876 final long parentWindow = gdk_widget_get_window( handle );
877
878 final long screen = OS.gdk_screen_get_default ();
879 final long gdkvisual = OS.gdk_x11_screen_lookup_visual (screen, visualID);
880
881 final GdkWindowAttr attrs = new GdkWindowAttr();
882 attrs.width = width > 0 ? width : 1;
883 attrs.height = height > 0 ? height : 1;
884 attrs.event_mask = OS.GDK_KEY_PRESS_MASK | OS.GDK_KEY_RELEASE_MASK |
885 OS.GDK_FOCUS_CHANGE_MASK | OS.GDK_POINTER_MOTION_MASK |
886 OS.GDK_BUTTON_PRESS_MASK | OS.GDK_BUTTON_RELEASE_MASK |
887 OS.GDK_ENTER_NOTIFY_MASK | OS.GDK_LEAVE_NOTIFY_MASK |
888 OS.GDK_EXPOSURE_MASK | OS.GDK_VISIBILITY_NOTIFY_MASK |
889 OS.GDK_POINTER_MOTION_HINT_MASK;
890 attrs.window_type = OS.GDK_WINDOW_CHILD;
891 attrs.visual = gdkvisual;
892
893 final long childWindow = OS.gdk_window_new (parentWindow, attrs, OS.GDK_WA_VISUAL|GDK_WA_TYPE_HINT);
894 OS.gdk_window_set_user_data (childWindow, handle);
895 OS.gdk_window_set_back_pixmap (parentWindow, 0, false);
896
897 OS.gdk_window_show (childWindow);
898 OS.gdk_flush();
899 return childWindow; */
900 }
901
902 public static void showGDKWindow(final long gdkWindow) {
903 /* OS.gdk_window_show (gdkWindow);
904 OS.gdk_flush(); */
905 }
906 public static void focusGDKWindow(final long gdkWindow) {
907 /*
908 OS.gdk_window_show (gdkWindow);
909 OS.gdk_window_focus(gdkWindow, 0);
910 OS.gdk_flush(); */
911 }
912 public static void resizeGDKWindow(final Rectangle clientArea, final long gdkWindow) {
913 /**
914 OS.gdk_window_move (gdkWindow, clientArea.x, clientArea.y);
915 OS.gdk_window_resize (gdkWindow, clientArea.width, clientArea.height);
916 OS.gdk_flush(); */
917 }
918
919 public static void destroyGDKWindow(final long gdkWindow) {
920 // OS.gdk_window_destroy (gdkWindow);
921 }
922}
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 Point scaleUp(final Point point, final int zoom)
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 Rectangle scaleUp(final Rectangle rect, final int zoom)
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 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 float getDeviceScalingFactor()
Returns SWT derived scale-factor based on DPIUtil#getDeviceZoom() only, not considering higher-toolki...
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 Point autoScaleUp(final Point point)
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 Rectangle autoScaleUp(final Rectangle rect)
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...