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