1 /*
2  * Copyright (c) 2002-2008 LWJGL Project
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  *
12  * * Redistributions in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in the
14  *   documentation and/or other materials provided with the distribution.
15  *
16  * * Neither the name of 'LWJGL' nor the names of
17  *   its contributors may be used to endorse or promote products derived
18  *   from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /**
34  * $Id$
35  *
36  * Linux specific display functions.
37  *
38  * @author elias_naur <elias_naur@users.sourceforge.net>
39  * @version $Revision$
40  */
41 
42 #include <X11/X.h>
43 #include <X11/Xlib.h>
44 #include <X11/Xutil.h>
45 #include <X11/extensions/xf86vmode.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <assert.h>
49 #include <jni.h>
50 #include <jawt_md.h>
51 #include "common_tools.h"
52 #include "extgl.h"
53 #include "extgl_glx.h"
54 #include "context.h"
55 #include "org_lwjgl_opengl_LinuxDisplay.h"
56 #include "org_lwjgl_opengl_LinuxDisplayPeerInfo.h"
57 #include "org_lwjgl_LinuxSysImplementation.h"
58 
59 #define ERR_MSG_SIZE 1024
60 
61 typedef struct {
62 	unsigned long flags;
63 	unsigned long functions;
64 	unsigned long decorations;
65 	long input_mode;
66 	unsigned long status;
67 } MotifWmHints;
68 
69 #define MWM_HINTS_DECORATIONS   (1L << 1)
70 
71 static GLXWindow glx_window = None;
72 
73 static Colormap cmap;
74 static int current_depth;
75 
76 static Visual *current_visual;
77 
checkXError(JNIEnv * env,Display * disp)78 static bool checkXError(JNIEnv *env, Display *disp) {
79 	XSync(disp, False);
80 	return (*env)->ExceptionCheck(env) == JNI_FALSE;
81 }
82 
global_error_handler(Display * disp,XErrorEvent * error)83 static int global_error_handler(Display *disp, XErrorEvent *error) {
84 	JNIEnv *env = getThreadEnv();
85 	if (env != NULL) {
86 		jclass org_lwjgl_LinuxDisplay_class = (*env)->FindClass(env, "org/lwjgl/opengl/LinuxDisplay");
87 		if (org_lwjgl_LinuxDisplay_class == NULL) {
88 			// Don't propagate error
89 			(*env)->ExceptionClear(env);
90 			return 0;
91 		}
92 		jmethodID handler_method = (*env)->GetStaticMethodID(env, org_lwjgl_LinuxDisplay_class, "globalErrorHandler", "(JJJJJJJ)I");
93 		if (handler_method == NULL)
94 			return 0;
95 		return (*env)->CallStaticIntMethod(env, org_lwjgl_LinuxDisplay_class, handler_method, (jlong)(intptr_t)disp, (jlong)(intptr_t)error,
96 				(jlong)(intptr_t)error->display, (jlong)error->serial, (jlong)error->error_code, (jlong)error->request_code, (jlong)error->minor_code);
97 	} else
98 		return 0;
99 }
100 
openDisplay(JNIEnv * env)101 static jlong openDisplay(JNIEnv *env) {
102 	Display *display_connection = XOpenDisplay(NULL);
103 	if (display_connection == NULL) {
104 		throwException(env, "Could not open X display connection");
105 		return (intptr_t)NULL;
106 	}
107 	return (intptr_t)display_connection;
108 }
109 
Java_org_lwjgl_DefaultSysImplementation_getJNIVersion(JNIEnv * env,jobject ignored)110 JNIEXPORT jint JNICALL Java_org_lwjgl_DefaultSysImplementation_getJNIVersion
111   (JNIEnv *env, jobject ignored) {
112 	return org_lwjgl_LinuxSysImplementation_JNI_VERSION;
113 }
114 
Java_org_lwjgl_opengl_LinuxDisplay_getErrorText(JNIEnv * env,jclass unused,jlong display_ptr,jlong error_code)115 JNIEXPORT jstring JNICALL Java_org_lwjgl_opengl_LinuxDisplay_getErrorText(JNIEnv *env, jclass unused, jlong display_ptr, jlong error_code) {
116 	Display *disp = (Display *)(intptr_t)display_ptr;
117 	char err_msg_buffer[ERR_MSG_SIZE];
118 	XGetErrorText(disp, error_code, err_msg_buffer, ERR_MSG_SIZE);
119 	err_msg_buffer[ERR_MSG_SIZE - 1] = '\0';
120 	return NewStringNativeWithLength(env, err_msg_buffer, strlen(err_msg_buffer));
121 }
122 
Java_org_lwjgl_opengl_LinuxDisplay_callErrorHandler(JNIEnv * env,jclass unused,jlong handler_ptr,jlong display_ptr,jlong event_ptr)123 JNIEXPORT jint JNICALL Java_org_lwjgl_opengl_LinuxDisplay_callErrorHandler(JNIEnv *env, jclass unused, jlong handler_ptr, jlong display_ptr, jlong event_ptr) {
124 	XErrorHandler handler = (XErrorHandler)(intptr_t)handler_ptr;
125 	Display *disp = (Display *)(intptr_t)display_ptr;
126 	XErrorEvent *event = (XErrorEvent *)(intptr_t)event_ptr;
127 	return (jint)handler(disp, event);
128 }
129 
Java_org_lwjgl_opengl_LinuxDisplay_setErrorHandler(JNIEnv * env,jclass unused)130 JNIEXPORT jlong JNICALL Java_org_lwjgl_opengl_LinuxDisplay_setErrorHandler(JNIEnv *env, jclass unused) {
131 	return (intptr_t)XSetErrorHandler(global_error_handler);
132 }
133 
Java_org_lwjgl_opengl_LinuxDisplay_resetErrorHandler(JNIEnv * env,jclass unused,jlong handler_ptr)134 JNIEXPORT jlong JNICALL Java_org_lwjgl_opengl_LinuxDisplay_resetErrorHandler(JNIEnv *env, jclass unused, jlong handler_ptr) {
135 	XErrorHandler handler = (XErrorHandler)(intptr_t)handler_ptr;
136 	return (intptr_t)XSetErrorHandler(handler);
137 }
138 
Java_org_lwjgl_opengl_LinuxDisplay_nSync(JNIEnv * env,jclass unused,jlong display_ptr,jboolean throw_away_events)139 JNIEXPORT void JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nSync(JNIEnv *env, jclass unused, jlong display_ptr, jboolean throw_away_events) {
140 	Display *disp = (Display *)(intptr_t)display_ptr;
141 	XSync(disp, throw_away_events ? True : False);
142 }
143 
Java_org_lwjgl_opengl_LinuxDisplay_sync(JNIEnv * env,jclass unused,jlong display_ptr,jboolean throw_away_events)144 JNIEXPORT void JNICALL Java_org_lwjgl_opengl_LinuxDisplay_sync(JNIEnv *env, jclass unused, jlong display_ptr, jboolean throw_away_events) {
145 	Display *disp = (Display *)(intptr_t)display_ptr;
146 	XSync(disp, throw_away_events ? True : False);
147 }
148 
Java_org_lwjgl_opengl_LinuxDisplay_nGetDefaultScreen(JNIEnv * env,jclass unused,jlong display_ptr)149 JNIEXPORT jint JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nGetDefaultScreen(JNIEnv *env, jclass unused, jlong display_ptr) {
150 	Display *disp = (Display *)(intptr_t)display_ptr;
151 	return XDefaultScreen(disp);
152 }
153 
Java_org_lwjgl_opengl_LinuxDisplay_nInternAtom(JNIEnv * env,jclass unused,jlong display_ptr,jstring atom_name_obj,jboolean only_if_exists)154 JNIEXPORT jlong JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nInternAtom(JNIEnv *env, jclass unused, jlong display_ptr, jstring atom_name_obj, jboolean only_if_exists) {
155 	Display *disp = (Display *)(intptr_t)display_ptr;
156 	char *atom_name = GetStringNativeChars(env, atom_name_obj);
157 	if (atom_name == NULL)
158 		return 0;
159 	Atom atom = XInternAtom(disp, atom_name, only_if_exists ? True : False);
160 	free(atom_name);
161 	return atom;
162 }
163 
setDecorations(Display * disp,Window window,int dec)164 static void setDecorations(Display *disp, Window window, int dec) {
165 	Atom motif_hints_atom = XInternAtom(disp, "_MOTIF_WM_HINTS", False);
166 	MotifWmHints motif_hints;
167 	motif_hints.flags = MWM_HINTS_DECORATIONS;
168 	motif_hints.decorations = dec;
169 	XChangeProperty(disp, window, motif_hints_atom, motif_hints_atom, 32, PropModeReplace, (unsigned char *)&motif_hints, sizeof(MotifWmHints)/sizeof(long));
170 }
171 
isLegacyFullscreen(jint window_mode)172 static bool isLegacyFullscreen(jint window_mode) {
173 	return window_mode == org_lwjgl_opengl_LinuxDisplay_FULLSCREEN_LEGACY;
174 }
175 
setWindowTitle(Display * disp,Window window,jlong title,jint len)176 static void setWindowTitle(Display *disp, Window window, jlong title, jint len) {
177 	Atom UTF8_STRING = XInternAtom(disp, "UTF8_STRING", True);
178 	Atom _NET_WM_NAME = XInternAtom(disp, "_NET_WM_NAME", True);
179 	Atom _NET_WM_ICON_NAME = XInternAtom(disp, "_NET_WM_ICON_NAME", True);
180 
181 	// ASCII fallback if XChangeProperty fails.
182     XmbSetWMProperties(disp, window, (const char *)(intptr_t)title, (const char *)(intptr_t)title, NULL, 0, NULL, NULL, NULL);
183 
184 	// Set the UTF-8 encoded title
185 	if ( _NET_WM_NAME )
186 		XChangeProperty(
187 			disp, window, _NET_WM_NAME, UTF8_STRING,
188 			8, PropModeReplace, (const unsigned char *)(intptr_t)title, len
189 		);
190 
191 	if ( _NET_WM_ICON_NAME )
192 		XChangeProperty(
193 			disp, window, _NET_WM_ICON_NAME, UTF8_STRING,
194 			8, PropModeReplace, (const unsigned char *)(intptr_t)title, len
195 		);
196 }
197 
setClassHint(Display * disp,Window window,jlong wm_name,jlong wm_class)198 static void setClassHint(Display *disp, Window window, jlong wm_name, jlong wm_class) {
199 	XClassHint* hint = XAllocClassHint();
200 
201 	hint->res_name = (char *)(intptr_t)wm_name;
202 	hint->res_class = (char *)(intptr_t)wm_class;
203 
204 	XSetClassHint(disp, window, hint);
205 
206 	XFree(hint);
207 }
208 
Java_org_lwjgl_opengl_LinuxDisplay_openDisplay(JNIEnv * env,jclass clazz)209 JNIEXPORT jlong JNICALL Java_org_lwjgl_opengl_LinuxDisplay_openDisplay(JNIEnv *env, jclass clazz) {
210 	return openDisplay(env);
211 }
212 
Java_org_lwjgl_opengl_LinuxDisplay_closeDisplay(JNIEnv * env,jclass clazz,jlong display)213 JNIEXPORT void JNICALL Java_org_lwjgl_opengl_LinuxDisplay_closeDisplay(JNIEnv *env, jclass clazz, jlong display) {
214 	Display *disp = (Display *)(intptr_t)display;
215 	XCloseDisplay(disp);
216 }
217 
Java_org_lwjgl_opengl_LinuxDisplayPeerInfo_initDrawable(JNIEnv * env,jclass clazz,jlong window,jobject peer_info_handle)218 JNIEXPORT void JNICALL Java_org_lwjgl_opengl_LinuxDisplayPeerInfo_initDrawable(JNIEnv *env, jclass clazz, jlong window, jobject peer_info_handle) {
219 	X11PeerInfo *peer_info = (*env)->GetDirectBufferAddress(env, peer_info_handle);
220 	if (peer_info->glx13)
221 		peer_info->drawable = glx_window;
222 	else
223 		peer_info->drawable = window;
224 }
225 
Java_org_lwjgl_opengl_LinuxDisplayPeerInfo_initDefaultPeerInfo(JNIEnv * env,jclass clazz,jlong display,jint screen,jobject peer_info_handle,jobject pixel_format)226 JNIEXPORT void JNICALL Java_org_lwjgl_opengl_LinuxDisplayPeerInfo_initDefaultPeerInfo(JNIEnv *env, jclass clazz, jlong display, jint screen, jobject peer_info_handle, jobject pixel_format) {
227 	Display *disp = (Display *)(intptr_t)display;
228 	initPeerInfo(env, peer_info_handle, disp, screen, pixel_format, true, GLX_WINDOW_BIT, true, false);
229 }
230 
Java_org_lwjgl_opengl_LinuxDisplay_nSetTitle(JNIEnv * env,jclass clazz,jlong display,jlong window_ptr,jlong title,jint len)231 JNIEXPORT void JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nSetTitle(JNIEnv * env, jclass clazz, jlong display, jlong window_ptr, jlong title, jint len) {
232 	Display *disp = (Display *)(intptr_t)display;
233 	Window window = (Window)window_ptr;
234 	setWindowTitle(disp, window, title, len);
235 }
236 
Java_org_lwjgl_opengl_LinuxDisplay_nSetClassHint(JNIEnv * env,jclass clazz,jlong display,jlong window_ptr,jlong wm_name,jlong wm_class)237 JNIEXPORT void JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nSetClassHint(JNIEnv * env, jclass clazz, jlong display, jlong window_ptr, jlong wm_name, jlong wm_class) {
238 	Display *disp = (Display *)(intptr_t)display;
239 	Window window = (Window)window_ptr;
240 	setClassHint(disp, window, wm_name, wm_class);
241 }
242 
destroyWindow(JNIEnv * env,Display * disp,Window window)243 static void destroyWindow(JNIEnv *env, Display *disp, Window window) {
244 	if (glx_window != None) {
245 		lwjgl_glXDestroyWindow(disp, glx_window);
246 		glx_window = None;
247 	}
248 	XDestroyWindow(disp, window);
249 	XFreeColormap(disp, cmap);
250 }
251 
isNetWMFullscreenSupported(JNIEnv * env,Display * disp,int screen)252 static bool isNetWMFullscreenSupported(JNIEnv *env, Display *disp, int screen) {
253 	unsigned long nitems;
254 	Atom actual_type;
255 	int actual_format;
256 	unsigned long bytes_after;
257 	Atom *supported_list;
258 	Atom netwm_supported_atom = XInternAtom(disp, "_NET_SUPPORTED", False);
259 	int result = XGetWindowProperty(disp, RootWindow(disp, screen), netwm_supported_atom, 0, 10000, False, AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes_after, (void *)&supported_list);
260 	if (result != Success) {
261 		throwException(env, "Unable to query _NET_SUPPORTED window property");
262 		return false;
263 	}
264 	Atom fullscreen_atom = XInternAtom(disp, "_NET_WM_STATE_FULLSCREEN", False);
265 	bool supported = false;
266 	unsigned long i;
267 	for (i = 0; i < nitems; i++) {
268 		if (fullscreen_atom == supported_list[i]) {
269 			supported = true;
270 			break;
271 		}
272 	}
273 	XFree(supported_list);
274 	return supported;
275 }
276 
Java_org_lwjgl_opengl_LinuxDisplay_nIsNetWMFullscreenSupported(JNIEnv * env,jclass unused,jlong display,jint screen)277 JNIEXPORT jboolean JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nIsNetWMFullscreenSupported(JNIEnv *env, jclass unused, jlong display, jint screen) {
278 	Display *disp = (Display *)(intptr_t)display;
279 	return isNetWMFullscreenSupported(env, disp, screen) ? JNI_TRUE : JNI_FALSE;
280 }
281 
Java_org_lwjgl_opengl_LinuxDisplay_nReshape(JNIEnv * env,jclass clazz,jlong display,jlong window_ptr,jint x,jint y,jint width,jint height)282 JNIEXPORT void JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nReshape(JNIEnv *env, jclass clazz, jlong display, jlong window_ptr, jint x, jint y, jint width, jint height) {
283 	Display *disp = (Display *)(intptr_t)display;
284 	Window window = (Window)window_ptr;
285 	XMoveWindow(disp, window, x, y);
286 	XResizeWindow(disp, window, width, height);
287 }
288 
Java_org_lwjgl_opengl_LinuxDisplay_synchronize(JNIEnv * env,jclass clazz,jlong display,jboolean synchronize)289 JNIEXPORT void JNICALL Java_org_lwjgl_opengl_LinuxDisplay_synchronize(JNIEnv *env, jclass clazz, jlong display, jboolean synchronize) {
290 	Display *disp = (Display *)(intptr_t)display;
291 	XSynchronize(disp, synchronize ? True : False);
292 }
293 
Java_org_lwjgl_opengl_LinuxDisplay_getRootWindow(JNIEnv * env,jclass clazz,jlong display,jint screen)294 JNIEXPORT jlong JNICALL Java_org_lwjgl_opengl_LinuxDisplay_getRootWindow(JNIEnv *env, jclass clazz, jlong display, jint screen) {
295 	Display *disp = (Display *)(intptr_t)display;
296 	return RootWindow(disp, screen);
297 }
298 
getCurrentWindow(JNIEnv * env,jlong display_ptr,jlong window_ptr)299 static Window getCurrentWindow(JNIEnv *env, jlong display_ptr, jlong window_ptr) {
300 	Display *disp = (Display *)(intptr_t)display_ptr;
301 
302 	Window parent = (Window)window_ptr;
303 	Window win, root;
304 
305 	Window *children;
306 	unsigned int nchildren;
307 
308 	do {
309 		win = parent;
310 
311 		if (XQueryTree(disp, win, &root, &parent, &children, &nchildren) == 0) {
312 			throwException(env, "XQueryTree failed");
313 			return 0;
314 		}
315 
316 		if (children != NULL) XFree(children);
317 	} while (parent != root);
318 
319 	return win;
320 }
321 
Java_org_lwjgl_opengl_LinuxDisplay_nGetX(JNIEnv * env,jclass unused,jlong display_ptr,jlong window_ptr)322 JNIEXPORT jint JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nGetX(JNIEnv *env, jclass unused, jlong display_ptr, jlong window_ptr) {
323 	Display *disp = (Display *)(intptr_t)display_ptr;
324 	Window win = getCurrentWindow(env, display_ptr, window_ptr);
325 
326 	XWindowAttributes win_attribs;
327 	XGetWindowAttributes(disp, win, &win_attribs);
328 
329 	return win_attribs.x;
330 }
331 
Java_org_lwjgl_opengl_LinuxDisplay_nGetY(JNIEnv * env,jclass unused,jlong display_ptr,jlong window_ptr)332 JNIEXPORT jint JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nGetY(JNIEnv *env, jclass unused, jlong display_ptr, jlong window_ptr) {
333 	Display *disp = (Display *)(intptr_t)display_ptr;
334 	Window win = getCurrentWindow(env, display_ptr, window_ptr);
335 
336 	XWindowAttributes win_attribs;
337 	XGetWindowAttributes(disp, win, &win_attribs);
338 
339 	return win_attribs.y;
340 }
341 
Java_org_lwjgl_opengl_LinuxDisplay_nGetWidth(JNIEnv * env,jclass unused,jlong display_ptr,jlong window_ptr)342 JNIEXPORT jint JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nGetWidth(JNIEnv *env, jclass unused, jlong display_ptr, jlong window_ptr) {
343 	Display *disp = (Display *)(intptr_t)display_ptr;
344 	Window win = (Window)window_ptr;
345 	XWindowAttributes win_attribs;
346 
347 	XGetWindowAttributes(disp, win, &win_attribs);
348 
349 	return win_attribs.width;
350 }
351 
Java_org_lwjgl_opengl_LinuxDisplay_nGetHeight(JNIEnv * env,jclass unused,jlong display_ptr,jlong window_ptr)352 JNIEXPORT jint JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nGetHeight(JNIEnv *env, jclass unused, jlong display_ptr, jlong window_ptr) {
353 	Display *disp = (Display *)(intptr_t)display_ptr;
354 	Window win = (Window)window_ptr;
355 	XWindowAttributes win_attribs;
356 
357 	XGetWindowAttributes(disp, win, &win_attribs);
358 
359 	return win_attribs.height;
360 }
361 
updateWindowHints(JNIEnv * env,Display * disp,Window window)362 static void updateWindowHints(JNIEnv *env, Display *disp, Window window) {
363 	XWMHints* win_hints = XAllocWMHints();
364 	if (win_hints == NULL) {
365 		throwException(env, "XAllocWMHints failed");
366 		return;
367 	}
368 
369 	win_hints->flags = InputHint;
370 	win_hints->input = True;
371 
372 	XSetWMHints(disp, window, win_hints);
373 	XFree(win_hints);
374 	XFlush(disp);
375 }
376 
updateWindowBounds(Display * disp,Window win,int x,int y,int width,int height,jboolean position,jboolean resizable)377 static void updateWindowBounds(Display *disp, Window win, int x, int y, int width, int height, jboolean position, jboolean resizable) {
378 	XSizeHints *window_hints = XAllocSizeHints();
379 
380 	if (position) {
381 		window_hints->flags |= PPosition;
382 		window_hints->x = x;
383 		window_hints->y = y;
384 	}
385 
386 	if (!resizable) {
387 		window_hints->flags |= PMinSize | PMaxSize;
388 		window_hints->min_width = width;
389 		window_hints->max_width = width;
390 		window_hints->min_height = height;
391 		window_hints->max_height = height;
392 	}
393 
394 	XSetWMNormalHints(disp, win, window_hints);
395 	XFree(window_hints);
396 }
397 
createWindow(JNIEnv * env,Display * disp,int screen,jint window_mode,X11PeerInfo * peer_info,int x,int y,int width,int height,jboolean undecorated,long parent_handle,jboolean resizable)398 static Window createWindow(JNIEnv* env, Display *disp, int screen, jint window_mode, X11PeerInfo *peer_info, int x, int y, int width, int height, jboolean undecorated, long parent_handle, jboolean resizable) {
399 	Window parent = (Window)parent_handle;
400 	Window win;
401 	XSetWindowAttributes attribs;
402 	int attribmask;
403 
404 	XVisualInfo *vis_info = getVisualInfoFromPeerInfo(env, peer_info);
405 	if (vis_info == NULL)
406 		return false;
407 	cmap = XCreateColormap(disp, parent, vis_info->visual, AllocNone);
408 	attribs.colormap = cmap;
409 	attribs.border_pixel = 0;
410 	attribs.event_mask = ExposureMask | FocusChangeMask | VisibilityChangeMask | StructureNotifyMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask| EnterWindowMask | LeaveWindowMask;
411 	attribmask = CWColormap | CWEventMask | CWBorderPixel;
412 	if (isLegacyFullscreen(window_mode)) {
413 		attribmask |= CWOverrideRedirect;
414 		attribs.override_redirect = True;
415 	}
416 	win = XCreateWindow(disp, parent, x, y, width, height, 0, vis_info->depth, InputOutput, vis_info->visual, attribmask, &attribs);
417 
418 	current_depth = vis_info->depth;
419 	current_visual = vis_info->visual;
420 
421 	XFree(vis_info);
422 	if (!checkXError(env, disp)) {
423 		XFreeColormap(disp, cmap);
424 		return false;
425 	}
426 //	printfDebugJava(env, "Created window");
427 	if (undecorated) {
428 		// Use Motif decoration hint property and hope the window manager respects them
429 		setDecorations(disp, win, 0);
430 	}
431 
432 	if (RootWindow(disp, screen) == parent_handle) { // only set hints when Display.setParent isn't used
433 		updateWindowBounds(disp, win, x, y, width, height, JNI_TRUE, resizable);
434 		updateWindowHints(env, disp, win);
435 	}
436 
437 #define NUM_ATOMS 1
438 	Atom protocol_atoms[NUM_ATOMS] = {XInternAtom(disp, "WM_DELETE_WINDOW", False)/*, XInternAtom(disp, "WM_TAKE_FOCUS", False)*/};
439 	XSetWMProtocols(disp, win, protocol_atoms, NUM_ATOMS);
440 	if (window_mode == org_lwjgl_opengl_LinuxDisplay_FULLSCREEN_NETWM) {
441 		Atom fullscreen_atom = XInternAtom(disp, "_NET_WM_STATE_FULLSCREEN", False);
442 		XChangeProperty(disp, win, XInternAtom(disp, "_NET_WM_STATE", False),
443 						XInternAtom(disp, "ATOM", False), 32, PropModeReplace, (const unsigned char*)&fullscreen_atom, 1);
444 	}
445 	if (!checkXError(env, disp)) {
446 		destroyWindow(env, disp, win);
447 		return 0;
448 	}
449 	return win;
450 }
451 
Java_org_lwjgl_opengl_LinuxDisplay_reparentWindow(JNIEnv * env,jclass unused,jlong display,jlong window_ptr,jlong parent_ptr,jint x,jint y)452 JNIEXPORT void JNICALL Java_org_lwjgl_opengl_LinuxDisplay_reparentWindow(JNIEnv *env, jclass unused, jlong display, jlong window_ptr, jlong parent_ptr, jint x, jint y) {
453 	Display *disp = (Display *)(intptr_t)display;
454 	Window window = (Window)window_ptr;
455 	Window parent = (Window)parent_ptr;
456 	XReparentWindow(disp, window, parent, x, y);
457 }
458 
Java_org_lwjgl_opengl_LinuxDisplay_mapRaised(JNIEnv * env,jclass unused,jlong display,jlong window_ptr)459 JNIEXPORT void JNICALL Java_org_lwjgl_opengl_LinuxDisplay_mapRaised(JNIEnv *env, jclass unused, jlong display, jlong window_ptr) {
460 	Display *disp = (Display *)(intptr_t)display;
461 	Window window = (Window)window_ptr;
462 	XMapRaised(disp, window);
463 }
464 
Java_org_lwjgl_opengl_LinuxDisplay_getParentWindow(JNIEnv * env,jclass unused,jlong display,jlong window_ptr)465 JNIEXPORT jlong JNICALL Java_org_lwjgl_opengl_LinuxDisplay_getParentWindow(JNIEnv *env, jclass unused, jlong display, jlong window_ptr) {
466 	Display *disp = (Display *)(intptr_t)display;
467 	Window window = (Window)window_ptr;
468 	Window root, parent;
469 	Window *children;
470 	unsigned int nchildren;
471 	if (XQueryTree(disp, window, &root, &parent, &children, &nchildren) == 0) {
472 		throwException(env, "XQueryTree failed");
473 		return None;
474 	}
475 	if (children != NULL)
476 		XFree(children);
477 	return parent;
478 }
479 
Java_org_lwjgl_opengl_LinuxDisplay_getChildCount(JNIEnv * env,jclass unused,jlong display,jlong window_ptr)480 JNIEXPORT jint JNICALL Java_org_lwjgl_opengl_LinuxDisplay_getChildCount(JNIEnv *env, jclass unused, jlong display, jlong window_ptr) {
481 	Display *disp = (Display *)(intptr_t)display;
482 	Window window = (Window)window_ptr;
483 	Window root, parent;
484 	Window *children;
485 	unsigned int nchildren;
486 	if (XQueryTree(disp, window, &root, &parent, &children, &nchildren) == 0) {
487 		throwException(env, "XQueryTree failed");
488 		return None;
489 	}
490 	if (children != NULL)
491 		XFree(children);
492 
493 	return nchildren;
494 }
495 
Java_org_lwjgl_opengl_LinuxDisplay_hasProperty(JNIEnv * env,jclass unusued,jlong display,jlong window_ptr,jlong property_ptr)496 JNIEXPORT jboolean JNICALL Java_org_lwjgl_opengl_LinuxDisplay_hasProperty(JNIEnv *env, jclass unusued, jlong display, jlong window_ptr, jlong property_ptr) {
497 	Display *disp = (Display *)(intptr_t)display;
498 	Window window = (Window)window_ptr;
499 	Atom property = (Atom)property_ptr;
500 	int num_props;
501 	Atom *properties = XListProperties(disp, window, &num_props);
502 	if (properties == NULL)
503 		return JNI_FALSE;
504 	jboolean result = JNI_FALSE;
505 	for (int i = 0; i < num_props; i++) {
506 		if (properties[i] == property) {
507 			result = JNI_TRUE;
508 			break;
509 		}
510 	}
511 	XFree(properties);
512 	return result;
513 }
514 
Java_org_lwjgl_opengl_LinuxDisplay_nGetInputFocus(JNIEnv * env,jclass unused,jlong display_ptr)515 JNIEXPORT jlong JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nGetInputFocus(JNIEnv *env, jclass unused, jlong display_ptr) {
516 	Display *disp = (Display *)(intptr_t)display_ptr;
517 	int revert_mode;
518 	Window win;
519 	XGetInputFocus(disp, &win, &revert_mode);
520 	return win;
521 }
522 
Java_org_lwjgl_opengl_LinuxDisplay_nSetInputFocus(JNIEnv * env,jclass clazz,jlong display,jlong window_ptr,jlong time)523 JNIEXPORT void JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nSetInputFocus(JNIEnv *env, jclass clazz, jlong display, jlong window_ptr, jlong time) {
524 	Display *disp = (Display *)(intptr_t)display;
525 	Window window = (Window)window_ptr;
526 	XSetInputFocus(disp, window, RevertToParent, time);
527 }
528 
Java_org_lwjgl_opengl_LinuxDisplay_nCreateWindow(JNIEnv * env,jclass clazz,jlong display,jint screen,jobject peer_info_handle,jobject mode,jint window_mode,jint x,jint y,jboolean undecorated,jlong parent_handle,jboolean resizable)529 JNIEXPORT jlong JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nCreateWindow(JNIEnv *env, jclass clazz, jlong display, jint screen, jobject peer_info_handle, jobject mode, jint window_mode, jint x, jint y, jboolean undecorated, jlong parent_handle, jboolean resizable) {
530 	Display *disp = (Display *)(intptr_t)display;
531 	X11PeerInfo *peer_info = (*env)->GetDirectBufferAddress(env, peer_info_handle);
532 	GLXFBConfig *fb_config = NULL;
533 	if (peer_info->glx13) {
534 		fb_config = getFBConfigFromPeerInfo(env, peer_info);
535 		if (fb_config == NULL)
536 			return 0;
537 	}
538 	jclass cls_displayMode = (*env)->GetObjectClass(env, mode);
539 	jfieldID fid_width = (*env)->GetFieldID(env, cls_displayMode, "width", "I");
540 	jfieldID fid_height = (*env)->GetFieldID(env, cls_displayMode, "height", "I");
541 	int width = (*env)->GetIntField(env, mode, fid_width);
542 	int height = (*env)->GetIntField(env, mode, fid_height);
543 	Window win = createWindow(env, disp, screen, window_mode, peer_info, x, y, width, height, undecorated, parent_handle, resizable);
544 	if ((*env)->ExceptionOccurred(env)) {
545 		return 0;
546 	}
547 	if (peer_info->glx13) {
548 		glx_window = lwjgl_glXCreateWindow(disp, *fb_config, win, NULL);
549 		XFree(fb_config);
550 	}
551 	if (!checkXError(env, disp)) {
552 		lwjgl_glXDestroyWindow(disp, glx_window);
553 		destroyWindow(env, disp, win);
554 	}
555 	return win;
556 }
557 
Java_org_lwjgl_opengl_LinuxDisplay_nSetWindowSize(JNIEnv * env,jclass clazz,jlong display,jlong window_ptr,jint width,jint height,jboolean resizable)558 JNIEXPORT void JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nSetWindowSize(JNIEnv *env, jclass clazz, jlong display, jlong window_ptr, jint width, jint height, jboolean resizable) {
559 	Display *disp = (Display *)(intptr_t)display;
560 	Window win = (Window)window_ptr;
561 	updateWindowBounds(disp, win, 0, 0, width, height, JNI_FALSE, resizable);
562 }
563 
Java_org_lwjgl_opengl_LinuxDisplay_nDestroyWindow(JNIEnv * env,jclass clazz,jlong display,jlong window_ptr)564 JNIEXPORT void JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nDestroyWindow(JNIEnv *env, jclass clazz, jlong display, jlong window_ptr) {
565 	Display *disp = (Display *)(intptr_t)display;
566 	Window window = (Window)window_ptr;
567 	destroyWindow(env, disp, window);
568 }
569 
Java_org_lwjgl_opengl_LinuxDisplay_nLockAWT(JNIEnv * env,jclass clazz)570 JNIEXPORT void JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nLockAWT(JNIEnv *env, jclass clazz) {
571 	JAWT jawt;
572 	jawt.version = JAWT_VERSION_1_4;
573 	if (JAWT_GetAWT(env, &jawt) != JNI_TRUE) {
574 		throwException(env, "GetAWT failed");
575 		return;
576 	}
577 	jawt.Lock(env);
578 }
579 
Java_org_lwjgl_opengl_LinuxDisplay_nUnlockAWT(JNIEnv * env,jclass clazz)580 JNIEXPORT void JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nUnlockAWT(JNIEnv *env, jclass clazz) {
581 	JAWT jawt;
582 	jawt.version = JAWT_VERSION_1_4;
583 	if (JAWT_GetAWT(env, &jawt) != JNI_TRUE) {
584 		throwException(env, "GetAWT failed");
585 		return;
586 	}
587 	jawt.Unlock(env);
588 }
589 
Java_org_lwjgl_opengl_LinuxDisplay_nSetWindowIcon(JNIEnv * env,jclass clazz,jlong display,jlong window_ptr,jobject icons_buffer,jint icons_buffer_size)590 JNIEXPORT void JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nSetWindowIcon
591   (JNIEnv *env, jclass clazz, jlong display, jlong window_ptr, jobject icons_buffer, jint icons_buffer_size)
592 {
593 	Display *disp = (Display *)(intptr_t)display;
594 	Window window = (Window)window_ptr;
595 	const unsigned char *icons_char_buffer = (const unsigned char *)(*env)->GetDirectBufferAddress(env, icons_buffer);
596 
597 	int length = icons_buffer_size/4;
598 	unsigned long icons_long_buffer[length];
599 	int i = 0;
600 
601 	// copy byte array to long array
602 	for (i = 0; i < icons_buffer_size; i += 4) {
603 		unsigned long argb = (icons_char_buffer[i] << 24) |
604 							(icons_char_buffer[i+1] << 16) |
605 							(icons_char_buffer[i+2] << 8) |
606 							(icons_char_buffer[i+3]);
607 		icons_long_buffer[i/4] = argb;
608 	}
609 
610 	XChangeProperty(disp, window,
611 					XInternAtom(disp, "_NET_WM_ICON", False),
612 					XInternAtom(disp, "CARDINAL", False),
613 					32, PropModeReplace, (const unsigned char*) icons_long_buffer, length);
614 }
615 
Java_org_lwjgl_opengl_LinuxDisplay_nUngrabKeyboard(JNIEnv * env,jclass unused,jlong display_ptr)616 JNIEXPORT jint JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nUngrabKeyboard(JNIEnv *env, jclass unused, jlong display_ptr) {
617 	Display *disp = (Display *)(intptr_t)display_ptr;
618 	return XUngrabKeyboard(disp, CurrentTime);
619 }
620 
Java_org_lwjgl_opengl_LinuxDisplay_nGrabKeyboard(JNIEnv * env,jclass unused,jlong display_ptr,jlong window_ptr)621 JNIEXPORT jint JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nGrabKeyboard(JNIEnv *env, jclass unused, jlong display_ptr, jlong window_ptr) {
622 	Display *disp = (Display *)(intptr_t)display_ptr;
623 	Window win = (Window)window_ptr;
624 	return XGrabKeyboard(disp, win, False, GrabModeAsync, GrabModeAsync, CurrentTime);
625 }
626 
Java_org_lwjgl_opengl_LinuxDisplay_nGrabPointer(JNIEnv * env,jclass unused,jlong display_ptr,jlong window_ptr,jlong cursor_ptr)627 JNIEXPORT jint JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nGrabPointer(JNIEnv *env, jclass unused, jlong display_ptr, jlong window_ptr, jlong cursor_ptr) {
628 	Display *disp = (Display *)(intptr_t)display_ptr;
629 	Window win = (Window)window_ptr;
630 	Cursor cursor = (Cursor)cursor_ptr;
631 	int grab_mask = PointerMotionMask | ButtonPressMask | ButtonReleaseMask;
632 	return XGrabPointer(disp, win, False, grab_mask, GrabModeAsync, GrabModeAsync, win, cursor, CurrentTime);
633 }
634 
Java_org_lwjgl_opengl_LinuxDisplay_nSetViewPort(JNIEnv * env,jclass unused,jlong display_ptr,jlong window_ptr,jint screen)635 JNIEXPORT void JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nSetViewPort(JNIEnv *env, jclass unused, jlong display_ptr, jlong window_ptr, jint screen) {
636 	Display *disp = (Display *)(intptr_t)display_ptr;
637 	Window win = (Window)window_ptr;
638 	XWindowAttributes win_attribs;
639 
640 	XGetWindowAttributes(disp, win, &win_attribs);
641 	XF86VidModeSetViewPort(disp, screen, win_attribs.x, win_attribs.y);
642 }
643 
Java_org_lwjgl_opengl_LinuxDisplay_nUngrabPointer(JNIEnv * env,jclass unused,jlong display_ptr)644 JNIEXPORT jint JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nUngrabPointer(JNIEnv *env, jclass unused, jlong display_ptr) {
645 	Display *disp = (Display *)(intptr_t)display_ptr;
646 	return XUngrabPointer(disp, CurrentTime);
647 }
648 
Java_org_lwjgl_opengl_LinuxDisplay_nDefineCursor(JNIEnv * env,jclass unused,jlong display_ptr,jlong window_ptr,jlong cursor_ptr)649 JNIEXPORT void JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nDefineCursor(JNIEnv *env, jclass unused, jlong display_ptr, jlong window_ptr, jlong cursor_ptr) {
650 	Display *disp = (Display *)(intptr_t)display_ptr;
651 	Window win = (Window)window_ptr;
652 	Cursor cursor = (Cursor)cursor_ptr;
653 	XDefineCursor(disp, win, cursor);
654 }
655 
Java_org_lwjgl_opengl_LinuxDisplay_nCreateBlankCursor(JNIEnv * env,jclass unused,jlong display_ptr,jlong window_ptr)656 JNIEXPORT jlong JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nCreateBlankCursor(JNIEnv *env, jclass unused, jlong display_ptr, jlong window_ptr) {
657 	Display *disp = (Display *)(intptr_t)display_ptr;
658 	Window win = (Window)window_ptr;
659 	unsigned int best_width, best_height;
660 	if (XQueryBestCursor(disp, win, 1, 1, &best_width, &best_height) == 0) {
661 		throwException(env, "Could not query best cursor size");
662 		return false;
663 	}
664 	Pixmap mask = XCreatePixmap(disp, win, best_width, best_height, 1);
665 	XGCValues gc_values;
666 	gc_values.foreground = 0;
667 	GC gc = XCreateGC(disp, mask, GCForeground, &gc_values);
668 	XFillRectangle(disp, mask, gc, 0, 0, best_width, best_height);
669 	XFreeGC(disp, gc);
670 	XColor dummy_color;
671 	Cursor cursor = XCreatePixmapCursor(disp, mask, mask, &dummy_color, &dummy_color, 0, 0);
672 	XFreePixmap(disp, mask);
673 	return cursor;
674 }
675 
Java_org_lwjgl_opengl_LinuxDisplay_nIconifyWindow(JNIEnv * env,jclass unused,jlong display_ptr,jlong window_ptr,jint screen)676 JNIEXPORT void JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nIconifyWindow(JNIEnv *env, jclass unused, jlong display_ptr, jlong window_ptr, jint screen) {
677 	Display *disp = (Display *)(intptr_t)display_ptr;
678 	Window win = (Window)window_ptr;
679 	XIconifyWindow(disp, win, screen);
680 }
681