Jogamp
moved com.jogamp.javafx.* to com.jogamp.*.
[jogl.git] / src / newt / native / X11Window.c
1 /*
2  * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
3  * 
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  * 
8  * - Redistribution of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  * 
11  * - Redistribution in binary form must reproduce the above copyright
12  *   notice, this list of conditions and the following disclaimer in the
13  *   documentation and/or other materials provided with the distribution.
14  * 
15  * Neither the name of Sun Microsystems, Inc. or the names of
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  * 
19  * This software is provided "AS IS," without a warranty of any kind. ALL
20  * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
21  * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
22  * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
23  * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
24  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
25  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
26  * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
27  * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
28  * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
29  * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
30  * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
31  * 
32  */
33
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <stdarg.h>
38 // Building on obsolete platform on SPARC right now
39 #ifdef __sparc
40   #include <inttypes.h>
41 #else
42   #include <stdint.h>
43 #endif
44 #include <unistd.h>
45 #include <X11/Xlib.h>
46 #include <X11/Xutil.h>
47 #include <X11/keysym.h>
48
49 #include "com_jogamp_newt_x11_X11Window.h"
50
51 #include "EventListener.h"
52 #include "MouseEvent.h"
53 #include "KeyEvent.h"
54 #include "WindowEvent.h"
55
56 // #define VERBOSE_ON 1
57
58 #ifdef VERBOSE_ON
59     // Workaround for ancient compiler on Solaris/SPARC
60     // #define DBG_PRINT(args...) fprintf(stderr, args);
61     #define DBG_PRINT0(str) fprintf(stderr, str);
62     #define DBG_PRINT1(str, arg1) fprintf(stderr, str, arg1);
63     #define DBG_PRINT2(str, arg1, arg2) fprintf(stderr, str, arg1, arg2);
64     #define DBG_PRINT3(str, arg1, arg2, arg3) fprintf(stderr, str, arg1, arg2, arg3);
65     #define DBG_PRINT4(str, arg1, arg2, arg3, arg4) fprintf(stderr, str, arg1, arg2, arg3, arg4);
66     #define DBG_PRINT5(str, arg1, arg2, arg3, arg4, arg5) fprintf(stderr, str, arg1, arg2, arg3, arg4, arg5);
67     #define DBG_PRINT6(str, arg1, arg2, arg3, arg4, arg5, arg6) fprintf(stderr, str, arg1, arg2, arg3, arg4, arg5, arg6);
68     #define DBG_PRINT7(str, arg1, arg2, arg3, arg4, arg5, arg6, arg7) fprintf(stderr, str, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
69     #define DBG_PRINT8(str, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) fprintf(stderr, str, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
70
71     #define DUMP_VISUAL_INFO(a,b) _dumpVisualInfo((a),(b))
72
73     static void _dumpVisualInfo(const char * msg, XVisualInfo *pVisualQuery) {
74         if(pVisualQuery!=NULL) {
75             fprintf(stderr, "%s: screen %d, visual: %p, visual-id: 0x%X, depth: %d, class %d, cmap sz: %d, bpp: 3x%d, rgb 0x%X 0x%X 0x%X\n",
76                 msg,
77                 pVisualQuery->screen,
78                 pVisualQuery->visual,
79                 (int)pVisualQuery->visualid,
80                 pVisualQuery->depth,
81                 pVisualQuery->class,
82                 pVisualQuery->colormap_size,
83                 pVisualQuery->bits_per_rgb,
84                 (int)pVisualQuery->red_mask,
85                 (int)pVisualQuery->green_mask,
86                 (int)pVisualQuery->blue_mask
87             );
88         } else {
89             fprintf(stderr, "%s: NULL XVisualInfo\n", msg);
90         }
91     }
92
93 #else
94
95     // Workaround for ancient compiler on Solaris/SPARC
96     // #define DBG_PRINT(args...)
97     #define DBG_PRINT0(str)
98     #define DBG_PRINT1(str, arg1)
99     #define DBG_PRINT2(str, arg1, arg2)
100     #define DBG_PRINT3(str, arg1, arg2, arg3)
101     #define DBG_PRINT4(str, arg1, arg2, arg3, arg4)
102     #define DBG_PRINT5(str, arg1, arg2, arg3, arg4, arg5)
103     #define DBG_PRINT6(str, arg1, arg2, arg3, arg4, arg5, arg6)
104     #define DBG_PRINT7(str, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
105     #define DBG_PRINT8(str, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
106
107     #define DUMP_VISUAL_INFO(a,b)
108
109 #endif
110
111 /**
112  * Keycode
113  */
114
115 #define IS_WITHIN(k,a,b) ((a)<=(k)&&(k)<=(b))
116
117 static jint X11KeySym2NewtVKey(KeySym keySym) {
118     if(IS_WITHIN(keySym,XK_F1,XK_F12)) 
119         return (keySym-XK_F1)+J_VK_F1;
120
121     switch(keySym) {
122         case XK_Alt_L:
123         case XK_Alt_R:
124             return J_VK_ALT;
125
126         case XK_Left:
127             return J_VK_LEFT;
128         case XK_Right:
129             return J_VK_RIGHT;
130         case XK_Up:
131             return J_VK_UP;
132         case XK_Down:
133             return J_VK_DOWN;
134         case XK_Page_Up:
135             return J_VK_PAGE_UP;
136         case XK_Page_Down:
137             return J_VK_PAGE_DOWN;
138         case XK_Shift_L:
139         case XK_Shift_R:
140             return J_VK_SHIFT;
141         case XK_Control_L:
142         case XK_Control_R:
143             return J_VK_CONTROL;
144         case XK_Escape:
145             return J_VK_ESCAPE;
146         case XK_Delete:
147             return J_VK_DELETE;
148     }
149     return keySym;
150 }
151
152 static const char * const ClazzNameRuntimeException = 
153                             "java/lang/RuntimeException";
154 static jclass    runtimeExceptionClz=NULL;
155
156 static const char * const ClazzNameNewtWindow = 
157                             "com/jogamp/newt/Window";
158 static jclass    newtWindowClz=NULL;
159
160 static jmethodID windowChangedID = NULL;
161 static jmethodID windowDestroyNotifyID = NULL;
162 static jmethodID windowDestroyedID = NULL;
163 static jmethodID windowCreatedID = NULL;
164 static jmethodID sendMouseEventID = NULL;
165 static jmethodID sendKeyEventID = NULL;
166
167 static jmethodID displayCompletedID = NULL;
168
169 static void _throwNewRuntimeException(Display * unlockDisplay, JNIEnv *env, const char* msg, ...)
170 {
171     char buffer[512];
172     va_list ap;
173
174     if(NULL!=unlockDisplay) {
175         XUnlockDisplay(unlockDisplay);
176     }
177
178     va_start(ap, msg);
179     vsnprintf(buffer, sizeof(buffer), msg, ap);
180     va_end(ap);
181
182     (*env)->ThrowNew(env, runtimeExceptionClz, buffer);
183 }
184
185 /**
186  * Display
187  */
188
189 /*
190  * Class:     com_jogamp_newt_x11_X11Display
191  * Method:    initIDs
192  * Signature: ()Z
193  */
194 JNIEXPORT jboolean JNICALL Java_com_jogamp_newt_x11_X11Display_initIDs
195   (JNIEnv *env, jclass clazz)
196 {
197     jclass c;
198
199     if( 0 == XInitThreads() ) {
200         fprintf(stderr, "Warning: XInitThreads() failed\n");
201     }
202
203     displayCompletedID = (*env)->GetMethodID(env, clazz, "displayCompleted", "(JJ)V");
204     if (displayCompletedID == NULL) {
205         return JNI_FALSE;
206     }
207
208     if(NULL==newtWindowClz) {
209         c = (*env)->FindClass(env, ClazzNameNewtWindow);
210         if(NULL==c) {
211             fprintf(stderr, "FatalError: NEWT X11Window: can't find %s\n", ClazzNameNewtWindow);
212             return JNI_FALSE;
213         }
214         newtWindowClz = (jclass)(*env)->NewGlobalRef(env, c);
215         (*env)->DeleteLocalRef(env, c);
216         if(NULL==newtWindowClz) {
217             fprintf(stderr, "FatalError: NEWT X11Window: can't use %s\n", ClazzNameNewtWindow);
218             return JNI_FALSE;
219         }
220     }
221
222     if(NULL==runtimeExceptionClz) {
223         c = (*env)->FindClass(env, ClazzNameRuntimeException);
224         if(NULL==c) {
225             fprintf(stderr, "FatalError: NEWT X11Window: can't find %s\n", ClazzNameRuntimeException);
226             return JNI_FALSE;
227         }
228         runtimeExceptionClz = (jclass)(*env)->NewGlobalRef(env, c);
229         (*env)->DeleteLocalRef(env, c);
230         if(NULL==runtimeExceptionClz) {
231             fprintf(stderr, "FatalError: NEWT X11Window: can't use %s\n", ClazzNameRuntimeException);
232             return JNI_FALSE;
233         }
234     }
235
236     return JNI_TRUE;
237 }
238
239 /*
240  * Class:     com_jogamp_newt_x11_X11Display
241  * Method:    LockDisplay
242  * Signature: (J)V
243  */
244 JNIEXPORT void JNICALL Java_com_jogamp_newt_x11_X11Display_LockDisplay
245   (JNIEnv *env, jobject obj, jlong display)
246 {
247     Display * dpy = (Display *)(intptr_t)display;
248     if(dpy==NULL) {
249         _throwNewRuntimeException(NULL, env, "given display connection is NULL\n");
250     }
251     XLockDisplay(dpy) ;
252 }
253
254
255 /*
256  * Class:     com_jogamp_newt_x11_X11Display
257  * Method:    UnlockDisplay
258  * Signature: (J)V
259  */
260 JNIEXPORT void JNICALL Java_com_jogamp_newt_x11_X11Display_UnlockDisplay
261   (JNIEnv *env, jobject obj, jlong display)
262 {
263     Display * dpy = (Display *)(intptr_t)display;
264     if(dpy==NULL) {
265         _throwNewRuntimeException(NULL, env, "given display connection is NULL\n");
266     }
267     XUnlockDisplay(dpy) ;
268 }
269
270
271 /*
272  * Class:     com_jogamp_newt_x11_X11Display
273  * Method:    CompleteDisplay
274  * Signature: (J)V
275  */
276 JNIEXPORT void JNICALL Java_com_jogamp_newt_x11_X11Display_CompleteDisplay
277   (JNIEnv *env, jobject obj, jlong display)
278 {
279     Display * dpy = (Display *)(intptr_t)display;
280     jlong javaObjectAtom;
281     jlong windowDeleteAtom;
282
283     if(dpy==NULL) {
284         _throwNewRuntimeException(NULL, env, "given display connection is NULL\n");
285     }
286     XLockDisplay(dpy) ;
287
288     javaObjectAtom = (jlong) XInternAtom(dpy, "JOGL_JAVA_OBJECT", False);
289     if(None==javaObjectAtom) {
290         _throwNewRuntimeException(dpy, env, "could not create Atom JOGL_JAVA_OBJECT, bail out!\n");
291         return;
292     }
293
294     windowDeleteAtom = (jlong) XInternAtom(dpy, "WM_DELETE_WINDOW", False);
295     if(None==windowDeleteAtom) {
296         _throwNewRuntimeException(dpy, env, "could not create Atom WM_DELETE_WINDOW, bail out!\n");
297         return;
298     }
299
300     // XSetCloseDownMode(dpy, RetainTemporary); // Just a try ..
301     XUnlockDisplay(dpy) ;
302
303     DBG_PRINT1("X11: X11Display_completeDisplay dpy %p\n", dpy);
304
305     (*env)->CallVoidMethod(env, obj, displayCompletedID, javaObjectAtom, windowDeleteAtom);
306 }
307
308 static int putPtrIn32Long(unsigned long * dst, uintptr_t src) {
309     int i=0;
310         dst[i++] = (unsigned long) ( ( src >>  0 ) & 0xFFFFFFFF ) ;
311     if(sizeof(uintptr_t) == 8) {
312         dst[i++] = (unsigned long) ( ( src >> 32 ) & 0xFFFFFFFF ) ;
313     }
314     return i;
315 }
316
317 static uintptr_t getPtrOut32Long(unsigned long * src) {
318     uintptr_t  res = ( (uintptr_t) ( src[0] & 0xFFFFFFFF ) )  <<  0 ;
319     if(sizeof(uintptr_t) == 8) {
320               res |= ( (uintptr_t) ( src[1] & 0xFFFFFFFF ) )  << 32 ;
321     }
322     return res;
323 }
324
325 static void setJavaWindowProperty(JNIEnv *env, Display *dpy, Window window, jlong javaObjectAtom, jobject jwindow) {
326     unsigned long jogl_java_object_data[2];
327     int nitems_32 = putPtrIn32Long( jogl_java_object_data, (uintptr_t) jwindow);
328
329     {
330         jobject test = (jobject) getPtrOut32Long(jogl_java_object_data);
331         if( ! (jwindow==test) ) {
332             _throwNewRuntimeException(dpy, env, "Internal Error .. Encoded Window ref not the same %p != %p !\n", jwindow, test);
333             return;
334         }
335     }
336
337     XChangeProperty( dpy, window, (Atom)javaObjectAtom, (Atom)javaObjectAtom, 32, PropModeReplace, 
338                                      (unsigned char *)&jogl_java_object_data, nitems_32);
339 }
340
341 static jobject getJavaWindowProperty(JNIEnv *env, Display *dpy, Window window, jlong javaObjectAtom) {
342     Atom actual_type_return;
343     int actual_format_return;
344     int nitems_32 = ( sizeof(uintptr_t) == 8 ) ? 2 : 1 ;
345     unsigned char * jogl_java_object_data_pp = NULL;
346     jobject jwindow;
347
348     {
349         unsigned long nitems_return = 0;
350         unsigned long bytes_after_return = 0;
351         jobject jwindow = NULL;
352         int res;
353
354         res = XGetWindowProperty(dpy, window, (Atom)javaObjectAtom, 0, nitems_32, False, 
355                                  (Atom)javaObjectAtom, &actual_type_return, &actual_format_return, 
356                                  &nitems_return, &bytes_after_return, &jogl_java_object_data_pp);
357
358         if ( Success != res ) {
359             _throwNewRuntimeException(dpy, env, "could not fetch Atom JOGL_JAVA_OBJECT window property (res %d) nitems_return %ld, bytes_after_return %ld, bail out!\n",
360                 res, nitems_return, bytes_after_return);
361             return NULL;
362         }
363
364         if(actual_type_return!=(Atom)javaObjectAtom || nitems_return<nitems_32 || NULL==jogl_java_object_data_pp) {
365             XFree(jogl_java_object_data_pp);
366             _throwNewRuntimeException(dpy, env, "could not fetch Atom JOGL_JAVA_OBJECT window property (res %d) nitems_return %ld, bytes_after_return %ld, actual_type_return %ld, JOGL_JAVA_OBJECT %ld, bail out!\n",
367                 res, nitems_return, bytes_after_return, (long)actual_type_return, javaObjectAtom);
368             return NULL;
369         }
370     }
371
372     jwindow = (jobject) getPtrOut32Long( (unsigned long *) jogl_java_object_data_pp ) ;
373     XFree(jogl_java_object_data_pp);
374
375 #ifdef VERBOSE_ON
376     if(JNI_FALSE == (*env)->IsInstanceOf(env, jwindow, newtWindowClz)) {
377         _throwNewRuntimeException(NULL, env, "fetched Atom JOGL_JAVA_OBJECT window is not a NEWT Window: javaWindow 0x%X !\n", jwindow);
378     }
379 #endif
380     return jwindow;
381 }
382
383 /*
384  * Class:     com_jogamp_newt_x11_X11Display
385  * Method:    DispatchMessages
386  * Signature: (JIJJ)V
387  */
388 JNIEXPORT void JNICALL Java_com_jogamp_newt_x11_X11Display_DispatchMessages
389   (JNIEnv *env, jobject obj, jlong display, jlong javaObjectAtom, jlong wmDeleteAtom)
390 {
391     Display * dpy = (Display *) (intptr_t) display;
392     int num_events = 100;
393
394     if ( NULL == dpy ) {
395         return;
396     }
397
398     // Periodically take a break
399     while( num_events > 0 ) {
400         jobject jwindow = NULL;
401         XEvent evt;
402         KeySym keySym;
403         char keyChar;
404         char text[255];
405
406         XLockDisplay(dpy) ;
407
408         // num_events = XPending(dpy); // XEventsQueued(dpy, QueuedAfterFlush); // I/O Flush ..
409         // num_events = XEventsQueued(dpy, QueuedAlready); // Better, no I/O ..
410         if ( 0 >= XEventsQueued(dpy, QueuedAlready) ) {
411             XUnlockDisplay(dpy) ;
412             return;
413         }
414
415         XNextEvent(dpy, &evt);
416         num_events--;
417
418         if( 0==evt.xany.window ) {
419             _throwNewRuntimeException(dpy, env, "event window NULL, bail out!\n");
420             return ;
421         }
422
423         if(dpy!=evt.xany.display) {
424             _throwNewRuntimeException(dpy, env, "wrong display, bail out!\n");
425             return ;
426         }
427         jwindow = getJavaWindowProperty(env, dpy, evt.xany.window, javaObjectAtom);
428
429         if(NULL==jwindow) {
430             // just leave .. _throwNewRuntimeException(env, "could not fetch Java Window object, bail out!\n");
431             XUnlockDisplay(dpy) ;
432             return;
433         }
434  
435         switch(evt.type) {
436             case KeyRelease:
437             case KeyPress:
438                 if(XLookupString(&evt.xkey,text,255,&keySym,0)==1) {
439                     keyChar=text[0];
440                 } else {
441                     keyChar=0;
442                 }
443                 break;
444             default:
445                 break;
446         }
447
448         XUnlockDisplay(dpy) ;
449
450         switch(evt.type) {
451             case ButtonPress:
452                 (*env)->CallVoidMethod(env, jwindow, sendMouseEventID, (jint) EVENT_MOUSE_PRESSED, 
453                                       (jint) evt.xbutton.state, 
454                                       (jint) evt.xbutton.x, (jint) evt.xbutton.y, (jint) evt.xbutton.button, 0 /*rotation*/);
455                 break;
456             case ButtonRelease:
457                 (*env)->CallVoidMethod(env, jwindow, sendMouseEventID, (jint) EVENT_MOUSE_RELEASED, 
458                                       (jint) evt.xbutton.state, 
459                                       (jint) evt.xbutton.x, (jint) evt.xbutton.y, (jint) evt.xbutton.button, 0 /*rotation*/);
460                 break;
461             case MotionNotify:
462                 (*env)->CallVoidMethod(env, jwindow, sendMouseEventID, (jint) EVENT_MOUSE_MOVED, 
463                                       (jint) evt.xmotion.state, 
464                                       (jint) evt.xmotion.x, (jint) evt.xmotion.y, (jint) 0, 0 /*rotation*/); 
465                 break;
466             case KeyPress:
467                 (*env)->CallVoidMethod(env, jwindow, sendKeyEventID, (jint) EVENT_KEY_PRESSED, 
468                                       (jint) evt.xkey.state, 
469                                       X11KeySym2NewtVKey(keySym), (jchar) keyChar);
470                 break;
471             case KeyRelease:
472                 (*env)->CallVoidMethod(env, jwindow, sendKeyEventID, (jint) EVENT_KEY_RELEASED, 
473                                       (jint) evt.xkey.state, 
474                                       X11KeySym2NewtVKey(keySym), (jchar) keyChar);
475
476                 (*env)->CallVoidMethod(env, jwindow, sendKeyEventID, (jint) EVENT_KEY_TYPED, 
477                                       (jint) evt.xkey.state, 
478                                       (jint) -1, (jchar) keyChar);
479                 break;
480             case DestroyNotify:
481                 DBG_PRINT1( "X11: event . DestroyNotify call 0x%X\n", evt.xdestroywindow.window);
482                 (*env)->CallVoidMethod(env, jwindow, windowDestroyedID);
483                 break;
484             case CreateNotify:
485                 DBG_PRINT1( "X11: event . CreateNotify call 0x%X\n", evt.xcreatewindow.window);
486                 (*env)->CallVoidMethod(env, jwindow, windowCreatedID);
487                 break;
488             case ConfigureNotify:
489                 DBG_PRINT8( "X11: event . ConfigureNotify call 0x%X (parent 0x%X, above 0x%X) %d/%d %dx%d %d\n", 
490                             evt.xconfigure.window, evt.xconfigure.event, evt.xconfigure.above,
491                             evt.xconfigure.x, evt.xconfigure.y, evt.xconfigure.width, evt.xconfigure.height, 
492                             evt.xconfigure.override_redirect);
493                 (*env)->CallVoidMethod(env, jwindow, windowChangedID, 
494                                         (jint) evt.xconfigure.x, (jint) evt.xconfigure.y,
495                                         (jint) evt.xconfigure.width, (jint) evt.xconfigure.height);
496                 break;
497             case ClientMessage:
498                 if (evt.xclient.send_event==True && evt.xclient.data.l[0]==(Atom)wmDeleteAtom) {
499                     DBG_PRINT2( "X11: event . ClientMessage call 0x%X type 0x%X !!!\n", evt.xclient.window, evt.xclient.message_type);
500                     (*env)->CallVoidMethod(env, jwindow, windowDestroyNotifyID);
501                     // Called by Window.java: CloseWindow(); 
502                 }
503                 break;
504
505             // unhandled events .. yet ..
506
507             case FocusIn:
508                 DBG_PRINT1( "X11: event . FocusIn call 0x%X\n", evt.xvisibility.window);
509                 break;
510             case FocusOut:
511                 DBG_PRINT1( "X11: event . FocusOut call 0x%X\n", evt.xvisibility.window);
512                 break;
513             case VisibilityNotify:
514                 DBG_PRINT1( "X11: event . VisibilityNotify call 0x%X\n", evt.xvisibility.window);
515                 break;
516             case Expose:
517                 DBG_PRINT1( "X11: event . Expose call 0x%X\n", evt.xexpose.window);
518                 /* FIXME: Might want to send a repaint event .. */
519                 break;
520             case UnmapNotify:
521                 DBG_PRINT1( "X11: event . UnmapNotify call 0x%X\n", evt.xunmap.window);
522                 break;
523             default:
524                 DBG_PRINT3("X11: event . unhandled %d 0x%X call 0x%X\n", evt.type, evt.type, evt.xunmap.window);
525         }
526     }
527 }
528
529
530 /**
531  * Screen
532  */
533
534 /*
535  * Class:     com_jogamp_newt_x11_X11Screen
536  * Method:    GetScreen
537  * Signature: (JI)J
538  */
539 JNIEXPORT jlong JNICALL Java_com_jogamp_newt_x11_X11Screen_GetScreen
540   (JNIEnv *env, jobject obj, jlong display, jint screen_index)
541 {
542     Display * dpy = (Display *)(intptr_t)display;
543     Screen  * scrn= NULL;
544
545     if(dpy==NULL) {
546         _throwNewRuntimeException(NULL, env, "invalid display connection..\n");
547         return 0;
548     }
549     XLockDisplay(dpy);
550
551     scrn = ScreenOfDisplay(dpy,screen_index);
552     if(scrn==NULL) {
553         scrn=DefaultScreenOfDisplay(dpy);
554     }
555     if(scrn==NULL) {
556         fprintf(stderr, "couldn't get screen ..\n");
557     }
558     XUnlockDisplay(dpy) ;
559     return (jlong) (intptr_t) scrn;
560 }
561
562 JNIEXPORT jint JNICALL Java_com_jogamp_newt_x11_X11Screen_getWidth0
563   (JNIEnv *env, jobject obj, jlong display, jint scrn_idx)
564 {
565     Display * dpy = (Display *) (intptr_t) display;
566     return (jint) XDisplayWidth( dpy, scrn_idx);
567 }
568
569 JNIEXPORT jint JNICALL Java_com_jogamp_newt_x11_X11Screen_getHeight0
570   (JNIEnv *env, jobject obj, jlong display, jint scrn_idx)
571 {
572     Display * dpy = (Display *) (intptr_t) display;
573     return (jint) XDisplayHeight( dpy, scrn_idx);
574 }
575
576
577 /**
578  * Window
579  */
580
581 /*
582  * Class:     com_jogamp_newt_x11_X11Window
583  * Method:    initIDs
584  * Signature: ()Z
585  */
586 JNIEXPORT jboolean JNICALL Java_com_jogamp_newt_x11_X11Window_initIDs
587   (JNIEnv *env, jclass clazz)
588 {
589     windowChangedID = (*env)->GetMethodID(env, clazz, "windowChanged", "(IIII)V");
590     windowDestroyNotifyID = (*env)->GetMethodID(env, clazz, "windowDestroyNotify", "()V");
591     windowDestroyedID = (*env)->GetMethodID(env, clazz, "windowDestroyed", "()V");
592     windowCreatedID = (*env)->GetMethodID(env, clazz, "windowCreated", "(J)V");
593     sendMouseEventID = (*env)->GetMethodID(env, clazz, "sendMouseEvent", "(IIIIII)V");
594     sendKeyEventID = (*env)->GetMethodID(env, clazz, "sendKeyEvent", "(IIIC)V");
595
596     if (windowChangedID == NULL ||
597         windowDestroyNotifyID == NULL ||
598         windowDestroyedID == NULL ||
599         windowCreatedID == NULL ||
600         sendMouseEventID == NULL ||
601         sendKeyEventID == NULL) {
602         return JNI_FALSE;
603     }
604     return JNI_TRUE;
605 }
606
607 /*
608  * Class:     com_jogamp_newt_x11_X11Window
609  * Method:    CreateWindow
610  * Signature: (JJIJIIII)J
611  */
612 JNIEXPORT jlong JNICALL Java_com_jogamp_newt_x11_X11Window_CreateWindow
613   (JNIEnv *env, jobject obj, jlong parent, jlong display, jint screen_index, 
614                              jlong visualID, 
615                              jlong javaObjectAtom, jlong windowDeleteAtom, 
616                              jint x, jint y, jint width, jint height)
617 {
618     Display * dpy  = (Display *)(intptr_t)display;
619     int       scrn_idx = (int)screen_index;
620     Window  windowParent = (Window) parent;
621     Window  window = 0;
622
623     XVisualInfo visualTemplate;
624     XVisualInfo *pVisualQuery = NULL;
625     Visual *visual = NULL;
626     int depth;
627
628     XSetWindowAttributes xswa;
629     unsigned long attrMask;
630     int n;
631
632     Screen* scrn;
633     Atom wm_delete_atom;
634
635     DBG_PRINT4( "X11: CreateWindow %x/%d %dx%d\n", x, y, width, height);
636
637     if(dpy==NULL) {
638         _throwNewRuntimeException(NULL, env, "invalid display connection..\n");
639         return 0;
640     }
641
642     if(visualID<0) {
643         _throwNewRuntimeException(NULL, env, "invalid VisualID ..\n");
644         return 0;
645     }
646
647     XLockDisplay(dpy) ;
648
649     XSync(dpy, False);
650
651     scrn = ScreenOfDisplay(dpy, screen_index);
652
653     // try given VisualID on screen
654     memset(&visualTemplate, 0, sizeof(XVisualInfo));
655     visualTemplate.screen = scrn_idx;
656     visualTemplate.visualid = (VisualID)visualID;
657     pVisualQuery = XGetVisualInfo(dpy, VisualIDMask|VisualScreenMask, &visualTemplate,&n);
658     DUMP_VISUAL_INFO("Given VisualID,ScreenIdx", pVisualQuery);
659     if(pVisualQuery!=NULL) {
660         visual   = pVisualQuery->visual;
661         depth    = pVisualQuery->depth;
662         visualID = (jlong)pVisualQuery->visualid;
663         XFree(pVisualQuery);
664         pVisualQuery=NULL;
665     }
666     DBG_PRINT5( "X11: [CreateWindow] trying given (dpy %p, screen %d, visualID: %d, parent %p) found: %p\n", dpy, scrn_idx, (int)visualID, windowParent, visual);
667
668     if (visual==NULL)
669     { 
670         _throwNewRuntimeException(dpy, env, "could not query Visual by given VisualID, bail out!\n");
671         return 0;
672     } 
673
674     if(pVisualQuery!=NULL) {
675         XFree(pVisualQuery);
676         pVisualQuery=NULL;
677     }
678
679     if(0==windowParent) {
680         windowParent = XRootWindowOfScreen(scrn);
681     }
682
683     attrMask  = (CWBackPixel | CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect) ;
684
685     memset(&xswa, 0, sizeof(xswa));
686     xswa.override_redirect = False; // decorated
687     xswa.border_pixel = 0;
688     xswa.background_pixel = 0;
689     xswa.event_mask = ExposureMask | StructureNotifyMask | KeyPressMask | KeyReleaseMask;
690     xswa.colormap = XCreateColormap(dpy,
691                                     XRootWindow(dpy, scrn_idx),
692                                     visual,
693                                     AllocNone);
694
695     window = XCreateWindow(dpy,
696                            windowParent,
697                            x, y,
698                            width, height,
699                            0, // border width
700                            depth,
701                            InputOutput,
702                            visual,
703                            attrMask,
704                            &xswa);
705
706     wm_delete_atom = (Atom)windowDeleteAtom;
707     XSetWMProtocols(dpy, window, &wm_delete_atom, 1);
708
709     setJavaWindowProperty(env, dpy, window, javaObjectAtom, (*env)->NewGlobalRef(env, obj));
710
711     XClearWindow(dpy, window);
712     XSync(dpy, False);
713
714     {
715         long xevent_mask = 0;
716         xevent_mask |= ButtonPressMask|ButtonReleaseMask|PointerMotionMask;
717         xevent_mask |= KeyPressMask|KeyReleaseMask;
718         xevent_mask |= ExposureMask | StructureNotifyMask | SubstructureNotifyMask | VisibilityNotify ;
719         XSelectInput(dpy, window, xevent_mask);
720
721         /**
722             XGrabPointer(dpy, window, True, ButtonPressMask|ButtonReleaseMask|PointerMotionMask,
723                         GrabModeAsync, GrabModeAsync, window, None, CurrentTime);
724             XGrabKeyboard(dpy, window, True, GrabModeAsync, GrabModeAsync, CurrentTime);
725         */
726     }
727
728     XUnlockDisplay(dpy) ;
729
730     DBG_PRINT2( "X11: [CreateWindow] created window %p on display %p\n", window, dpy);
731     (*env)->CallVoidMethod(env, obj, windowCreatedID, (jlong) window);
732
733     return (jlong) window;
734 }
735
736 /*
737  * Class:     com_jogamp_newt_x11_X11Window
738  * Method:    CloseWindow
739  * Signature: (JJ)V
740  */
741 JNIEXPORT void JNICALL Java_com_jogamp_newt_x11_X11Window_CloseWindow
742   (JNIEnv *env, jobject obj, jlong display, jlong window, jlong javaObjectAtom)
743 {
744     Display * dpy = (Display *) (intptr_t) display;
745     Window w = (Window)window;
746     jobject jwindow;
747
748     if(dpy==NULL) {
749         _throwNewRuntimeException(NULL, env, "invalid display connection..\n");
750         return;
751     }
752     XLockDisplay(dpy) ;
753
754     jwindow = getJavaWindowProperty(env, dpy, w, javaObjectAtom);
755     if(NULL==jwindow) {
756         _throwNewRuntimeException(dpy, env, "could not fetch Java Window object, bail out!\n");
757         return;
758     }
759     if ( JNI_FALSE == (*env)->IsSameObject(env, jwindow, obj) ) {
760         _throwNewRuntimeException(dpy, env, "Internal Error .. Window global ref not the same!\n");
761         return;
762     }
763     (*env)->DeleteGlobalRef(env, jwindow);
764
765     XSync(dpy, False);
766     /**
767      XUngrabPointer(dpy, CurrentTime);
768      XUngrabKeyboard(dpy, CurrentTime);
769      */
770     XSelectInput(dpy, w, 0);
771     XUnmapWindow(dpy, w);
772     XSync(dpy, False);
773     XDestroyWindow(dpy, w);
774     XSync(dpy, False);
775
776     XUnlockDisplay(dpy) ;
777
778     (*env)->CallVoidMethod(env, obj, windowDestroyedID);
779 }
780
781 /*
782  * Class:     com_jogamp_newt_x11_X11Window
783  * Method:    setVisible0
784  * Signature: (JJZ)V
785  */
786 JNIEXPORT void JNICALL Java_com_jogamp_newt_x11_X11Window_setVisible0
787   (JNIEnv *env, jobject obj, jlong display, jlong window, jboolean visible)
788 {
789     Display * dpy = (Display *) (intptr_t) display;
790     Window w = (Window)window;
791     DBG_PRINT1( "X11: setVisible0 vis %d\n", visible);
792
793     if(dpy==NULL) {
794         _throwNewRuntimeException(NULL, env, "invalid display connection..\n");
795         return;
796     }
797     XLockDisplay(dpy) ;
798
799     XSync(dpy, False);
800     if(visible==JNI_TRUE) {
801         XMapRaised(dpy, w);
802         XSync(dpy, False);
803
804         // XSetInputFocus(dpy, w, RevertToParent, CurrentTime);
805         // XSync(dpy, False);
806
807     } else {
808         /**
809          XUngrabPointer(dpy, CurrentTime);
810          XUngrabKeyboard(dpy, CurrentTime);
811          */
812         XUnmapWindow(dpy, w);
813         XSync(dpy, False);
814     }
815     XUnlockDisplay(dpy) ;
816 }
817
818 #define MWM_FULLSCREEN 1
819
820 #ifdef MWM_FULLSCREEN
821     #define MWM_HINTS_DECORATIONS   (1L << 1)
822     #define PROP_MWM_HINTS_ELEMENTS 5
823 #endif
824
825 /*
826  * Class:     com_jogamp_newt_x11_X11Window
827  * Method:    setSize0
828  * Signature: (JIJIIIIIZ)V
829  */
830 JNIEXPORT void JNICALL Java_com_jogamp_newt_x11_X11Window_setSize0
831   (JNIEnv *env, jobject obj, jlong jparent, jlong display, jint screen_index, jlong window, jint x, jint y, jint width, jint height, jint decorationToggle, jboolean setVisible)
832 {
833     Display * dpy = (Display *) (intptr_t) display;
834     Window w = (Window)window;
835     Screen * scrn = ScreenOfDisplay(dpy, (int)screen_index);
836     Window parent = (0!=jparent)?(Window)jparent:XRootWindowOfScreen(scrn);
837
838     XWindowChanges xwc;
839
840     DBG_PRINT6( "X11: setSize0 %d/%d %dx%d, dec %d, vis %d\n", x, y, width, height, decorationToggle, setVisible);
841
842     if(dpy==NULL) {
843         _throwNewRuntimeException(NULL, env, "invalid display connection..\n");
844         return;
845     }
846     XLockDisplay(dpy) ;
847
848     XSync(dpy, False);
849
850     if(setVisible==JNI_TRUE) {
851         XMapRaised(dpy, w);
852         XSync(dpy, False);
853     }
854
855     if(0!=decorationToggle) {
856 #ifdef MWM_FULLSCREEN
857         unsigned long mwmhints[PROP_MWM_HINTS_ELEMENTS] = { 0, 0, 0, 0, 0 }; // flags, functions, decorations, input_mode, status
858         Atom prop;
859
860         mwmhints[0] = MWM_HINTS_DECORATIONS;
861         mwmhints[2] = (decorationToggle<0)?False:True;
862         prop = XInternAtom( dpy, "_MOTIF_WM_HINTS", False );
863         XChangeProperty( dpy, w, prop, prop, 32, PropModeReplace, (unsigned char *)&mwmhints, PROP_MWM_HINTS_ELEMENTS);
864 #else
865         XSetWindowAttributes xswa;
866         unsigned long attrMask=CWOverrideRedirect;
867
868         if(decorationToggle<0) {
869             /* undecorated  */
870             xswa.override_redirect = True; 
871         } else {
872             /* decorated  */
873             xswa.override_redirect = False;
874         }
875         XChangeWindowAttributes(dpy, w, attrMask, &xswa);
876         XReparentWindow( dpy, w, parent, x, y );
877 #endif
878     }
879     XSync(dpy, False);
880     xwc.width=width;
881     xwc.height=height;
882     XConfigureWindow(dpy, w, CWWidth|CWHeight, &xwc);
883     XReparentWindow( dpy, w, parent, x, y );
884
885     XSync(dpy, False);
886     XUnlockDisplay(dpy) ;
887 }
888
889 /*
890  * Class:     com_jogamp_newt_x11_X11Window
891  * Method:    setPosition0
892  * Signature: (JJII)V
893  */
894 JNIEXPORT void JNICALL Java_com_jogamp_newt_x11_X11Window_setPosition0
895   (JNIEnv *env, jobject obj, jlong display, jlong window, jint x, jint y)
896 {
897     Display * dpy = (Display *) (intptr_t) display;
898     Window w = (Window)window;
899     XWindowChanges xwc;
900
901     DBG_PRINT2( "X11: setPos0 . XConfigureWindow %d/%d\n", x, y);
902     if(dpy==NULL) {
903         _throwNewRuntimeException(NULL, env, "invalid display connection..\n");
904         return;
905     }
906     XLockDisplay(dpy) ;
907
908     xwc.x=x;
909     xwc.y=y;
910     XConfigureWindow(dpy, w, CWX|CWY, &xwc);
911     XSync(dpy, False);
912
913     XUnlockDisplay(dpy) ;
914 }
915
http://JogAmp.org git info: FAQ, tutorial and man pages.