]> icculus.org git repositories - divverent/darkplaces.git/blob - vid_glx.c
added cl_explosions and cl_stainmaps cvars, which will be used soon...
[divverent/darkplaces.git] / vid_glx.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 */
19
20 #include <termios.h>
21 #include <sys/ioctl.h>
22 #include <sys/stat.h>
23 #include <sys/vt.h>
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <signal.h>
27
28 #include <dlfcn.h>
29
30 #include "quakedef.h"
31
32 #include <GL/glx.h>
33
34 #include <X11/keysym.h>
35 #include <X11/cursorfont.h>
36
37 #include <X11/extensions/XShm.h>
38 #include <X11/extensions/xf86dga.h>
39 #include <X11/extensions/xf86vmode.h>
40
41 static Display *vidx11_display = NULL;
42 static int scrnum;
43 static Window win;
44 static GLXContext ctx = NULL;
45
46 #define KEY_MASK (KeyPressMask | KeyReleaseMask)
47 #define MOUSE_MASK (ButtonPressMask | ButtonReleaseMask | \
48                     PointerMotionMask | ButtonMotionMask )
49 #define X_MASK (KEY_MASK | MOUSE_MASK | VisibilityChangeMask | StructureNotifyMask )
50
51
52 viddef_t        vid;                            // global video state
53
54 static qboolean         mouse_avail = true;
55 static qboolean         mouse_active = false, usingmouse = false;
56 static float    mouse_x, mouse_y;
57 static int p_mouse_x, p_mouse_y;
58
59 cvar_t vid_dga = {CVAR_SAVE, "vid_dga", "1"};
60 cvar_t vid_dga_mouseaccel = {0, "vid_dga_mouseaccel", "1"};
61
62 qboolean vidmode_ext = false;
63
64 static int win_x, win_y;
65
66 static int scr_width, scr_height;
67
68 static XF86VidModeModeInfo **vidmodes;
69 static int num_vidmodes;
70 static qboolean vidmode_active = false;
71
72 static Visual *vidx11_visual;
73 static Colormap vidx11_colormap;
74
75 /*-----------------------------------------------------------------------*/
76
77 const char *gl_vendor;
78 const char *gl_renderer;
79 const char *gl_version;
80 const char *gl_extensions;
81
82 /*-----------------------------------------------------------------------*/
83 static int
84 XLateKey(XKeyEvent *ev)
85 {
86         int key = 0;
87         KeySym keysym;
88
89         keysym = XLookupKeysym(ev, 0);
90
91         switch(keysym)
92         {
93                 case XK_KP_Page_Up:     key = KP_PGUP; break;
94                 case XK_Page_Up:        key = K_PGUP; break;
95
96                 case XK_KP_Page_Down:   key = KP_PGDN; break;
97                 case XK_Page_Down:      key = K_PGDN; break;
98
99                 case XK_KP_Home:        key = KP_HOME; break;
100                 case XK_Home:           key = K_HOME; break;
101
102                 case XK_KP_End:         key = KP_END; break;
103                 case XK_End:            key = K_END; break;
104
105                 case XK_KP_Left:        key = KP_LEFTARROW; break;
106                 case XK_Left:           key = K_LEFTARROW; break;
107
108                 case XK_KP_Right:       key = KP_RIGHTARROW; break;
109                 case XK_Right:          key = K_RIGHTARROW; break;
110
111                 case XK_KP_Down:        key = KP_DOWNARROW; break;
112                 case XK_Down:           key = K_DOWNARROW; break;
113
114                 case XK_KP_Up:          key = KP_UPARROW; break;
115                 case XK_Up:                     key = K_UPARROW; break;
116
117                 case XK_Escape:         key = K_ESCAPE; break;
118
119                 case XK_KP_Enter:       key = KP_ENTER; break;
120                 case XK_Return:         key = K_ENTER; break;
121
122                 case XK_Tab:            key = K_TAB; break;
123
124                 case XK_F1:                     key = K_F1; break;
125                 case XK_F2:                     key = K_F2; break;
126                 case XK_F3:                     key = K_F3; break;
127                 case XK_F4:                     key = K_F4; break;
128                 case XK_F5:                     key = K_F5; break;
129                 case XK_F6:                     key = K_F6; break;
130                 case XK_F7:                     key = K_F7; break;
131                 case XK_F8:                     key = K_F8; break;
132                 case XK_F9:                     key = K_F9; break;
133                 case XK_F10:            key = K_F10; break;
134                 case XK_F11:            key = K_F11; break;
135                 case XK_F12:            key = K_F12; break;
136
137                 case XK_BackSpace:      key = K_BACKSPACE; break;
138
139                 case XK_KP_Delete:      key = KP_DEL; break;
140                 case XK_Delete:         key = K_DEL; break;
141
142                 case XK_Pause:          key = K_PAUSE; break;
143
144                 case XK_Shift_L:
145                 case XK_Shift_R:        key = K_SHIFT; break;
146
147                 case XK_Execute:
148                 case XK_Control_L:
149                 case XK_Control_R:      key = K_CTRL; break;
150
151                 case XK_Mode_switch:
152                 case XK_Alt_L:
153                 case XK_Meta_L:
154                 case XK_Alt_R:
155                 case XK_Meta_R:         key = K_ALT; break;
156
157                 case XK_Caps_Lock:      key = K_CAPSLOCK; break;
158                 case XK_KP_Begin:       key = KP_5; break;
159
160                 case XK_Insert:         key = K_INS; break;
161                 case XK_KP_Insert:      key = KP_INS; break;
162
163                 case XK_KP_Multiply:    key = KP_MULTIPLY; break;
164                 case XK_KP_Add:         key = KP_PLUS; break;
165                 case XK_KP_Subtract:    key = KP_MINUS; break;
166                 case XK_KP_Divide:      key = KP_DIVIDE; break;
167
168                 /* For Sun keyboards */
169                 case XK_F27:            key = K_HOME; break;
170                 case XK_F29:            key = K_PGUP; break;
171                 case XK_F33:            key = K_END; break;
172                 case XK_F35:            key = K_PGDN; break;
173
174                 default:
175                         if (keysym < 128)
176                         {
177                                 /* ASCII keys */
178                                 key = keysym;
179                                 if ((key >= 'A') && (key <= 'Z'))
180                                         key = key + ('a' - 'A');
181                         }
182                         break;
183         }
184
185         return key;
186 }
187
188 static Cursor CreateNullCursor(Display *display, Window root)
189 {
190         Pixmap cursormask;
191         XGCValues xgc;
192         GC gc;
193         XColor dummycolour;
194         Cursor cursor;
195
196         cursormask = XCreatePixmap(display, root, 1, 1, 1);
197         xgc.function = GXclear;
198         gc =  XCreateGC(display, cursormask, GCFunction, &xgc);
199         XFillRectangle(display, cursormask, gc, 0, 0, 1, 1);
200         dummycolour.pixel = 0;
201         dummycolour.red = 0;
202         dummycolour.flags = 04;
203         cursor = XCreatePixmapCursor(display, cursormask, cursormask, &dummycolour,&dummycolour, 0,0);
204         XFreePixmap(display,cursormask);
205         XFreeGC(display,gc);
206         return cursor;
207 }
208
209 static void install_grabs(void)
210 {
211         XWindowAttributes attribs_1;
212         XSetWindowAttributes attribs_2;
213
214         XGetWindowAttributes(vidx11_display, win, &attribs_1);
215         attribs_2.event_mask = attribs_1.your_event_mask | KEY_MASK | MOUSE_MASK;
216         XChangeWindowAttributes(vidx11_display, win, CWEventMask, &attribs_2);
217
218 // inviso cursor
219         XDefineCursor(vidx11_display, win, CreateNullCursor(vidx11_display, win));
220
221         XGrabPointer(vidx11_display, win,  True, 0, GrabModeAsync, GrabModeAsync, win, None, CurrentTime);
222
223         if (vid_dga.integer)
224         {
225                 int MajorVersion, MinorVersion;
226
227                 if (!XF86DGAQueryVersion(vidx11_display, &MajorVersion, &MinorVersion))
228                 {
229                         // unable to query, probalby not supported
230                         Con_Printf( "Failed to detect XF86DGA Mouse\n" );
231                         vid_dga.integer = 0;
232                 }
233                 else
234                 {
235                         vid_dga.integer = 1;
236                         XF86DGADirectVideo(vidx11_display, DefaultScreen(vidx11_display), XF86DGADirectMouse);
237                         XWarpPointer(vidx11_display, None, win, 0, 0, 0, 0, 0, 0);
238                 }
239         }
240         else
241                 XWarpPointer(vidx11_display, None, win, 0, 0, 0, 0, scr_width / 2, scr_height / 2);
242
243         XGrabKeyboard(vidx11_display, win, False, GrabModeAsync, GrabModeAsync, CurrentTime);
244
245         mouse_active = true;
246         mouse_x = mouse_y = 0;
247 }
248
249 static void uninstall_grabs(void)
250 {
251         if (!vidx11_display || !win)
252                 return;
253
254         if (vid_dga.integer == 1)
255                 XF86DGADirectVideo(vidx11_display, DefaultScreen(vidx11_display), 0);
256
257         XUngrabPointer(vidx11_display, CurrentTime);
258         XUngrabKeyboard(vidx11_display, CurrentTime);
259
260 // inviso cursor
261         XUndefineCursor(vidx11_display, win);
262
263         mouse_active = false;
264 }
265
266 static void HandleEvents(void)
267 {
268         XEvent event;
269         qboolean dowarp = false;
270
271         if (!vidx11_display)
272                 return;
273
274         while (XPending(vidx11_display))
275         {
276                 XNextEvent(vidx11_display, &event);
277
278                 switch (event.type)
279                 {
280                 case KeyPress:
281                 case KeyRelease:
282                         Key_Event(XLateKey(&event.xkey), event.type == KeyPress);
283                         break;
284
285                 case MotionNotify:
286                         if (usingmouse)
287                         {
288                                 if (vid_dga.integer == 1)
289                                 {
290                                         mouse_x += event.xmotion.x_root * vid_dga_mouseaccel.value;
291                                         mouse_y += event.xmotion.y_root * vid_dga_mouseaccel.value;
292                                 }
293                                 else
294                                 {
295                                         
296                                         if (!event.xmotion.send_event)
297                                         {
298                                                 mouse_x += event.xmotion.x - p_mouse_x;
299                                                 mouse_y += event.xmotion.y - p_mouse_y;
300                                                 if (abs(scr_width/2 - event.xmotion.x) > scr_width / 4 || abs(scr_height/2 - event.xmotion.y) > scr_height / 4)
301                                                         dowarp = true;
302                                         }
303                                         p_mouse_x = event.xmotion.x;
304                                         p_mouse_y = event.xmotion.y;
305                                 }
306                         }
307                         else
308                                 ui_mouseupdate(event.xmotion.x, event.xmotion.y);
309                         break;
310
311                 case ButtonPress:
312                         switch(event.xbutton.button)
313                         {
314                         case 1:
315                                 Key_Event(K_MOUSE1, true);
316                                 break;
317                         case 2:
318                                 Key_Event(K_MOUSE3, true);
319                                 break;
320                         case 3:
321                                 Key_Event(K_MOUSE2, true);
322                                 break;
323                         case 4:
324                                 Key_Event(K_MWHEELUP, true);
325                                 break;
326                         case 5:
327                                 Key_Event(K_MWHEELDOWN, true);
328                                 break;
329                 default:
330                                 Con_Printf("HandleEvents: ButtonPress gave value %d, 1-5 expected\n", event.xbutton.button);
331                                 break;
332                         }
333                         break;
334
335                 case ButtonRelease:
336                         switch(event.xbutton.button)
337                         {
338                         case 1:
339                                 Key_Event(K_MOUSE1, false);
340                                 break;
341                         case 2:
342                                 Key_Event(K_MOUSE3, false);
343                                 break;
344                         case 3:
345                                 Key_Event(K_MOUSE2, false);
346                                 break;
347                         case 4:
348                                 Key_Event(K_MWHEELUP, false);
349                                 break;
350                         case 5:
351                                 Key_Event(K_MWHEELDOWN, false);
352                                 break;
353                 default:
354                                 Con_Printf("HandleEvents: ButtonRelease gave value %d, 1-5 expected\n", event.xbutton.button);
355                                 break;
356                         }
357                         break;
358
359                 case CreateNotify :
360                         win_x = event.xcreatewindow.x;
361                         win_y = event.xcreatewindow.y;
362                         break;
363
364                 case ConfigureNotify :
365                         win_x = event.xconfigure.x;
366                         win_y = event.xconfigure.y;
367                         break;
368                 }
369         }
370
371         if (dowarp)
372         {
373                 /* move the mouse to the window center again */
374                 p_mouse_x = scr_width / 2;
375                 p_mouse_y = scr_height / 2;
376                 XWarpPointer(vidx11_display, None, win, 0, 0, 0, 0, p_mouse_x, p_mouse_y);
377         }
378
379 }
380
381 static void IN_DeactivateMouse( void )
382 {
383         if (!mouse_avail || !vidx11_display || !win)
384                 return;
385
386         if (mouse_active)
387         {
388                 uninstall_grabs();
389                 mouse_active = false;
390         }
391 }
392
393 static void IN_ActivateMouse( void )
394 {
395         if (!mouse_avail || !vidx11_display || !win)
396                 return;
397
398         if (!mouse_active)
399         {
400                 mouse_x = mouse_y = 0; // don't spazz
401                 install_grabs();
402                 mouse_active = true;
403         }
404 }
405
406
407 void VID_Shutdown(void)
408 {
409         if (!ctx || !vidx11_display)
410                 return;
411
412         if (vidx11_display)
413         {
414                 uninstall_grabs();
415
416                 if (vidmode_active)
417                         XF86VidModeSwitchToMode(vidx11_display, scrnum, vidmodes[0]);
418                 if (win)
419                         XDestroyWindow(vidx11_display, win);
420                 XCloseDisplay(vidx11_display);
421         }
422         vidmode_active = false;
423         vidx11_display = NULL;
424         win = 0;
425         ctx = NULL;
426 }
427
428 void signal_handler(int sig)
429 {
430         printf("Received signal %d, exiting...\n", sig);
431         Sys_Quit();
432         exit(0);
433 }
434
435 void InitSig(void)
436 {
437         signal(SIGHUP, signal_handler);
438         signal(SIGINT, signal_handler);
439         signal(SIGQUIT, signal_handler);
440         signal(SIGILL, signal_handler);
441         signal(SIGTRAP, signal_handler);
442         signal(SIGIOT, signal_handler);
443         signal(SIGBUS, signal_handler);
444         signal(SIGFPE, signal_handler);
445         signal(SIGSEGV, signal_handler);
446         signal(SIGTERM, signal_handler);
447 }
448
449 /*
450 =================
451 VID_GetWindowSize
452 =================
453 */
454 void VID_GetWindowSize (int *x, int *y, int *width, int *height)
455 {
456         *x = *y = 0;
457         *width = scr_width;
458         *height = scr_height;
459 }
460
461 void VID_Finish (void)
462 {
463         int usemouse;
464         if (r_render.integer)
465         {
466                 qglFinish();
467                 glXSwapBuffers(vidx11_display, win);
468         }
469
470 // handle the mouse state when windowed if that's changed
471         usemouse = false;
472         if (vid_mouse.integer && key_dest == key_game)
473                 usemouse = true;
474         if (vidmode_active)
475                 usemouse = true;
476         if (usemouse)
477         {
478                 if (!usingmouse)
479                 {
480                         usingmouse = true;
481                         IN_ActivateMouse ();
482                 }
483         }
484         else
485         {
486                 if (usingmouse)
487                 {
488                         usingmouse = false;
489                         IN_DeactivateMouse ();
490                 }
491         }
492 }
493
494 // LordHavoc: ported from SDL 1.2.2, this was far more difficult to port from
495 // SDL than to simply use the XFree gamma ramp extension, but that affects the
496 // whole screen even when the game window is inactive, this only affects the
497 // screen while the window is active, very desirable behavior :)
498 int VID_SetGamma(float prescale, float gamma, float scale, float base)
499 {
500 // LordHavoc: FIXME: finish this code, we need to allocate colors before we can store them
501 #if 1
502         return FALSE;
503 #else
504         int i, ncolors, c;
505         unsigned int Rmask, Gmask, Bmask, Rloss, Gloss, Bloss, Rshift, Gshift, Bshift, mask;
506         XColor xcmap[256];
507         unsigned short ramp[256];
508
509         if (COM_CheckParm("-nogamma"))
510                 return FALSE;
511
512         if (vidx11_visual->class != DirectColor)
513         {
514                 Con_Printf("X11 Visual class is %d, can only do gamma on %d\n", vidx11_visual->class, DirectColor);
515                 return FALSE;
516         }
517
518         Rmask = vidx11_visual->red_mask;
519         Gmask = vidx11_visual->green_mask;
520         Bmask = vidx11_visual->blue_mask;
521
522         Rshift = 0;
523         Rloss = 8;
524         if ((mask = Rmask))
525         {
526                 for (;!(mask & 1);mask >>= 1)
527                         ++Rshift;
528                 for (;(mask & 1);mask >>= 1)
529                         --Rloss;
530         }
531         Gshift = 0;
532         Gloss = 8;
533         if ((mask = Gmask))
534         {
535                 for (;!(mask & 1);mask >>= 1)
536                         ++Gshift;
537                 for (;(mask & 1);mask >>= 1)
538                         --Gloss;
539         }
540         Bshift = 0;
541         Bloss = 8;
542         if ((mask = Bmask))
543         {
544                 for (;!(mask & 1);mask >>= 1)
545                         ++Bshift;
546                 for (;(mask & 1);mask >>= 1)
547                         --Bloss;
548         }
549
550         BuildGammaTable16(prescale, gamma, scale, base, ramp);
551
552         // convert gamma ramp to palette (yes this seems odd)
553         ncolors = vidx11_visual->map_entries;
554         for (i = 0;i < ncolors;i++)
555         {
556                 c = (256 * i / ncolors);
557                 xcmap[i].pixel = ((c >> Rloss) << Rshift) | ((c >> Gloss) << Gshift) | ((c >> Bloss) << Bshift);
558                 xcmap[i].red   = ramp[c];
559                 xcmap[i].green = ramp[c];
560                 xcmap[i].blue  = ramp[c];
561                 xcmap[i].flags = (DoRed|DoGreen|DoBlue);
562         }
563         XStoreColors(vidx11_display, vidx11_colormap, xcmap, ncolors);
564         XSync(vidx11_display, false);
565         // FIXME: should this check for BadAccess/BadColor/BadValue errors produced by XStoreColors before setting this true?
566         return TRUE;
567 #endif
568 }
569
570 void VID_Init(void)
571 {
572         int i;
573 // LordHavoc: FIXME: finish this code, we need to allocate colors before we can store them
574 #if 0
575         int gammaattrib[] =
576         {
577                 GLX_RGBA,
578                 GLX_RED_SIZE, 1,
579                 GLX_GREEN_SIZE, 1,
580                 GLX_BLUE_SIZE, 1,
581                 GLX_DOUBLEBUFFER,
582                 GLX_DEPTH_SIZE, 1,
583                 GLX_X_VISUAL_TYPE, GLX_DIRECT_COLOR,
584                 None
585         };
586 #endif
587         int nogammaattrib[] =
588         {
589                 GLX_RGBA,
590                 GLX_RED_SIZE, 1,
591                 GLX_GREEN_SIZE, 1,
592                 GLX_BLUE_SIZE, 1,
593                 GLX_DOUBLEBUFFER,
594                 GLX_DEPTH_SIZE, 1,
595                 None
596         };
597         int width = 640, height = 480;
598         XSetWindowAttributes attr;
599         unsigned long mask;
600         Window root;
601         XVisualInfo *visinfo;
602         qboolean fullscreen = true;
603         int MajorVersion, MinorVersion;
604
605         Cvar_RegisterVariable (&vid_dga);
606         Cvar_RegisterVariable (&vid_dga_mouseaccel);
607
608 // interpret command-line params
609
610 // set vid parameters
611         if ((i = COM_CheckParm("-window")) != 0)
612                 fullscreen = false;
613
614         if ((i = COM_CheckParm("-width")) != 0)
615                 width = atoi(com_argv[i+1]);
616
617         if ((i = COM_CheckParm("-height")) != 0)
618                 height = atoi(com_argv[i+1]);
619
620         if ((i = COM_CheckParm("-conwidth")) != 0)
621                 vid.conwidth = atoi(com_argv[i+1]);
622         else
623                 vid.conwidth = 640;
624
625         vid.conwidth &= 0xfff8; // make it a multiple of eight
626
627         if (vid.conwidth < 320)
628                 vid.conwidth = 320;
629
630         // pick a conheight that matches with correct aspect
631         vid.conheight = vid.conwidth*3 / 4;
632
633         if ((i = COM_CheckParm("-conheight")) != 0)
634                 vid.conheight = atoi(com_argv[i+1]);
635         if (vid.conheight < 200)
636                 vid.conheight = 200;
637
638         if (!(vidx11_display = XOpenDisplay(NULL)))
639         {
640                 fprintf(stderr, "Error couldn't open the X display\n");
641                 exit(1);
642         }
643
644         scrnum = DefaultScreen(vidx11_display);
645         root = RootWindow(vidx11_display, scrnum);
646
647         // Get video mode list
648         MajorVersion = MinorVersion = 0;
649         if (!XF86VidModeQueryVersion(vidx11_display, &MajorVersion, &MinorVersion))
650                 vidmode_ext = false;
651         else
652         {
653                 Con_Printf("Using XFree86-VidModeExtension Version %d.%d\n", MajorVersion, MinorVersion);
654                 vidmode_ext = true;
655         }
656
657         visinfo = NULL;
658 // LordHavoc: FIXME: finish this code, we need to allocate colors before we can store them
659 #if 0
660         if (!COM_CheckParm("-nogamma"))
661                 visinfo = glXChooseVisual(vidx11_display, scrnum, gammaattrib);
662 #endif
663         if (!visinfo)
664         {
665                 visinfo = glXChooseVisual(vidx11_display, scrnum, nogammaattrib);
666                 if (!visinfo)
667                 {
668                         fprintf(stderr, "qkHack: Error couldn't get an RGB, Double-buffered, Depth visual\n");
669                         exit(1);
670                 }
671         }
672
673         if (vidmode_ext)
674         {
675                 int best_fit, best_dist, dist, x, y;
676
677                 XF86VidModeGetAllModeLines(vidx11_display, scrnum, &num_vidmodes, &vidmodes);
678
679                 // Are we going fullscreen?  If so, let's change video mode
680                 if (fullscreen)
681                 {
682                         best_dist = 9999999;
683                         best_fit = -1;
684
685                         for (i = 0; i < num_vidmodes; i++)
686                         {
687                                 if (width > vidmodes[i]->hdisplay || height > vidmodes[i]->vdisplay)
688                                         continue;
689
690                                 x = width - vidmodes[i]->hdisplay;
691                                 y = height - vidmodes[i]->vdisplay;
692                                 dist = (x * x) + (y * y);
693                                 if (dist < best_dist)
694                                 {
695                                         best_dist = dist;
696                                         best_fit = i;
697                                 }
698                         }
699
700                         if (best_fit != -1)
701                         {
702                                 // LordHavoc: changed from ActualWidth/ActualHeight =,
703                                 // to width/height =, so the window will take the full area of
704                                 // the mode chosen
705                                 width = vidmodes[best_fit]->hdisplay;
706                                 height = vidmodes[best_fit]->vdisplay;
707
708                                 // change to the mode
709                                 XF86VidModeSwitchToMode(vidx11_display, scrnum, vidmodes[best_fit]);
710                                 vidmode_active = true;
711
712                                 // Move the viewport to top left
713                                 XF86VidModeSetViewPort(vidx11_display, scrnum, 0, 0);
714                         }
715                         else
716                                 fullscreen = 0;
717                 }
718         }
719
720         // LordHavoc: save the visual for use in gamma ramp settings later
721         vidx11_visual = visinfo->visual;
722
723         /* window attributes */
724         attr.background_pixel = 0;
725         attr.border_pixel = 0;
726         // LordHavoc: save the colormap for later, too
727         vidx11_colormap = attr.colormap = XCreateColormap(vidx11_display, root, visinfo->visual, AllocNone);
728         attr.event_mask = X_MASK;
729         if (vidmode_active)
730         {
731                 mask = CWBackPixel | CWColormap | CWSaveUnder | CWBackingStore | CWEventMask | CWOverrideRedirect;
732                 attr.override_redirect = True;
733                 attr.backing_store = NotUseful;
734                 attr.save_under = False;
735         }
736         else
737                 mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
738
739         win = XCreateWindow(vidx11_display, root, 0, 0, width, height, 0, visinfo->depth, InputOutput, visinfo->visual, mask, &attr);
740         XStoreName(vidx11_display, win, gamename);
741         XMapWindow(vidx11_display, win);
742
743         if (vidmode_active)
744         {
745                 XMoveWindow(vidx11_display, win, 0, 0);
746                 XRaiseWindow(vidx11_display, win);
747                 XWarpPointer(vidx11_display, None, win, 0, 0, 0, 0, 0, 0);
748                 XFlush(vidx11_display);
749                 // Move the viewport to top left
750                 XF86VidModeSetViewPort(vidx11_display, scrnum, 0, 0);
751         }
752
753         XFlush(vidx11_display);
754
755         ctx = glXCreateContext(vidx11_display, visinfo, NULL, True);
756
757         glXMakeCurrent(vidx11_display, win, ctx);
758
759         scr_width = width;
760         scr_height = height;
761
762         if (vid.conheight > height)
763                 vid.conheight = height;
764         if (vid.conwidth > width)
765                 vid.conwidth = width;
766
767         InitSig(); // trap evil signals
768
769         GL_Init();
770
771         Con_SafePrintf ("Video mode %dx%d initialized.\n", width, height);
772 }
773
774 void Sys_SendKeyEvents(void)
775 {
776         HandleEvents();
777 }
778
779 void IN_Init(void)
780 {
781         if (COM_CheckParm ("-nomouse"))
782                 mouse_avail = false;
783 }
784
785 void IN_Shutdown(void)
786 {
787 }
788
789 /*
790 ===========
791 IN_Commands
792 ===========
793 */
794 void IN_Commands (void)
795 {
796 }
797
798 void IN_Move (usercmd_t *cmd)
799 {
800         if (mouse_avail)
801                 IN_Mouse(cmd, mouse_x, mouse_y);
802         mouse_x = 0;
803         mouse_y = 0;
804 }
805