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  */
28 
29 #include "NativewindowCommon.h"
30 #include "Xmisc.h"
31 #include "jogamp_nativewindow_x11_X11Lib.h"
32 #include "jogamp_nativewindow_x11_X11Util.h"
33 
34 #include <X11/Xatom.h>
35 
36 #include <X11/extensions/Xrender.h>
37 
38 /** Remove memcpy GLIBC > 2.4 dependencies */
39 #include <glibc-compat-symbols.h>
40 
41 // #define VERBOSE_ON 1
42 
43 #ifdef VERBOSE_ON
44     #define DBG_PRINT(args...) fprintf(stderr, args);
45 #else
46     #define DBG_PRINT(args...)
47 #endif
48 
49 
50 /* Linux headers don't work properly */
51 #define __USE_GNU
52 #include <dlfcn.h>
53 #undef __USE_GNU
54 
55 #include "Xmisc.h"
56 
57 /* Current versions of Solaris don't expose the XF86 extensions,
58    although with the recent transition to Xorg this will probably
59    happen in an upcoming release */
60 #if defined(__sun_obsolete) || defined(_HPUX)
61 /* Need to provide stubs for these */
XF86VidModeGetGammaRampSize(Display * display,int screen,int * size)62 Bool XF86VidModeGetGammaRampSize(
63     Display *display,
64     int screen,
65     int* size)
66 {
67   return False;
68 }
69 
XF86VidModeGetGammaRamp(Display * display,int screen,int size,unsigned short * red_array,unsigned short * green_array,unsigned short * blue_array)70 Bool XF86VidModeGetGammaRamp(
71     Display *display,
72     int screen,
73     int size,
74     unsigned short *red_array,
75     unsigned short *green_array,
76     unsigned short *blue_array) {
77   return False;
78 }
XF86VidModeSetGammaRamp(Display * display,int screen,int size,unsigned short * red_array,unsigned short * green_array,unsigned short * blue_array)79 Bool XF86VidModeSetGammaRamp(
80     Display *display,
81     int screen,
82     int size,
83     unsigned short *red_array,
84     unsigned short *green_array,
85     unsigned short *blue_array) {
86   return False;
87 }
88 #endif /* defined(__sun_obsolete) || defined(_HPUX) */
89 
90 /* HP-UX doesn't define RTLD_DEFAULT. */
91 #if defined(_HPUX) && !defined(RTLD_DEFAULT)
92 #define RTLD_DEFAULT NULL
93 #endif
94 
95 #define X11_MOUSE_EVENT_MASK (ButtonPressMask | ButtonReleaseMask | PointerMotionMask | EnterWindowMask | LeaveWindowMask)
96 
97 static const char * const ClazzNameBuffers = "com/jogamp/common/nio/Buffers";
98 static const char * const ClazzNameBuffersStaticCstrName = "copyByteBuffer";
99 static const char * const ClazzNameBuffersStaticCstrSignature = "(Ljava/nio/ByteBuffer;)Ljava/nio/ByteBuffer;";
100 static const char * const ClazzNameByteBuffer = "java/nio/ByteBuffer";
101 static const char * const ClazzNamePoint = "com/jogamp/nativewindow/util/Point";
102 static const char * const ClazzAnyCstrName = "<init>";
103 static const char * const ClazzNamePointCstrSignature = "(II)V";
104 static jclass X11UtilClazz = NULL;
105 static jmethodID getCurrentThreadNameID = NULL;
106 static jmethodID dumpStackID = NULL;
107 static jclass clazzBuffers = NULL;
108 static jmethodID cstrBuffers = NULL;
109 static jclass clazzByteBuffer = NULL;
110 static jclass pointClz = NULL;
111 static jmethodID pointCstr = NULL;
112 
_initClazzAccess(JNIEnv * env)113 static void _initClazzAccess(JNIEnv *env) {
114     jclass c;
115 
116     if( NativewindowCommon_init(env) ) {
117         getCurrentThreadNameID = (*env)->GetStaticMethodID(env, X11UtilClazz, "getCurrentThreadName", "()Ljava/lang/String;");
118         if(NULL==getCurrentThreadNameID) {
119             NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't get method getCurrentThreadName");
120         }
121         dumpStackID = (*env)->GetStaticMethodID(env, X11UtilClazz, "dumpStack", "()V");
122         if(NULL==dumpStackID) {
123             NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't get method dumpStack");
124         }
125 
126         c = (*env)->FindClass(env, ClazzNameBuffers);
127         if(NULL==c) {
128             NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't find %s", ClazzNameBuffers);
129         }
130         clazzBuffers = (jclass)(*env)->NewGlobalRef(env, c);
131         (*env)->DeleteLocalRef(env, c);
132         if(NULL==clazzBuffers) {
133             NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't use %s", ClazzNameBuffers);
134         }
135         c = (*env)->FindClass(env, ClazzNameByteBuffer);
136         if(NULL==c) {
137             NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't find %s", ClazzNameByteBuffer);
138         }
139         clazzByteBuffer = (jclass)(*env)->NewGlobalRef(env, c);
140         (*env)->DeleteLocalRef(env, c);
141         if(NULL==c) {
142             NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't use %s", ClazzNameByteBuffer);
143         }
144 
145         cstrBuffers = (*env)->GetStaticMethodID(env, clazzBuffers,
146                                 ClazzNameBuffersStaticCstrName, ClazzNameBuffersStaticCstrSignature);
147         if(NULL==cstrBuffers) {
148             NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't create %s.%s %s",
149                 ClazzNameBuffers, ClazzNameBuffersStaticCstrName, ClazzNameBuffersStaticCstrSignature);
150         }
151 
152         c = (*env)->FindClass(env, ClazzNamePoint);
153         if(NULL==c) {
154             NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't find %s", ClazzNamePoint);
155         }
156         pointClz = (jclass)(*env)->NewGlobalRef(env, c);
157         (*env)->DeleteLocalRef(env, c);
158         if(NULL==pointClz) {
159             NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't use %s", ClazzNamePoint);
160         }
161         pointCstr = (*env)->GetMethodID(env, pointClz, ClazzAnyCstrName, ClazzNamePointCstrSignature);
162         if(NULL==pointCstr) {
163             NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't fetch %s.%s %s",
164                 ClazzNamePoint, ClazzAnyCstrName, ClazzNamePointCstrSignature);
165         }
166     }
167 }
168 
169 static XErrorHandler origErrorHandler = NULL ;
170 static int errorHandlerQuiet = 1 ;
171 static int errorHandlerDebug = 0 ;
172 static int errorHandlerThrowException = 0;
173 
x11ErrorHandler(Display * dpy,XErrorEvent * e)174 static int x11ErrorHandler(Display *dpy, XErrorEvent *e)
175 {
176     if( !errorHandlerQuiet || errorHandlerDebug ) {
177         const char * errnoStr = strerror(errno);
178         char errCodeStr[80];
179         char reqCodeStr[80];
180         int shallBeDetached = 0;
181         JNIEnv *jniEnv = NULL;
182 
183         snprintf(errCodeStr, sizeof(errCodeStr), "%d", e->request_code);
184         XGetErrorDatabaseText(dpy, "XRequest", errCodeStr, "Unknown", reqCodeStr, sizeof(reqCodeStr));
185         XGetErrorText(dpy, e->error_code, errCodeStr, sizeof(errCodeStr));
186 
187         fprintf(stderr, "Info: Nativewindow X11 Error: %d - %s, dpy %p, id %x, # %d: %d:%d %s\n",
188             e->error_code, errCodeStr, e->display, (int)e->resourceid, (int)e->serial,
189             (int)e->request_code, (int)e->minor_code, reqCodeStr);
190         fflush(stderr);
191 
192         if( errorHandlerDebug || errorHandlerThrowException ) {
193             jniEnv = NativewindowCommon_GetJNIEnv(0 /* asDaemon */, &shallBeDetached);
194             if(NULL == jniEnv) {
195                 fprintf(stderr, "Nativewindow X11 Error: null JNIEnv");
196                 fflush(stderr);
197             }
198         }
199 
200         if( NULL != jniEnv ) {
201             if( errorHandlerDebug ) {
202                 (*jniEnv)->CallStaticVoidMethod(jniEnv, X11UtilClazz, dumpStackID);
203             }
204 
205             if(errorHandlerThrowException) {
206                 NativewindowCommon_throwNewRuntimeException(jniEnv, "Nativewindow X11 Error: %d - %s, dpy %p, id %x, # %d: %d:%d %s\n",
207                                                             e->error_code, errCodeStr, e->display, (int)e->resourceid, (int)e->serial,
208                                                             (int)e->request_code, (int)e->minor_code, reqCodeStr);
209             }
210             NativewindowCommon_ReleaseJNIEnv(shallBeDetached);
211         }
212     }
213 
214     return 0;
215 }
216 
NativewindowCommon_x11ErrorHandlerEnable(JNIEnv * env,Display * dpy,int force,int onoff,int quiet,int sync)217 static void NativewindowCommon_x11ErrorHandlerEnable(JNIEnv * env, Display *dpy, int force, int onoff, int quiet, int sync) {
218     errorHandlerQuiet = quiet;
219     if(onoff) {
220         if(force || NULL==origErrorHandler) {
221             XErrorHandler prevErrorHandler;
222             prevErrorHandler = XSetErrorHandler(x11ErrorHandler);
223             if(x11ErrorHandler != prevErrorHandler) { // if forced don't overwrite w/ orig w/ our handler
224                 origErrorHandler = prevErrorHandler;
225             }
226             if(sync && NULL!=dpy) {
227                 XSync(dpy, False);
228             }
229         }
230     } else {
231         if(NULL!=origErrorHandler) {
232             if(sync && NULL!=dpy) {
233                 XSync(dpy, False);
234             }
235             XSetErrorHandler(origErrorHandler);
236             origErrorHandler = NULL;
237         }
238     }
239 }
240 
241 static XIOErrorHandler origIOErrorHandler = NULL;
242 
x11IOErrorHandler(Display * dpy)243 static int x11IOErrorHandler(Display *dpy)
244 {
245     const char * dpyName = XDisplayName(NULL);
246     const char * errnoStr = strerror(errno);
247     int shallBeDetached = 0;
248     JNIEnv *jniEnv = NULL;
249 
250     fprintf(stderr, "Nativewindow X11 IOError: Display %p (%s): %s\n", dpy, dpyName, errnoStr);
251     fflush(stderr);
252 
253     jniEnv = NativewindowCommon_GetJNIEnv(0 /* asDaemon */, &shallBeDetached);
254     if (NULL != jniEnv) {
255         NativewindowCommon_FatalError(jniEnv, "Nativewindow X11 IOError: Display %p (%s): %s", dpy, dpyName, errnoStr);
256         NativewindowCommon_ReleaseJNIEnv(shallBeDetached);
257     }
258     if(NULL!=origIOErrorHandler) {
259         origIOErrorHandler(dpy);
260     }
261     return 0;
262 }
263 
x11IOErrorHandlerEnable(int onoff,JNIEnv * env)264 static void x11IOErrorHandlerEnable(int onoff, JNIEnv * env) {
265     if(onoff) {
266         if(NULL==origIOErrorHandler) {
267             origIOErrorHandler = XSetIOErrorHandler(x11IOErrorHandler);
268         }
269     } else {
270         XSetIOErrorHandler(origIOErrorHandler);
271         origIOErrorHandler = NULL;
272     }
273 }
274 
275 static int _initialized = 0;
276 
277 JNIEXPORT jboolean JNICALL
Java_jogamp_nativewindow_x11_X11Util_initialize0(JNIEnv * env,jclass clazz,jboolean debug)278 Java_jogamp_nativewindow_x11_X11Util_initialize0(JNIEnv *env, jclass clazz, jboolean debug) {
279     if( 0 == _initialized ) {
280         if(debug) {
281             errorHandlerDebug = 1;
282         }
283         X11UtilClazz = (jclass)(*env)->NewGlobalRef(env, clazz);
284 
285         _initClazzAccess(env);
286         x11IOErrorHandlerEnable(1, env);
287         NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 1, 1, debug ? 0 : 1, 0 /* no dpy, force, no sync */);
288         _initialized=1;
289         if(JNI_TRUE == debug) {
290             fprintf(stderr, "Info: NativeWindow native init passed\n");
291         }
292     }
293     return JNI_TRUE;
294 }
295 
296 JNIEXPORT void JNICALL
Java_jogamp_nativewindow_x11_X11Util_shutdown0(JNIEnv * env,jclass _unused)297 Java_jogamp_nativewindow_x11_X11Util_shutdown0(JNIEnv *env, jclass _unused) {
298     NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 0, 0, errorHandlerQuiet, 0 /* no dpy, no sync */);
299     x11IOErrorHandlerEnable(0, env);
300 }
301 
302 JNIEXPORT void JNICALL
Java_jogamp_nativewindow_x11_X11Util_setX11ErrorHandler0(JNIEnv * env,jclass _unused,jboolean onoff,jboolean quiet)303 Java_jogamp_nativewindow_x11_X11Util_setX11ErrorHandler0(JNIEnv *env, jclass _unused, jboolean onoff, jboolean quiet) {
304     NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 1, onoff ? 1 : 0, quiet ? 1 : 0, 0 /* no dpy, force, no sync */);
305 }
306 
307 /*   Java->C glue code:
308  *   Java package: jogamp.nativewindow.x11.X11Lib
309  *    Java method: boolean XRenderFindVisualFormat(long dpy, long visual, XRenderPictFormat dest)
310  */
311 JNIEXPORT jboolean JNICALL
Java_jogamp_nativewindow_x11_X11Lib_XRenderFindVisualFormat1(JNIEnv * env,jclass _unused,jlong dpy,jlong visual,jobject xRenderPictFormat)312 Java_jogamp_nativewindow_x11_X11Lib_XRenderFindVisualFormat1(JNIEnv *env, jclass _unused, jlong dpy, jlong visual, jobject xRenderPictFormat) {
313   XRenderPictFormat * dest = (XRenderPictFormat *) (*env)->GetDirectBufferAddress(env, xRenderPictFormat);
314   XRenderPictFormat * src = XRenderFindVisualFormat((Display *) (intptr_t) dpy, (Visual *) (intptr_t) visual);
315   if (NULL == src) return JNI_FALSE;
316   memcpy(dest, src, sizeof(XRenderPictFormat));
317   return JNI_TRUE;
318 }
319 
320 /*   Java->C glue code:
321  *   Java package: jogamp.nativewindow.x11.X11Lib
322  *    Java method: XVisualInfo XGetVisualInfo(long arg0, long arg1, XVisualInfo arg2, java.nio.IntBuffer arg3)
323  *     C function: XVisualInfo *  XGetVisualInfo(Display * , long, XVisualInfo * , int * );
324  */
325 JNIEXPORT jobject JNICALL
Java_jogamp_nativewindow_x11_X11Lib_XGetVisualInfo1__JJLjava_nio_ByteBuffer_2Ljava_lang_Object_2I(JNIEnv * env,jclass _unused,jlong arg0,jlong arg1,jobject arg2,jobject arg3,jint arg3_byte_offset)326 Java_jogamp_nativewindow_x11_X11Lib_XGetVisualInfo1__JJLjava_nio_ByteBuffer_2Ljava_lang_Object_2I(JNIEnv *env, jclass _unused, jlong arg0, jlong arg1, jobject arg2, jobject arg3, jint arg3_byte_offset) {
327   XVisualInfo * _ptr2 = NULL;
328   int * _ptr3 = NULL;
329   XVisualInfo *  _res = NULL;
330   int count = 0;
331   jobject jbyteSource = NULL;
332   jobject jbyteCopy = NULL;
333   if( 0 == arg0 || 0 == arg2 || 0 == arg3 ) {
334     NativewindowCommon_FatalError(env, "invalid display connection, vinfo_template or nitems_return");
335     return NULL;
336   }
337   _ptr2 = (XVisualInfo *) (((char*) (*env)->GetDirectBufferAddress(env, arg2)) + 0);
338   if( NULL != _ptr2 ) {
339       _ptr3 = (int *) (((char*) (*env)->GetPrimitiveArrayCritical(env, arg3, NULL)) + arg3_byte_offset);
340       if( NULL != _ptr3 ) {
341           NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) arg0, 0, 1, errorHandlerQuiet, 0);
342           _res = XGetVisualInfo((Display *) (intptr_t) arg0, (long) arg1, (XVisualInfo *) _ptr2, (int *) _ptr3);
343           // NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) arg0, 0, 0, errorHandlerQuiet, 0);
344           count = _ptr3[0];
345           (*env)->ReleasePrimitiveArrayCritical(env, arg3, _ptr3, 0);
346       }
347   }
348   if (_res == NULL) return NULL;
349 
350   jbyteSource = (*env)->NewDirectByteBuffer(env, _res, count * sizeof(XVisualInfo));
351   jbyteCopy   = (*env)->CallStaticObjectMethod(env, clazzBuffers, cstrBuffers, jbyteSource);
352   (*env)->DeleteLocalRef(env, jbyteSource);
353 
354   XFree(_res);
355 
356   return jbyteCopy;
357 }
358 
359 JNIEXPORT jint JNICALL
Java_jogamp_nativewindow_x11_X11Lib_GetVisualIDFromWindow(JNIEnv * env,jclass _unused,jlong display,jlong window)360 Java_jogamp_nativewindow_x11_X11Lib_GetVisualIDFromWindow(JNIEnv *env, jclass _unused, jlong display, jlong window) {
361     Display * dpy = (Display *)(intptr_t)display;
362     Window      w = (Window) window;
363     XWindowAttributes xwa;
364     jlong r = 0; // undefinded
365 
366     if(NULL==dpy) {
367         NativewindowCommon_throwNewRuntimeException(env, "invalid display connection..");
368         return 0;
369     }
370 
371     NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 1, errorHandlerQuiet, 1);
372     memset(&xwa, 0, sizeof(XWindowAttributes));
373     XGetWindowAttributes(dpy, w, &xwa);
374     if(NULL != xwa.visual) {
375         r = (jint) XVisualIDFromVisual( xwa.visual );
376     } else {
377         r = 0;
378     }
379     // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, errorHandlerQuiet, 1);
380 
381     return r;
382 }
383 
384 
385 JNIEXPORT jint JNICALL
Java_jogamp_nativewindow_x11_X11Lib_DefaultVisualID(JNIEnv * env,jclass _unused,jlong display,jint screen)386 Java_jogamp_nativewindow_x11_X11Lib_DefaultVisualID(JNIEnv *env, jclass _unused, jlong display, jint screen) {
387   jlong r;
388     if(0==display) {
389         NativewindowCommon_FatalError(env, "invalid display connection..");
390     }
391   NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) display, 0, 1, errorHandlerQuiet, 0);
392   r = (jint) XVisualIDFromVisual( DefaultVisual( (Display*) (intptr_t) display, screen ) );
393   // NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) display, 0, 0, errorHandlerQuiet, 0);
394   return r;
395 }
396 
397 /*   Java->C glue code:
398  *   Java package: jogamp.nativewindow.x11.X11Lib
399  *    Java method: void XLockDisplay(long display)
400  *     C function: void XLockDisplay(Display *  display);
401  */
402 JNIEXPORT void JNICALL
Java_jogamp_nativewindow_x11_X11Lib_XLockDisplay__J(JNIEnv * env,jclass _unused,jlong display)403 Java_jogamp_nativewindow_x11_X11Lib_XLockDisplay__J(JNIEnv *env, jclass _unused, jlong display) {
404   if(0==display) {
405       NativewindowCommon_FatalError(env, "invalid display connection..");
406   }
407   XLockDisplay((Display *) (intptr_t) display);
408 }
409 
410 /*   Java->C glue code:
411  *   Java package: jogamp.nativewindow.x11.X11Lib
412  *    Java method: void XUnlockDisplay(long display)
413  *     C function: void XUnlockDisplay(Display *  display);
414  */
415 JNIEXPORT void JNICALL
Java_jogamp_nativewindow_x11_X11Lib_XUnlockDisplay__J(JNIEnv * env,jclass _unused,jlong display)416 Java_jogamp_nativewindow_x11_X11Lib_XUnlockDisplay__J(JNIEnv *env, jclass _unused, jlong display) {
417   if(0==display) {
418       NativewindowCommon_FatalError(env, "invalid display connection..");
419   }
420   XUnlockDisplay((Display *) (intptr_t) display);
421 }
422 
423 /*   Java->C glue code:
424  *   Java package: jogamp.nativewindow.x11.X11Lib
425  *    Java method: int XCloseDisplay(long display)
426  *     C function: int XCloseDisplay(Display *  display);
427  */
428 JNIEXPORT jint JNICALL
Java_jogamp_nativewindow_x11_X11Lib_XCloseDisplay__J(JNIEnv * env,jclass _unused,jlong display)429 Java_jogamp_nativewindow_x11_X11Lib_XCloseDisplay__J(JNIEnv *env, jclass _unused, jlong display) {
430   int _res;
431   if(0==display) {
432       NativewindowCommon_FatalError(env, "invalid display connection..");
433   }
434   NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 0, 1, errorHandlerQuiet, 0);
435   _res = XCloseDisplay((Display *) (intptr_t) display);
436   // NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 0, 0, errorHandlerQuiet, 0);
437   return _res;
438 }
439 
NativewindowX11_setNormalWindowEWMH(Display * dpy,Window w)440 static void NativewindowX11_setNormalWindowEWMH (Display *dpy, Window w) {
441     Atom _NET_WM_WINDOW_TYPE = XInternAtom( dpy, "_NET_WM_WINDOW_TYPE", False );
442     Atom types[1]={0};
443     types[0] = XInternAtom( dpy, "_NET_WM_WINDOW_TYPE_NORMAL", False );
444     XChangeProperty( dpy, w, _NET_WM_WINDOW_TYPE, XA_ATOM, 32, PropModeReplace, (unsigned char *)&types, 1);
445     XSync(dpy, False);
446 }
447 
448 #define DECOR_USE_MWM 1     // works for known WMs
449 // #define DECOR_USE_EWMH 1 // haven't seen this to work (NORMAL->POPUP, never gets undecorated)
450 
451 /* see <http://tonyobryan.com/index.php?article=9> */
452 #define MWM_HINTS_DECORATIONS   (1L << 1)
453 #define PROP_MWM_HINTS_ELEMENTS 5
454 
NativewindowX11_setDecorations(Display * dpy,Window w,Bool decorated)455 static void NativewindowX11_setDecorations (Display *dpy, Window w, Bool decorated) {
456 
457 #ifdef DECOR_USE_MWM
458     unsigned long mwmhints[PROP_MWM_HINTS_ELEMENTS] = { MWM_HINTS_DECORATIONS, 0, decorated, 0, 0 }; // flags, functions, decorations, input_mode, status
459     Atom _MOTIF_WM_HINTS = XInternAtom( dpy, "_MOTIF_WM_HINTS", False );
460 #endif
461 
462 #ifdef DECOR_USE_EWMH
463     Atom _NET_WM_WINDOW_TYPE = XInternAtom( dpy, "_NET_WM_WINDOW_TYPE", False );
464     Atom types[3]={0};
465     int ntypes=0;
466     if(True==decorated) {
467         types[ntypes++] = XInternAtom( dpy, "_NET_WM_WINDOW_TYPE_NORMAL", False );
468     } else {
469         types[ntypes++] = XInternAtom( dpy, "_NET_WM_WINDOW_TYPE_POPUP_MENU", False );
470     }
471 #endif
472 
473 #ifdef DECOR_USE_MWM
474     XChangeProperty( dpy, w, _MOTIF_WM_HINTS, _MOTIF_WM_HINTS, 32, PropModeReplace, (unsigned char *)&mwmhints, PROP_MWM_HINTS_ELEMENTS);
475 #endif
476 
477 #ifdef DECOR_USE_EWMH
478     XChangeProperty( dpy, w, _NET_WM_WINDOW_TYPE, XA_ATOM, 32, PropModeReplace, (unsigned char *)&types, ntypes);
479 #endif
480 
481     XSync(dpy, False);
482 }
483 
484 /*
485  * Class:     jogamp_nativewindow_x11_X11Lib
486  * Method:    CreateWindow
487  * Signature: (JJIIIIZZ)J
488  */
Java_jogamp_nativewindow_x11_X11Lib_CreateWindow(JNIEnv * env,jclass unused,jlong parent,jlong display,jint screen_index,jint visualID,jint width,jint height,jboolean input,jboolean visible)489 JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_x11_X11Lib_CreateWindow
490   (JNIEnv *env, jclass unused, jlong parent, jlong display, jint screen_index, jint visualID, jint width, jint height, jboolean input, jboolean visible)
491 {
492     Display * dpy  = (Display *)(intptr_t)display;
493     int       scrn_idx = (int)screen_index;
494     Window root = RootWindow(dpy, scrn_idx);
495     Window  windowParent = (Window) parent;
496     Window  window = 0;
497 
498     XVisualInfo visualTemplate;
499     XVisualInfo *pVisualQuery = NULL;
500     Visual *visual = NULL;
501     int depth;
502 
503     XSetWindowAttributes xswa;
504     unsigned long attrMask;
505     int n;
506 
507     Screen* scrn;
508 
509     if(NULL==dpy) {
510         NativewindowCommon_FatalError(env, "invalid display connection..");
511         return 0;
512     }
513 
514     if(visualID<0) {
515         NativewindowCommon_throwNewRuntimeException(env, "invalid VisualID ..");
516         return 0;
517     }
518 
519     NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 1, errorHandlerQuiet, 0);
520 
521     scrn = ScreenOfDisplay(dpy, scrn_idx);
522     if(0==windowParent) {
523         windowParent = root;
524     }
525 
526     // try given VisualID on screen
527     memset(&visualTemplate, 0, sizeof(XVisualInfo));
528     visualTemplate.screen = scrn_idx;
529     visualTemplate.visualid = (VisualID)visualID;
530     pVisualQuery = XGetVisualInfo(dpy, VisualIDMask|VisualScreenMask, &visualTemplate,&n);
531     if(pVisualQuery!=NULL) {
532         visual   = pVisualQuery->visual;
533         depth    = pVisualQuery->depth;
534         visualID = (jint)pVisualQuery->visualid;
535         XFree(pVisualQuery);
536         pVisualQuery=NULL;
537     }
538     DBG_PRINT( "X11: [CreateWindow] trying given (dpy %p, screen %d, visualID: %d, parent %p) found: %p\n", dpy, scrn_idx, (int)visualID, windowParent, visual);
539 
540     if (visual==NULL)
541     {
542         // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, errorHandlerQuiet, 1);
543         NativewindowCommon_throwNewRuntimeException(env, "could not query Visual by given VisualID, bail out!");
544         return 0;
545     }
546 
547     if(pVisualQuery!=NULL) {
548         XFree(pVisualQuery);
549         pVisualQuery=NULL;
550     }
551 
552 
553     attrMask  = ( CWBackingStore | CWBackingPlanes | CWBackingPixel | CWBackPixmap |
554                   CWBorderPixel | CWColormap | CWOverrideRedirect ) ;
555 
556     memset(&xswa, 0, sizeof(xswa));
557     xswa.override_redirect = False; // use the window manager, always
558     xswa.border_pixel = 0;
559     xswa.background_pixmap = None;
560     xswa.backing_store=NotUseful; /* NotUseful, WhenMapped, Always */
561     xswa.backing_planes=0;        /* planes to be preserved if possible */
562     xswa.backing_pixel=0;         /* value to use in restoring planes */
563     if( input ) {
564         xswa.event_mask  = X11_MOUSE_EVENT_MASK;
565         xswa.event_mask |= KeyPressMask | KeyReleaseMask ;
566     }
567     if( visible ) {
568         xswa.event_mask |= FocusChangeMask | SubstructureNotifyMask | StructureNotifyMask | ExposureMask ;
569     }
570 
571     xswa.colormap = XCreateColormap(dpy,
572                                     windowParent,
573                                     visual,
574                                     AllocNone);
575 
576     window = XCreateWindow(dpy,
577                            windowParent,
578                            0, 0, // only a hint, WM most likely will override
579                            width, height,
580                            0, // border width
581                            depth,
582                            InputOutput,
583                            visual,
584                            attrMask,
585                            &xswa);
586     if(0==window) {
587         NativewindowCommon_throwNewRuntimeException(env, "could not create Window, bail out!");
588         return 0;
589     }
590 
591     NativewindowX11_setNormalWindowEWMH(dpy, window);
592     NativewindowX11_setDecorations(dpy, window, False);
593 
594     if( visible ) {
595         XEvent event;
596 
597         XMapWindow(dpy, window);
598     }
599 
600     XSync(dpy, False);
601 
602     if( !input ) {
603         XSelectInput(dpy, window, 0); // no events
604     }
605 
606     // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, errorHandlerQuiet, 1);
607 
608     DBG_PRINT( "X11: [CreateWindow] created window %p on display %p\n", window, dpy);
609 
610     return (jlong) window;
611 }
612 
613 
614 /*
615  * Class:     jogamp_nativewindow_x11_X11Lib
616  * Method:    DestroyWindow
617  * Signature: (JJ)V
618  */
Java_jogamp_nativewindow_x11_X11Lib_DestroyWindow(JNIEnv * env,jclass unused,jlong display,jlong window)619 JNIEXPORT void JNICALL Java_jogamp_nativewindow_x11_X11Lib_DestroyWindow
620   (JNIEnv *env, jclass unused, jlong display, jlong window)
621 {
622     Display * dpy = (Display *)(intptr_t)display;
623     Window      w = (Window) window;
624     XWindowAttributes xwa;
625 
626     if(NULL==dpy) {
627         NativewindowCommon_throwNewRuntimeException(env, "invalid display connection..");
628         return;
629     }
630 
631     NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 1, errorHandlerQuiet, 0);
632     XSync(dpy, False);
633     memset(&xwa, 0, sizeof(XWindowAttributes));
634     XGetWindowAttributes(dpy, w, &xwa); // prefetch colormap to be destroyed after window destruction
635     XSelectInput(dpy, w, 0);
636     XUnmapWindow(dpy, w);
637     XSync(dpy, False);
638     XDestroyWindow(dpy, w);
639     if( None != xwa.colormap ) {
640         XFreeColormap(dpy, xwa.colormap);
641     }
642     // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, errorHandlerQuiet, 1);
643 }
644 
Java_jogamp_nativewindow_x11_X11Lib_SetWindowPosSize(JNIEnv * env,jclass unused,jlong display,jlong window,jint x,jint y,jint width,jint height)645 JNIEXPORT void JNICALL Java_jogamp_nativewindow_x11_X11Lib_SetWindowPosSize
646   (JNIEnv *env, jclass unused, jlong display, jlong window, jint x, jint y, jint width, jint height) {
647     Display * dpy = (Display *)(intptr_t)display;
648     Window      w = (Window) window;
649     XWindowChanges xwc;
650     int flags = 0;
651 
652     memset(&xwc, 0, sizeof(XWindowChanges));
653 
654     if(0<=x && 0<=y) {
655         flags |= CWX | CWY;
656         xwc.x=x;
657         xwc.y=y;
658     }
659 
660     if(0<width && 0<height) {
661         flags |= CWWidth | CWHeight;
662         xwc.width=width;
663         xwc.height=height;
664     }
665     XConfigureWindow(dpy, w, flags, &xwc);
666     XSync(dpy, False);
667 }
668 
669 /*
670  * Class:     jogamp_nativewindow_x11_X11Lib
671  * Method:    GetRelativeLocation
672  * Signature: (JIJJII)Lcom/jogamp/nativewindow/util/Point;
673  */
Java_jogamp_nativewindow_x11_X11Lib_GetRelativeLocation0(JNIEnv * env,jclass unused,jlong jdisplay,jint screen_index,jlong jsrc_win,jlong jdest_win,jint src_x,jint src_y)674 JNIEXPORT jobject JNICALL Java_jogamp_nativewindow_x11_X11Lib_GetRelativeLocation0
675   (JNIEnv *env, jclass unused, jlong jdisplay, jint screen_index, jlong jsrc_win, jlong jdest_win, jint src_x, jint src_y)
676 {
677     Display * dpy = (Display *) (intptr_t) jdisplay;
678     Screen * scrn = ScreenOfDisplay(dpy, (int)screen_index);
679     Window root = XRootWindowOfScreen(scrn);
680     Window src_win = (Window)jsrc_win;
681     Window dest_win = (Window)jdest_win;
682     int dest_x=-1;
683     int dest_y=-1;
684     Window child;
685     Bool res;
686 
687     if( 0 == jdest_win ) { dest_win = root; }
688     if( 0 == jsrc_win ) { src_win = root; }
689 
690     NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 1, errorHandlerQuiet, 0);
691 
692     res = XTranslateCoordinates(dpy, src_win, dest_win, src_x, src_y, &dest_x, &dest_y, &child);
693 
694     // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, errorHandlerQuiet, 0);
695 
696     DBG_PRINT( "X11: GetRelativeLocation0: %p %d/%d -> %p %d/%d - ok: %d\n",
697         (void*)src_win, src_x, src_y, (void*)dest_win, dest_x, dest_y, (int)res);
698 
699     return (*env)->NewObject(env, pointClz, pointCstr, (jint)dest_x, (jint)dest_y);
700 }
701 
702 /*
703  * Class:     jogamp_nativewindow_x11_X11Lib
704  * Method:    QueryExtension0
705  * Signature: (JLjava/lang/String;)Z
706  */
Java_jogamp_nativewindow_x11_X11Lib_QueryExtension0(JNIEnv * env,jclass unused,jlong jdisplay,jstring jextensionName)707 JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_x11_X11Lib_QueryExtension0
708   (JNIEnv *env, jclass unused, jlong jdisplay, jstring jextensionName)
709 {
710     int32_t major_opcode, first_event, first_error;
711     jboolean res = JNI_FALSE;
712     Display * display = (Display *) (intptr_t) jdisplay;
713     const char* extensionName = NULL;
714 
715     if(NULL==display) {
716         NativewindowCommon_throwNewRuntimeException(env, "NULL argument \"display\"");
717         return res;
718     }
719     if ( NULL == jextensionName ) {
720         NativewindowCommon_throwNewRuntimeException(env, "NULL argument \"extensionName\"");
721         return res;
722     }
723     extensionName = (*env)->GetStringUTFChars(env, jextensionName, (jboolean*)NULL);
724     if ( NULL == extensionName ) {
725         NativewindowCommon_throwNewRuntimeException(env, "Failed to get UTF-8 chars for argument \"extensionName\"");
726         return res;
727     }
728 
729     res = True == XQueryExtension(display, extensionName, &major_opcode, &first_event, &first_error) ? JNI_TRUE : JNI_FALSE;
730 
731     if ( NULL != jextensionName ) {
732         (*env)->ReleaseStringUTFChars(env, jextensionName, extensionName);
733     }
734     return res;
735 }
736 
737