1 // Copyright (C)2004 Landmark Graphics Corporation
2 // Copyright (C)2005, 2006 Sun Microsystems, Inc.
3 // Copyright (C)2009, 2011-2016, 2018-2021 D. R. Commander
4 //
5 // This library is free software and may be redistributed and/or modified under
6 // the terms of the wxWindows Library License, Version 3.1 or (at your option)
7 // any later version.  The full license is in the LICENSE.txt file included
8 // with this distribution.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // wxWindows Library License for more details.
14 
15 #include "PixmapHash.h"
16 #include "VisualHash.h"
17 #include "WindowHash.h"
18 #include "faker.h"
19 #include "vglconfigLauncher.h"
20 #ifdef FAKEXCB
21 #include "XCBConnHash.h"
22 #endif
23 #include "keycodetokeysym.h"
24 
25 
26 // Interposed X11 functions
27 
28 
29 extern "C" {
30 
31 // XCloseDisplay() implicitly closes all windows and subwindows that were
32 // attached to the display handle, so we have to make sure that the
33 // corresponding VirtualWin instances are shut down.
34 
XCloseDisplay(Display * dpy)35 int XCloseDisplay(Display *dpy)
36 {
37 	// MainWin calls various X11 functions from the destructor of one of its
38 	// shared libraries, which is executed after the VirtualGL Faker has shut
39 	// down, so we cannot access fconfig or vglout or winh without causing
40 	// deadlocks or other issues.  At this point, all we can safely do is hand
41 	// off to libX11.
42 	if(vglfaker::deadYet || vglfaker::getFakerLevel() > 0)
43 		return _XCloseDisplay(dpy);
44 
45 	int retval = 0;
46 	TRY();
47 
48 		OPENTRACE(XCloseDisplay);  PRARGD(dpy);  STARTTRACE();
49 
50 	DISABLE_FAKER();
51 
52 	#ifdef FAKEXCB
53 	if(fconfig.fakeXCB)
54 	{
55 		CHECKSYM_NONFATAL(XGetXCBConnection)
56 		if(!__XGetXCBConnection)
57 		{
58 			if(fconfig.verbose)
59 				vglout.print("[VGL] Disabling XCB interposer\n");
60 			fconfig.fakeXCB = 0;
61 		}
62 		else
63 		{
64 			xcb_connection_t *conn = _XGetXCBConnection(dpy);
65 			xcbconnhash.remove(conn);
66 		}
67 	}
68 	#endif
69 
70 	winhash.remove(dpy);
71 	retval = _XCloseDisplay(dpy);
72 
73 		STOPTRACE();  CLOSETRACE();
74 
75 	CATCH();
76 	ENABLE_FAKER();
77 	return retval;
78 }
79 
80 
81 // We have to override this function in order to handle GLX pixmap rendering
82 
XCopyArea(Display * dpy,Drawable src,Drawable dst,GC gc,int src_x,int src_y,unsigned int width,unsigned int height,int dest_x,int dest_y)83 int XCopyArea(Display *dpy, Drawable src, Drawable dst, GC gc, int src_x,
84 	int src_y, unsigned int width, unsigned int height, int dest_x, int dest_y)
85 {
86 	TRY();
87 
88 	if(IS_EXCLUDED(dpy))
89 		return _XCopyArea(dpy, src, dst, gc, src_x, src_y, width, height, dest_x,
90 			dest_y);
91 
92 	DISABLE_FAKER();
93 
94 	vglfaker::VirtualDrawable *srcVW = NULL, *dstVW = NULL;
95 	bool srcWin = false, dstWin = false;
96 	bool copy2d = true, copy3d = false, triggerRB = false;
97 	GLXDrawable glxsrc = 0, glxdst = 0;
98 
99 	if(src == 0 || dst == 0) return BadDrawable;
100 
101 		OPENTRACE(XCopyArea);  PRARGD(dpy);  PRARGX(src);  PRARGX(dst);
102 		PRARGX(gc);  PRARGI(src_x);  PRARGI(src_y);  PRARGI(width);
103 		PRARGI(height);  PRARGI(dest_x);  PRARGI(dest_y);  STARTTRACE();
104 
105 	if(!(srcVW = (vglfaker::VirtualDrawable *)pmhash.find(dpy, src)))
106 	{
107 		srcVW = (vglfaker::VirtualDrawable *)winhash.find(dpy, src);
108 		if(srcVW) srcWin = true;
109 	}
110 	if(srcVW && !srcVW->isInit())
111 	{
112 		// If the 3D drawable hasn't been made current yet, then its contents will
113 		// be identical to the corresponding 2D drawable
114 		srcVW = NULL;
115 		srcWin = false;
116 	}
117 	if(!(dstVW = (vglfaker::VirtualDrawable *)pmhash.find(dpy, dst)))
118 	{
119 		dstVW = (vglfaker::VirtualDrawable *)winhash.find(dpy, dst);
120 		if(dstVW) dstWin = true;
121 	}
122 	if(dstVW && !dstVW->isInit())
123 	{
124 		dstVW = NULL;
125 		dstWin = false;
126 	}
127 
128 	// GLX (3D) Pixmap --> non-GLX (2D) drawable
129 	// Sync pixels from the 3D pixmap (on the 3D X Server) to the corresponding
130 	// 2D pixmap (on the 2D X Server) and let the "real" XCopyArea() do the rest.
131 	if(srcVW && !srcWin && !dstVW)
132 		((vglfaker::VirtualPixmap *)srcVW)->readback();
133 
134 	// non-GLX (2D) drawable --> non-GLX (2D) drawable
135 	// Source and destination are not backed by a drawable on the 3D X Server, so
136 	// defer to the real XCopyArea() function.
137 	//
138 	// non-GLX (2D) drawable --> GLX (3D) drawable
139 	// We don't really handle this yet (and won't until we have to.)  Copy to the
140 	// 2D destination drawable only, without updating the corresponding 3D
141 	// drawable.
142 	//
143 	// GLX (3D) Window --> non-GLX (2D) drawable
144 	// We assume that glFinish() or another frame trigger function has been
145 	// called prior to XCopyArea(), in order to copy the rendered frame from the
146 	// off-screen drawable on the 3D X Server to the corresponding window on the
147 	// 2D X Server.  Thus, we defer to the real XCopyArea() function (but this
148 	// may not work properly without VGL_SYNC=1.)
149 	{}
150 
151 	// GLX (3D) Window --> GLX (3D) drawable
152 	// GLX (3D) Pixmap --> GLX (3D) Pixmap
153 	// Sync both 2D and 3D pixels.
154 	if(srcVW && srcWin && dstVW) copy3d = true;
155 	if(srcVW && !srcWin && dstVW && !dstWin) copy3d = true;
156 
157 	// GLX (3D) Pixmap --> GLX (3D) Window
158 	// Copy rendered frame to the window's corresponding off-screen drawable,
159 	// then trigger a readback to transport the frame from the off-screen
160 	// drawable to the window.
161 	if(srcVW && !srcWin && dstVW && dstWin)
162 	{
163 		copy2d = false;  copy3d = true;  triggerRB = true;
164 	}
165 
166 	if(copy2d)
167 		_XCopyArea(dpy, src, dst, gc, src_x, src_y, width, height, dest_x, dest_y);
168 
169 	if(copy3d)
170 	{
171 		glxsrc = srcVW->getGLXDrawable();
172 		glxdst = dstVW->getGLXDrawable();
173 		srcVW->copyPixels(src_x, src_y, width, height, dest_x, dest_y, glxdst);
174 		if(triggerRB)
175 			((vglfaker::VirtualWin *)dstVW)->readback(GL_FRONT, false, fconfig.sync);
176 	}
177 
178 		STOPTRACE();  if(copy3d) PRARGX(glxsrc);  if(copy3d) PRARGX(glxdst);
179 		CLOSETRACE();
180 
181 	CATCH();
182 	ENABLE_FAKER();
183 	return 0;
184 }
185 
186 
187 // When a window is created, add it to the hash.  A VirtualWin instance does
188 // not get created and hashed to the window until/unless the window is made
189 // current in OpenGL.
190 
XCreateSimpleWindow(Display * dpy,Window parent,int x,int y,unsigned int width,unsigned int height,unsigned int border_width,unsigned long border,unsigned long background)191 Window XCreateSimpleWindow(Display *dpy, Window parent, int x, int y,
192 	unsigned int width, unsigned int height, unsigned int border_width,
193 	unsigned long border, unsigned long background)
194 {
195 	Window win = 0;
196 	TRY();
197 
198 	if(IS_EXCLUDED(dpy))
199 		return _XCreateSimpleWindow(dpy, parent, x, y, width, height, border_width,
200 			border, background);
201 
202 		OPENTRACE(XCreateSimpleWindow);  PRARGD(dpy);  PRARGX(parent);  PRARGI(x);
203 		PRARGI(y);  PRARGI(width);  PRARGI(height);  STARTTRACE();
204 
205 	win = _XCreateSimpleWindow(dpy, parent, x, y, width, height, border_width,
206 		border, background);
207 	if(win) winhash.add(dpy, win);
208 
209 		STOPTRACE();  PRARGX(win);  CLOSETRACE();
210 
211 	CATCH();
212 	return win;
213 }
214 
215 
XCreateWindow(Display * dpy,Window parent,int x,int y,unsigned int width,unsigned int height,unsigned int border_width,int depth,unsigned int c_class,Visual * visual,unsigned long valuemask,XSetWindowAttributes * attributes)216 Window XCreateWindow(Display *dpy, Window parent, int x, int y,
217 	unsigned int width, unsigned int height, unsigned int border_width,
218 	int depth, unsigned int c_class, Visual *visual, unsigned long valuemask,
219 	XSetWindowAttributes *attributes)
220 {
221 	Window win = 0;
222 	TRY();
223 
224 	if(IS_EXCLUDED(dpy))
225 		return _XCreateWindow(dpy, parent, x, y, width, height, border_width,
226 			depth, c_class, visual, valuemask, attributes);
227 
228 		OPENTRACE(XCreateWindow);  PRARGD(dpy);  PRARGX(parent);  PRARGI(x);
229 		PRARGI(y);  PRARGI(width);  PRARGI(height);  PRARGI(depth);
230 		PRARGI(c_class);  PRARGV(visual);  STARTTRACE();
231 
232 	win = _XCreateWindow(dpy, parent, x, y, width, height, border_width, depth,
233 		c_class, visual, valuemask, attributes);
234 	if(win) winhash.add(dpy, win);
235 
236 		STOPTRACE();  PRARGX(win);  CLOSETRACE();
237 
238 	CATCH();
239 	return win;
240 }
241 
242 
243 // When a window is destroyed, we shut down the corresponding VirtualWin
244 // instance, but we also have to walk the window tree to ensure that VirtualWin
245 // instances attached to subwindows are also shut down.
246 
DeleteWindow(Display * dpy,Window win,bool subOnly=false)247 static void DeleteWindow(Display *dpy, Window win, bool subOnly = false)
248 {
249 	Window root, parent, *children = NULL;  unsigned int n = 0;
250 
251 	if(!subOnly) winhash.remove(dpy, win);
252 	if(XQueryTree(dpy, win, &root, &parent, &children, &n)
253 		&& children && n > 0)
254 	{
255 		for(unsigned int i = 0; i < n; i++) DeleteWindow(dpy, children[i]);
256 		_XFree(children);
257 	}
258 }
259 
260 
XDestroySubwindows(Display * dpy,Window win)261 int XDestroySubwindows(Display *dpy, Window win)
262 {
263 	int retval = 0;
264 	TRY();
265 
266 	if(IS_EXCLUDED(dpy))
267 		return _XDestroySubwindows(dpy, win);
268 
269 		OPENTRACE(XDestroySubwindows);  PRARGD(dpy);  PRARGX(win);  STARTTRACE();
270 
271 	DISABLE_FAKER();
272 
273 	if(dpy && win) DeleteWindow(dpy, win, true);
274 	retval = _XDestroySubwindows(dpy, win);
275 
276 		STOPTRACE();  CLOSETRACE();
277 
278 	CATCH();
279 	ENABLE_FAKER();
280 	return retval;
281 }
282 
283 
XDestroyWindow(Display * dpy,Window win)284 int XDestroyWindow(Display *dpy, Window win)
285 {
286 	int retval = 0;
287 	TRY();
288 
289 	if(IS_EXCLUDED(dpy))
290 		return _XDestroyWindow(dpy, win);
291 
292 		OPENTRACE(XDestroyWindow);  PRARGD(dpy);  PRARGX(win);  STARTTRACE();
293 
294 	DISABLE_FAKER();
295 
296 	if(dpy && win) DeleteWindow(dpy, win);
297 	retval = _XDestroyWindow(dpy, win);
298 
299 		STOPTRACE();  CLOSETRACE();
300 
301 	CATCH();
302 	ENABLE_FAKER();
303 	return retval;
304 }
305 
306 
307 // If we're freeing a visual that is hashed to an FB config, then remove the
308 // corresponding hash entry.
309 
XFree(void * data)310 int XFree(void *data)
311 {
312 	int ret = 0;
313 	TRY();
314 	ret = _XFree(data);
315 	if(data && !vglfaker::deadYet) vishash.remove(NULL, (XVisualInfo *)data);
316 	CATCH();
317 	return ret;
318 }
319 
320 
321 // Chromium is mainly to blame for this one.  Since it is using separate
322 // processes to do 3D and X11 rendering, the 3D process will call
323 // XGetGeometry() repeatedly to obtain the window size, and since the 3D
324 // process has no X event loop, monitoring this function is the only way for
325 // VirtualGL to know that the window size has changed.
326 
XGetGeometry(Display * dpy,Drawable drawable,Window * root,int * x,int * y,unsigned int * width_return,unsigned int * height_return,unsigned int * border_width,unsigned int * depth)327 Status XGetGeometry(Display *dpy, Drawable drawable, Window *root, int *x,
328 	int *y, unsigned int *width_return, unsigned int *height_return,
329 	unsigned int *border_width, unsigned int *depth)
330 {
331 	Status ret = 0;
332 	unsigned int width = 0, height = 0;
333 	TRY();
334 
335 	if(IS_EXCLUDED(dpy))
336 		return _XGetGeometry(dpy, drawable, root, x, y, width_return,
337 			height_return, border_width, depth);
338 
339 		OPENTRACE(XGetGeometry);  PRARGD(dpy);  PRARGX(drawable);  STARTTRACE();
340 
341 	vglfaker::VirtualWin *vw;
342 	if((vw = winhash.find(NULL, drawable)) != NULL)
343 	{
344 		// Apparently drawable is a GLX drawable ID that backs a window, so we need
345 		// to request the geometry of the window, not the GLX drawable.  This
346 		// prevents a BadDrawable error in Steam.
347 		dpy = vw->getX11Display();
348 		drawable = vw->getX11Drawable();
349 	}
350 	ret = _XGetGeometry(dpy, drawable, root, x, y, &width, &height, border_width,
351 		depth);
352 	if((vw = winhash.find(dpy, drawable)) != NULL && width > 0 && height > 0)
353 		vw->resize(width, height);
354 
355 		STOPTRACE();  if(root) PRARGX(*root);  if(x) PRARGI(*x);  if(y) PRARGI(*y);
356 		PRARGI(width);  PRARGI(height);  if(border_width) PRARGI(*border_width);
357 		if(depth) PRARGI(*depth);  CLOSETRACE();
358 
359 	if(width_return) *width_return = width;
360 	if(height_return) *height_return = height;
361 
362 	CATCH();
363 	return ret;
364 }
365 
366 
367 // If the pixmap has been used for 3D rendering, then we have to synchronize
368 // the contents of the 3D pixmap, which resides on the 3D X server, with the
369 // 2D pixmap on the 2D X server before calling the "real" XGetImage() function.
370 
XGetImage(Display * dpy,Drawable drawable,int x,int y,unsigned int width,unsigned int height,unsigned long plane_mask,int format)371 XImage *XGetImage(Display *dpy, Drawable drawable, int x, int y,
372 	unsigned int width, unsigned int height, unsigned long plane_mask,
373 	int format)
374 {
375 	XImage *xi = NULL;
376 	TRY();
377 
378 	if(IS_EXCLUDED(dpy))
379 		return _XGetImage(dpy, drawable, x, y, width, height, plane_mask, format);
380 
381 		OPENTRACE(XGetImage);  PRARGD(dpy);  PRARGX(drawable);  PRARGI(x);
382 		PRARGI(y);  PRARGI(width);  PRARGI(height);  PRARGX(plane_mask);
383 		PRARGI(format);  STARTTRACE();
384 
385 	DISABLE_FAKER();
386 
387 	vglfaker::VirtualPixmap *vpm = pmhash.find(dpy, drawable);
388 	if(vpm) vpm->readback();
389 
390 	xi = _XGetImage(dpy, drawable, x, y, width, height, plane_mask, format);
391 
392 		STOPTRACE();  CLOSETRACE();
393 
394 	CATCH();
395 	ENABLE_FAKER();
396 	return xi;
397 }
398 
399 
400 // Tell the application that the GLX extension is present, even if it isn't
401 
XListExtensions(Display * dpy,int * next)402 char **XListExtensions(Display *dpy, int *next)
403 {
404 	char **list = NULL, *listStr = NULL;  int n, i;
405 	int hasGLX = 0, listLen = 0;
406 
407 	TRY();
408 
409 	if(IS_EXCLUDED(dpy))
410 		return _XListExtensions(dpy, next);
411 
412 		OPENTRACE(XListExtensions);  PRARGD(dpy);  STARTTRACE();
413 
414 	list = _XListExtensions(dpy, &n);
415 	if(list && n > 0)
416 	{
417 		for(i = 0; i < n; i++)
418 		{
419 			if(list[i])
420 			{
421 				listLen += strlen(list[i]) + 1;
422 				if(!strcmp(list[i], "GLX")) hasGLX = 1;
423 			}
424 		}
425 	}
426 	if(!hasGLX)
427 	{
428 		char **newList = NULL;  int index = 0;
429 		listLen += 4;  // "GLX" + terminating NULL
430 		ERRIFNOT(newList = (char **)malloc(sizeof(char *) * (n + 1)))
431 		ERRIFNOT(listStr = (char *)malloc(listLen + 1))
432 		memset(listStr, 0, listLen + 1);
433 		listStr = &listStr[1];  // For compatibility with X.org implementation
434 		if(list && n > 0)
435 		{
436 			for(i = 0; i < n; i++)
437 			{
438 				newList[i] = &listStr[index];
439 				if(list[i])
440 				{
441 					memcpy(newList[i], list[i], strlen(list[i]));
442 					index += strlen(list[i]);
443 					listStr[index] = '\0';  index++;
444 				}
445 			}
446 			XFreeExtensionList(list);
447 		}
448 		newList[n] = &listStr[index];
449 		memcpy(newList[n], "GLX", 3);  newList[n][3] = '\0';
450 		list = newList;  n++;
451 	}
452 
453 		STOPTRACE();  PRARGI(n);  CLOSETRACE();
454 
455 	CATCH();
456 
457 	if(next) *next = n;
458 	return list;
459 }
460 
461 
setupXDisplay(Display * dpy)462 static void setupXDisplay(Display *dpy)
463 {
464 	XExtCodes *codes;
465 	XEDataObject obj = { dpy };
466 	XExtData *extData;
467 	bool excludeDisplay = vglfaker::isDisplayStringExcluded(DisplayString(dpy));
468 
469 	// Extension code 1 stores the excluded status for a Display.
470 	if(!(codes = XAddExtension(dpy))
471 		|| !(extData = (XExtData *)calloc(1, sizeof(XExtData)))
472 		|| !(extData->private_data = (XPointer)malloc(sizeof(bool))))
473 		THROW("Memory allocation error");
474 	*(bool *)extData->private_data = excludeDisplay;
475 	extData->number = codes->extension;
476 	XAddToExtensionList(XEHeadOfExtensionList(obj), extData);
477 
478 	// Extension code 2 stores the mutex for a Display.
479 	if(!(codes = XAddExtension(dpy))
480 		|| !(extData = (XExtData *)calloc(1, sizeof(XExtData))))
481 		THROW("Memory allocation error");
482 	extData->private_data = (XPointer)(new vglutil::CriticalSection());
483 	extData->number = codes->extension;
484 	extData->free_private = vglfaker::deleteCS;
485 	XAddToExtensionList(XEHeadOfExtensionList(obj), extData);
486 
487 	// Extension code 3 stores the visual attribute table for a Screen.
488 	if(!(codes = XAddExtension(dpy)))
489 		THROW("Memory allocation error");
490 
491 	// Extension code 4 stores the FB config attribute table for a Screen.
492 	if(!(codes = XAddExtension(dpy)))
493 		THROW("Memory allocation error");
494 
495 	#ifdef EGLBACKEND
496 	// Extension code 5 stores the RBO context instance for a Display
497 	if(!(codes = XAddExtension(dpy))
498 		|| !(extData = (XExtData *)calloc(1, sizeof(XExtData))))
499 		THROW("Memory allocation error");
500 	extData->private_data = (XPointer)(new vglfaker::EGLRBOContext());
501 	extData->number = 5;
502 	extData->free_private = vglfaker::deleteRBOContext;
503 	XAddToExtensionList(XEHeadOfExtensionList(obj), extData);
504 	#endif
505 
506 	if(!excludeDisplay && strlen(fconfig.vendor) > 0)
507 	{
508 		// Danger, Will Robinson!  We do this to prevent a small memory leak, but
509 		// we can only can get away with it because we know that Xlib dynamically
510 		// allocates the vendor string.  Xlib has done so for as long as VirtualGL
511 		// has been around, so it seems like a safe assumption.
512 		_XFree(ServerVendor(dpy));
513 		ServerVendor(dpy) = strdup(fconfig.vendor);
514 	}
515 }
516 
517 
518 // This is normally where VirtualGL initializes, unless a GLX function is
519 // called first.
520 
XOpenDisplay(_Xconst char * name)521 Display *XOpenDisplay(_Xconst char *name)
522 {
523 	Display *dpy = NULL;
524 
525 	TRY();
526 
527 	if(vglfaker::deadYet || vglfaker::getFakerLevel() > 0)
528 		return _XOpenDisplay(name);
529 
530 	vglfaker::init();
531 
532 		OPENTRACE(XOpenDisplay);  PRARGS(name);  STARTTRACE();
533 
534 	dpy = _XOpenDisplay(name);
535 	if(dpy) setupXDisplay(dpy);
536 
537 		STOPTRACE();  PRARGD(dpy);  CLOSETRACE();
538 
539 	CATCH();
540 	return dpy;
541 }
542 
543 
544 // XkbOpenDisplay() calls XOpenDisplay(), but since that function call occurs
545 // within libX11, VirtualGL cannot intercept it on some platforms.  Thus we
546 // need to interpose XkbOpenDisplay().
547 
XkbOpenDisplay(char * display_name,int * event_rtrn,int * error_rtrn,int * major_in_out,int * minor_in_out,int * reason_rtrn)548 Display *XkbOpenDisplay(char *display_name, int *event_rtrn, int *error_rtrn,
549 	int *major_in_out, int *minor_in_out, int *reason_rtrn)
550 {
551 	Display *dpy = NULL;
552 
553 	TRY();
554 
555 	if(vglfaker::deadYet || vglfaker::getFakerLevel() > 0)
556 		return _XkbOpenDisplay(display_name, event_rtrn, error_rtrn, major_in_out,
557 			minor_in_out, reason_rtrn);
558 
559 	vglfaker::init();
560 
561 		OPENTRACE(XkbOpenDisplay);  PRARGS(display_name);  STARTTRACE();
562 
563 	dpy = _XkbOpenDisplay(display_name, event_rtrn, error_rtrn, major_in_out,
564 		minor_in_out, reason_rtrn);
565 	if(dpy) setupXDisplay(dpy);
566 
567 		STOPTRACE();  PRARGD(dpy);  if(event_rtrn) PRARGI(*event_rtrn);
568 		if(error_rtrn) PRARGI(*error_rtrn);
569 		if(major_in_out) PRARGI(*major_in_out);
570 		if(minor_in_out) PRARGI(*minor_in_out);
571 		if(reason_rtrn) PRARGI(*reason_rtrn);  CLOSETRACE();
572 
573 	CATCH();
574 	return dpy;
575 }
576 
577 
578 // Tell the application that the GLX extension is present, even if it isn't.
579 
XQueryExtension(Display * dpy,_Xconst char * name,int * major_opcode,int * first_event,int * first_error)580 Bool XQueryExtension(Display *dpy, _Xconst char *name, int *major_opcode,
581 	int *first_event, int *first_error)
582 {
583 	Bool retval = True;
584 
585 	TRY();
586 
587 	if(IS_EXCLUDED(dpy))
588 		return _XQueryExtension(dpy, name, major_opcode, first_event, first_error);
589 
590 		OPENTRACE(XQueryExtension);  PRARGD(dpy);  PRARGS(name);  STARTTRACE();
591 
592 	if(!strcmp(name, "GLX"))
593 		retval = VGLQueryExtension(dpy, major_opcode, first_event, first_error);
594 	else
595 		retval = _XQueryExtension(dpy, name, major_opcode, first_event,
596 			first_error);
597 
598 		STOPTRACE();  if(major_opcode) PRARGI(*major_opcode);
599 		if(first_event) PRARGI(*first_event);
600 		if(first_error) PRARGI(*first_error);  CLOSETRACE();
601 
602 	CATCH();
603 
604 	return retval;
605 }
606 
607 
608 // This was implemented because of Pro/E Wildfire v2 on SPARC.  Unless the X
609 // server vendor string was "Sun Microsystems, Inc.", it would assume a remote
610 // connection and disable OpenGL rendering.
611 
XServerVendor(Display * dpy)612 char *XServerVendor(Display *dpy)
613 {
614 	TRY();
615 
616 	if(IS_EXCLUDED(dpy) || !strlen(fconfig.vendor))
617 		return _XServerVendor(dpy);
618 	return fconfig.vendor;
619 
620 	CATCH();
621 
622 	return NULL;
623 }
624 
625 
626 // The following functions are interposed so that VirtualGL can detect window
627 // resizes, key presses (to pop up the VGL configuration dialog), and window
628 // delete events from the window manager.
629 
handleEvent(Display * dpy,XEvent * xe)630 static void handleEvent(Display *dpy, XEvent *xe)
631 {
632 	vglfaker::VirtualWin *vw;
633 
634 	if(IS_EXCLUDED(dpy))
635 		return;
636 
637 	if(xe && xe->type == ConfigureNotify)
638 	{
639 		if((vw = winhash.find(dpy, xe->xconfigure.window)) != NULL)
640 		{
641 				OPENTRACE(handleEvent);  PRARGI(xe->xconfigure.width);
642 				PRARGI(xe->xconfigure.height);  PRARGX(xe->xconfigure.window);
643 				STARTTRACE();
644 
645 			vw->resize(xe->xconfigure.width, xe->xconfigure.height);
646 
647 				STOPTRACE();  CLOSETRACE();
648 		}
649 	}
650 	else if(xe && xe->type == KeyPress)
651 	{
652 		unsigned int state2, state = (xe->xkey.state) & (~(LockMask));
653 		state2 = fconfig.guimod;
654 		if(state2 & Mod1Mask)
655 		{
656 			state2 &= (~(Mod1Mask));  state2 |= Mod2Mask;
657 		}
658 		if(fconfig.gui
659 			&& KeycodeToKeysym(dpy, xe->xkey.keycode, 0) == fconfig.guikey
660 			&& (state == fconfig.guimod || state == state2)
661 			&& fconfig_getshmid() != -1)
662 			VGLPOPUP(dpy, fconfig_getshmid());
663 	}
664 	else if(xe && xe->type == ClientMessage)
665 	{
666 		XClientMessageEvent *cme = (XClientMessageEvent *)xe;
667 		Atom protoAtom = XInternAtom(dpy, "WM_PROTOCOLS", True);
668 		Atom deleteAtom = XInternAtom(dpy, "WM_DELETE_WINDOW", True);
669 		if(protoAtom && deleteAtom && cme->message_type == protoAtom
670 			&& cme->data.l[0] == (long)deleteAtom
671 			&& (vw = winhash.find(dpy, cme->window)) != NULL)
672 			vw->wmDelete();
673 	}
674 }
675 
676 
XCheckMaskEvent(Display * dpy,long event_mask,XEvent * xe)677 Bool XCheckMaskEvent(Display *dpy, long event_mask, XEvent *xe)
678 {
679 	Bool retval = 0;
680 	TRY();
681 
682 	if((retval = _XCheckMaskEvent(dpy, event_mask, xe)) == True)
683 		handleEvent(dpy, xe);
684 
685 	CATCH();
686 	return retval;
687 }
688 
689 
XCheckTypedEvent(Display * dpy,int event_type,XEvent * xe)690 Bool XCheckTypedEvent(Display *dpy, int event_type, XEvent *xe)
691 {
692 	Bool retval = 0;
693 	TRY();
694 
695 	if((retval = _XCheckTypedEvent(dpy, event_type, xe)) == True)
696 		handleEvent(dpy, xe);
697 
698 	CATCH();
699 	return retval;
700 }
701 
702 
XCheckTypedWindowEvent(Display * dpy,Window win,int event_type,XEvent * xe)703 Bool XCheckTypedWindowEvent(Display *dpy, Window win, int event_type,
704 	XEvent *xe)
705 {
706 	Bool retval = 0;
707 	TRY();
708 
709 	if((retval = _XCheckTypedWindowEvent(dpy, win, event_type, xe)) == True)
710 		handleEvent(dpy, xe);
711 
712 	CATCH();
713 	return retval;
714 }
715 
716 
XCheckWindowEvent(Display * dpy,Window win,long event_mask,XEvent * xe)717 Bool XCheckWindowEvent(Display *dpy, Window win, long event_mask, XEvent *xe)
718 {
719 	Bool retval = 0;
720 	TRY();
721 
722 	if((retval = _XCheckWindowEvent(dpy, win, event_mask, xe)) == True)
723 		handleEvent(dpy, xe);
724 
725 	CATCH();
726 	return retval;
727 }
728 
729 
XConfigureWindow(Display * dpy,Window win,unsigned int value_mask,XWindowChanges * values)730 int XConfigureWindow(Display *dpy, Window win, unsigned int value_mask,
731 	XWindowChanges *values)
732 {
733 	int retval = 0;
734 	TRY();
735 
736 	if(IS_EXCLUDED(dpy))
737 		return _XConfigureWindow(dpy, win, value_mask, values);
738 
739 		OPENTRACE(XConfigureWindow);  PRARGD(dpy);  PRARGX(win);
740 		if(values && (value_mask & CWWidth)) { PRARGI(values->width); }
741 		if(values && (value_mask & CWHeight)) { PRARGI(values->height); }
742 		STARTTRACE();
743 
744 	vglfaker::VirtualWin *vw;
745 	if((vw = winhash.find(dpy, win)) != NULL && values)
746 		vw->resize(value_mask & CWWidth ? values->width : 0,
747 			value_mask & CWHeight ? values->height : 0);
748 	retval = _XConfigureWindow(dpy, win, value_mask, values);
749 
750 		STOPTRACE();  CLOSETRACE();
751 
752 	CATCH();
753 	return retval;
754 }
755 
756 
XMaskEvent(Display * dpy,long event_mask,XEvent * xe)757 int XMaskEvent(Display *dpy, long event_mask, XEvent *xe)
758 {
759 	int retval = 0;
760 	TRY();
761 
762 	retval = _XMaskEvent(dpy, event_mask, xe);
763 	handleEvent(dpy, xe);
764 
765 	CATCH();
766 	return retval;
767 }
768 
769 
XMoveResizeWindow(Display * dpy,Window win,int x,int y,unsigned int width,unsigned int height)770 int XMoveResizeWindow(Display *dpy, Window win, int x, int y,
771 	unsigned int width, unsigned int height)
772 {
773 	int retval = 0;
774 	TRY();
775 
776 	if(IS_EXCLUDED(dpy))
777 		return _XMoveResizeWindow(dpy, win, x, y, width, height);
778 
779 		OPENTRACE(XMoveResizeWindow);  PRARGD(dpy);  PRARGX(win);  PRARGI(x);
780 		PRARGI(y);  PRARGI(width);  PRARGI(height);  STARTTRACE();
781 
782 	vglfaker::VirtualWin *vw;
783 	if((vw = winhash.find(dpy, win)) != NULL)
784 		vw->resize(width, height);
785 	retval = _XMoveResizeWindow(dpy, win, x, y, width, height);
786 
787 		STOPTRACE();  CLOSETRACE();
788 
789 	CATCH();
790 	return retval;
791 }
792 
793 
XNextEvent(Display * dpy,XEvent * xe)794 int XNextEvent(Display *dpy, XEvent *xe)
795 {
796 	int retval = 0;
797 	TRY();
798 
799 	retval = _XNextEvent(dpy, xe);
800 	handleEvent(dpy, xe);
801 
802 	CATCH();
803 	return retval;
804 }
805 
806 
XResizeWindow(Display * dpy,Window win,unsigned int width,unsigned int height)807 int XResizeWindow(Display *dpy, Window win, unsigned int width,
808 	unsigned int height)
809 {
810 	int retval = 0;
811 	TRY();
812 
813 	if(IS_EXCLUDED(dpy))
814 		return _XResizeWindow(dpy, win, width, height);
815 
816 		OPENTRACE(XResizeWindow);  PRARGD(dpy);  PRARGX(win);  PRARGI(width);
817 		PRARGI(height);  STARTTRACE();
818 
819 	vglfaker::VirtualWin *vw;
820 	if((vw = winhash.find(dpy, win)) != NULL)
821 		vw->resize(width, height);
822 	retval = _XResizeWindow(dpy, win, width, height);
823 
824 		STOPTRACE();  CLOSETRACE();
825 
826 	CATCH();
827 	return retval;
828 }
829 
830 
XWindowEvent(Display * dpy,Window win,long event_mask,XEvent * xe)831 int XWindowEvent(Display *dpy, Window win, long event_mask, XEvent *xe)
832 {
833 	int retval = 0;
834 	TRY();
835 
836 	retval = _XWindowEvent(dpy, win, event_mask, xe);
837 	handleEvent(dpy, xe);
838 
839 	CATCH();
840 	return retval;
841 }
842 
843 
844 }  // extern "C"
845