various printf/fprintf calls are now Con_Printf, and some other minor cleanups
[xonotic/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 <X11/Xlib.h>
31 #include <X11/Xutil.h>
32 #include <GL/glx.h>
33
34 #include <X11/keysym.h>
35 #include <X11/cursorfont.h>
36
37 #include <X11/extensions/XShm.h>
38 #if !defined(__APPLE__) && !defined(__MACH__)
39 #include <X11/extensions/xf86dga.h>
40 #endif
41 #include <X11/extensions/xf86vmode.h>
42
43 #include "quakedef.h"
44
45 // Tell startup code that we have a client
46 int cl_available = true;
47
48 //GLX prototypes
49 XVisualInfo *(GLAPIENTRY *qglXChooseVisual)(Display *dpy, int screen, int *attribList);
50 GLXContext (GLAPIENTRY *qglXCreateContext)(Display *dpy, XVisualInfo *vis, GLXContext shareList, Bool direct);
51 void (GLAPIENTRY *qglXDestroyContext)(Display *dpy, GLXContext ctx);
52 Bool (GLAPIENTRY *qglXMakeCurrent)(Display *dpy, GLXDrawable drawable, GLXContext ctx);
53 void (GLAPIENTRY *qglXSwapBuffers)(Display *dpy, GLXDrawable drawable);
54 const char *(GLAPIENTRY *qglXQueryExtensionsString)(Display *dpy, int screen);
55
56 //GLX_ARB_get_proc_address
57 void *(GLAPIENTRY *qglXGetProcAddressARB)(const GLubyte *procName);
58
59 static dllfunction_t getprocaddressfuncs[] =
60 {
61         {"glXGetProcAddressARB", (void **) &qglXGetProcAddressARB},
62         {NULL, NULL}
63 };
64
65 //GLX_SGI_swap_control
66 GLint (GLAPIENTRY *qglXSwapIntervalSGI)(GLint interval);
67
68 static dllfunction_t swapcontrolfuncs[] =
69 {
70         {"glXSwapIntervalSGI", (void **) &qglXSwapIntervalSGI},
71         {NULL, NULL}
72 };
73
74 static Display *vidx11_display = NULL;
75 static int vidx11_screen;
76 static Window win;
77 static GLXContext ctx = NULL;
78
79 Atom wm_delete_window_atom;
80
81 #define KEY_MASK (KeyPressMask | KeyReleaseMask)
82 #define MOUSE_MASK (ButtonPressMask | ButtonReleaseMask | \
83                     PointerMotionMask | ButtonMotionMask)
84 #define X_MASK (KEY_MASK | MOUSE_MASK | VisibilityChangeMask | \
85                 StructureNotifyMask | FocusChangeMask | EnterWindowMask | \
86                 LeaveWindowMask)
87
88
89 static qboolean mouse_avail = true;
90 static qboolean mouse_active = false;
91 static qboolean vid_usingmouse = false;
92 static qboolean vid_usemouse = false;
93 static qboolean vid_usingvsync = false;
94 static qboolean vid_usevsync = false;
95 static qboolean ignoremousemove = false;
96 static float    mouse_x, mouse_y;
97 static int p_mouse_x, p_mouse_y;
98
99 #ifndef __APPLE__
100 cvar_t vid_dga = {CVAR_SAVE, "vid_dga", "1"};
101 cvar_t vid_dga_mouseaccel = {0, "vid_dga_mouseaccel", "1"};
102 #endif
103
104 qboolean vidmode_ext = false;
105
106 static int win_x, win_y;
107
108 static int scr_width, scr_height;
109
110 static XF86VidModeModeInfo **vidmodes;
111 static int num_vidmodes;
112 static qboolean vid_isfullscreen = false;
113
114 static Visual *vidx11_visual;
115 static Colormap vidx11_colormap;
116
117 /*-----------------------------------------------------------------------*/
118
119 static int XLateKey(XKeyEvent *ev, char *ascii)
120 {
121         int key = 0;
122         char buf[64];
123         KeySym keysym, shifted;
124
125         keysym = XLookupKeysym (ev, 0);
126         XLookupString(ev, buf, sizeof buf, &shifted, 0);
127         *ascii = buf[0];
128
129         switch(keysym)
130         {
131                 case XK_KP_Page_Up:      key = K_KP_PGUP; break;
132                 case XK_Page_Up:         key = K_PGUP; break;
133
134                 case XK_KP_Page_Down: key = K_KP_PGDN; break;
135                 case XK_Page_Down:       key = K_PGDN; break;
136
137                 case XK_KP_Home: key = K_KP_HOME; break;
138                 case XK_Home:    key = K_HOME; break;
139
140                 case XK_KP_End:  key = K_KP_END; break;
141                 case XK_End:     key = K_END; break;
142
143                 case XK_KP_Left: key = K_KP_LEFTARROW; break;
144                 case XK_Left:    key = K_LEFTARROW; break;
145
146                 case XK_KP_Right: key = K_KP_RIGHTARROW; break;
147                 case XK_Right:  key = K_RIGHTARROW;             break;
148
149                 case XK_KP_Down: key = K_KP_DOWNARROW; break;
150                 case XK_Down:    key = K_DOWNARROW; break;
151
152                 case XK_KP_Up:   key = K_KP_UPARROW; break;
153                 case XK_Up:              key = K_UPARROW;        break;
154
155                 case XK_Escape: key = K_ESCAPE;         break;
156
157                 case XK_KP_Enter: key = K_KP_ENTER;     break;
158                 case XK_Return: key = K_ENTER;           break;
159
160                 case XK_Tab:            key = K_TAB;                     break;
161
162                 case XK_F1:              key = K_F1;                            break;
163
164                 case XK_F2:              key = K_F2;                            break;
165
166                 case XK_F3:              key = K_F3;                            break;
167
168                 case XK_F4:              key = K_F4;                            break;
169
170                 case XK_F5:              key = K_F5;                            break;
171
172                 case XK_F6:              key = K_F6;                            break;
173
174                 case XK_F7:              key = K_F7;                            break;
175
176                 case XK_F8:              key = K_F8;                            break;
177
178                 case XK_F9:              key = K_F9;                            break;
179
180                 case XK_F10:            key = K_F10;                     break;
181
182                 case XK_F11:            key = K_F11;                     break;
183
184                 case XK_F12:            key = K_F12;                     break;
185
186                 case XK_BackSpace: key = K_BACKSPACE; break;
187
188                 case XK_KP_Delete: key = K_KP_DEL; break;
189                 case XK_Delete: key = K_DEL; break;
190
191                 case XK_Pause:  key = K_PAUSE;           break;
192
193                 case XK_Shift_L:
194                 case XK_Shift_R:        key = K_SHIFT;          break;
195
196                 case XK_Execute:
197                 case XK_Control_L:
198                 case XK_Control_R:      key = K_CTRL;            break;
199
200                 case XK_Alt_L:
201                 case XK_Meta_L:
202                 case XK_Alt_R:
203                 case XK_Meta_R: key = K_ALT;                    break;
204
205                 case XK_KP_Begin: key = K_KP_5; break;
206
207                 case XK_Insert:key = K_INS; break;
208                 case XK_KP_Insert: key = K_KP_INS; break;
209
210                 case XK_KP_Multiply: key = '*'; break;
211                 case XK_KP_Add:  key = K_KP_PLUS; break;
212                 case XK_KP_Subtract: key = K_KP_MINUS; break;
213                 case XK_KP_Divide: key = K_KP_SLASH; break;
214
215                 default:
216                         if (keysym < 32 && keysym > 126)
217                                 break;
218
219                         if (keysym >= 'A' && keysym <= 'Z')
220                                 key = keysym - 'A' + 'a';
221                         else
222                                 key = keysym;
223
224                         break;
225         }
226
227         return key;
228 }
229
230 static Cursor CreateNullCursor(Display *display, Window root)
231 {
232         Pixmap cursormask;
233         XGCValues xgc;
234         GC gc;
235         XColor dummycolour;
236         Cursor cursor;
237
238         cursormask = XCreatePixmap(display, root, 1, 1, 1);
239         xgc.function = GXclear;
240         gc =  XCreateGC(display, cursormask, GCFunction, &xgc);
241         XFillRectangle(display, cursormask, gc, 0, 0, 1, 1);
242         dummycolour.pixel = 0;
243         dummycolour.red = 0;
244         dummycolour.flags = 04;
245         cursor = XCreatePixmapCursor(display, cursormask, cursormask, &dummycolour,&dummycolour, 0,0);
246         XFreePixmap(display,cursormask);
247         XFreeGC(display,gc);
248         return cursor;
249 }
250
251 static void install_grabs(void)
252 {
253         XWindowAttributes attribs_1;
254         XSetWindowAttributes attribs_2;
255
256         XGetWindowAttributes(vidx11_display, win, &attribs_1);
257         attribs_2.event_mask = attribs_1.your_event_mask | KEY_MASK | MOUSE_MASK;
258         XChangeWindowAttributes(vidx11_display, win, CWEventMask, &attribs_2);
259
260 // inviso cursor
261         XDefineCursor(vidx11_display, win, CreateNullCursor(vidx11_display, win));
262
263         XGrabPointer(vidx11_display, win,  True, 0, GrabModeAsync, GrabModeAsync, win, None, CurrentTime);
264
265 #ifndef __APPLE__
266         if (vid_dga.integer)
267         {
268                 int MajorVersion, MinorVersion;
269
270                 if (!XF86DGAQueryVersion(vidx11_display, &MajorVersion, &MinorVersion))
271                 {
272                         // unable to query, probalby not supported
273                         Con_Print( "Failed to detect XF86DGA Mouse\n" );
274                         vid_dga.integer = 0;
275                 }
276                 else
277                 {
278                         vid_dga.integer = 1;
279                         XF86DGADirectVideo(vidx11_display, DefaultScreen(vidx11_display), XF86DGADirectMouse);
280                         XWarpPointer(vidx11_display, None, win, 0, 0, 0, 0, 0, 0);
281                 }
282         }
283         else
284 #endif
285                 XWarpPointer(vidx11_display, None, win, 0, 0, 0, 0, scr_width / 2, scr_height / 2);
286
287         XGrabKeyboard(vidx11_display, win, False, GrabModeAsync, GrabModeAsync, CurrentTime);
288
289         mouse_active = true;
290         mouse_x = mouse_y = 0;
291         ignoremousemove = true;
292 }
293
294 static void uninstall_grabs(void)
295 {
296         if (!vidx11_display || !win)
297                 return;
298
299 #ifndef __APPLE__
300         if (vid_dga.integer == 1)
301                 XF86DGADirectVideo(vidx11_display, DefaultScreen(vidx11_display), 0);
302 #endif
303
304         XUngrabPointer(vidx11_display, CurrentTime);
305         XUngrabKeyboard(vidx11_display, CurrentTime);
306
307 // inviso cursor
308         XUndefineCursor(vidx11_display, win);
309
310         mouse_active = false;
311         ignoremousemove = true;
312 }
313
314 static void HandleEvents(void)
315 {
316         XEvent event;
317         int key;
318         char ascii;
319         qboolean dowarp = false;
320
321         if (!vidx11_display)
322                 return;
323
324         while (XPending(vidx11_display))
325         {
326                 XNextEvent(vidx11_display, &event);
327
328                 switch (event.type)
329                 {
330                 case KeyPress:
331                         // key pressed
332                         key = XLateKey (&event.xkey, &ascii);
333                         Key_Event(key, ascii, true);
334                         break;
335
336                 case KeyRelease:
337                         // key released
338                         key = XLateKey (&event.xkey, &ascii);
339                         Key_Event(key, ascii, false);
340                         break;
341
342                 case MotionNotify:
343                         // mouse moved
344                         if (vid_usingmouse)
345                         {
346 #ifndef __APPLE__
347                                 if (vid_dga.integer == 1)
348                                 {
349                                         mouse_x += event.xmotion.x_root * vid_dga_mouseaccel.value;
350                                         mouse_y += event.xmotion.y_root * vid_dga_mouseaccel.value;
351                                 }
352                                 else
353 #endif
354                                 {
355
356                                         if (!event.xmotion.send_event)
357                                         {
358                                                 mouse_x += event.xmotion.x - p_mouse_x;
359                                                 mouse_y += event.xmotion.y - p_mouse_y;
360                                                 if (abs(scr_width/2 - event.xmotion.x) > scr_width / 4 || abs(scr_height/2 - event.xmotion.y) > scr_height / 4)
361                                                         dowarp = true;
362                                         }
363                                         p_mouse_x = event.xmotion.x;
364                                         p_mouse_y = event.xmotion.y;
365                                 }
366                         }
367                         //else
368                         //      ui_mouseupdate(event.xmotion.x, event.xmotion.y);
369                         break;
370
371                 case ButtonPress:
372                         // mouse button pressed
373                         switch(event.xbutton.button)
374                         {
375                         case 1:
376                                 Key_Event(K_MOUSE1, 0, true);
377                                 break;
378                         case 2:
379                                 Key_Event(K_MOUSE3, 0, true);
380                                 break;
381                         case 3:
382                                 Key_Event(K_MOUSE2, 0, true);
383                                 break;
384                         case 4:
385                                 Key_Event(K_MWHEELUP, 0, true);
386                                 break;
387                         case 5:
388                                 Key_Event(K_MWHEELDOWN, 0, true);
389                                 break;
390                         case 6:
391                                 Key_Event(K_MOUSE4, 0, true);
392                                 break;
393                         case 7:
394                                 Key_Event(K_MOUSE5, 0, true);
395                                 break;
396                         case 8:
397                                 Key_Event(K_MOUSE6, 0, true);
398                                 break;
399                         case 9:
400                                 Key_Event(K_MOUSE7, 0, true);
401                                 break;
402                         case 10:
403                                 Key_Event(K_MOUSE8, 0, true);
404                                 break;
405                         case 11:
406                                 Key_Event(K_MOUSE9, 0, true);
407                                 break;
408                         case 12:
409                                 Key_Event(K_MOUSE10, 0, true);
410                                 break;
411                         default:
412                                 Con_Printf("HandleEvents: ButtonPress gave value %d, 1-12 expected\n", event.xbutton.button);
413                                 break;
414                         }
415                         break;
416
417                 case ButtonRelease:
418                         // mouse button released
419                         switch(event.xbutton.button)
420                         {
421                         case 1:
422                                 Key_Event(K_MOUSE1, 0, false);
423                                 break;
424                         case 2:
425                                 Key_Event(K_MOUSE3, 0, false);
426                                 break;
427                         case 3:
428                                 Key_Event(K_MOUSE2, 0, false);
429                                 break;
430                         case 4:
431                                 Key_Event(K_MWHEELUP, 0, false);
432                                 break;
433                         case 5:
434                                 Key_Event(K_MWHEELDOWN, 0, false);
435                                 break;
436                         case 6:
437                                 Key_Event(K_MOUSE4, 0, false);
438                                 break;
439                         case 7:
440                                 Key_Event(K_MOUSE5, 0, false);
441                                 break;
442                         case 8:
443                                 Key_Event(K_MOUSE6, 0, false);
444                                 break;
445                         case 9:
446                                 Key_Event(K_MOUSE7, 0, false);
447                                 break;
448                         case 10:
449                                 Key_Event(K_MOUSE8, 0, false);
450                                 break;
451                         case 11:
452                                 Key_Event(K_MOUSE9, 0, false);
453                                 break;
454                         case 12:
455                                 Key_Event(K_MOUSE10, 0, false);
456                                 break;
457                         default:
458                                 Con_Printf("HandleEvents: ButtonRelease gave value %d, 1-12 expected\n", event.xbutton.button);
459                                 break;
460                         }
461                         break;
462
463                 case CreateNotify:
464                         // window created
465                         win_x = event.xcreatewindow.x;
466                         win_y = event.xcreatewindow.y;
467                         break;
468
469                 case ConfigureNotify:
470                         // window changed size/location
471                         win_x = event.xconfigure.x;
472                         win_y = event.xconfigure.y;
473                         break;
474                 case DestroyNotify:
475                         // window has been destroyed
476                         Sys_Quit();
477                         break;
478                 case ClientMessage:
479                         // window manager messages
480                         if ((event.xclient.format == 32) && ((unsigned int)event.xclient.data.l[0] == wm_delete_window_atom))
481                                 Sys_Quit();
482                         break;
483                 case MapNotify:
484                         // window restored
485                         vid_hidden = false;
486                         vid_activewindow = false;
487                         VID_RestoreSystemGamma();
488                         break;
489                 case UnmapNotify:
490                         // window iconified/rolledup/whatever
491                         vid_hidden = true;
492                         vid_activewindow = false;
493                         VID_RestoreSystemGamma();
494                         break;
495                 case FocusIn:
496                         // window is now the input focus
497                         vid_activewindow = true;
498                         break;
499                 case FocusOut:
500                         // window is no longer the input focus
501                         vid_activewindow = false;
502                         VID_RestoreSystemGamma();
503                         break;
504                 case EnterNotify:
505                         // mouse entered window
506                         break;
507                 case LeaveNotify:
508                         // mouse left window
509                         break;
510                 }
511         }
512
513         if (dowarp)
514         {
515                 /* move the mouse to the window center again */
516                 p_mouse_x = scr_width / 2;
517                 p_mouse_y = scr_height / 2;
518                 XWarpPointer(vidx11_display, None, win, 0, 0, 0, 0, p_mouse_x, p_mouse_y);
519         }
520
521         // if told to ignore one mouse move, do so
522         if (ignoremousemove)
523         {
524                 ignoremousemove = false;
525                 mouse_x = 0;
526                 mouse_y = 0;
527         }
528 }
529
530 static void IN_DeactivateMouse( void )
531 {
532         if (!mouse_avail || !vidx11_display || !win)
533                 return;
534
535         if (mouse_active)
536         {
537                 uninstall_grabs();
538                 mouse_active = false;
539         }
540 }
541
542 static void IN_ActivateMouse( void )
543 {
544         if (!mouse_avail || !vidx11_display || !win)
545                 return;
546
547         if (!mouse_active)
548         {
549                 install_grabs();
550                 mouse_active = true;
551         }
552 }
553
554 static void *prjobj = NULL;
555
556 static void GL_CloseLibrary(void)
557 {
558         if (prjobj)
559                 dlclose(prjobj);
560         prjobj = NULL;
561         gl_driver[0] = 0;
562         qglXGetProcAddressARB = NULL;
563         gl_extensions = "";
564         gl_platform = "";
565         gl_platformextensions = "";
566 }
567
568 static int GL_OpenLibrary(const char *name)
569 {
570         Con_Printf("Loading OpenGL driver %s\n", name);
571         GL_CloseLibrary();
572         if (!(prjobj = dlopen(name, RTLD_LAZY)))
573         {
574                 Con_Printf("Unable to open symbol list for %s\n", name);
575                 return false;
576         }
577         strcpy(gl_driver, name);
578         return true;
579 }
580
581 void *GL_GetProcAddress(const char *name)
582 {
583         void *p = NULL;
584         if (qglXGetProcAddressARB != NULL)
585                 p = (void *) qglXGetProcAddressARB(name);
586         if (p == NULL)
587                 p = (void *) dlsym(prjobj, name);
588         return p;
589 }
590
591 void VID_Shutdown(void)
592 {
593         if (!ctx || !vidx11_display)
594                 return;
595
596         vid_hidden = true;
597         vid_usingmouse = false;
598         if (vidx11_display)
599         {
600                 VID_RestoreSystemGamma();
601                 uninstall_grabs();
602
603                 // FIXME: glXDestroyContext here?
604                 if (vid_isfullscreen)
605                         XF86VidModeSwitchToMode(vidx11_display, vidx11_screen, vidmodes[0]);
606                 if (win)
607                         XDestroyWindow(vidx11_display, win);
608                 XCloseDisplay(vidx11_display);
609         }
610         vid_isfullscreen = false;
611         vidx11_display = NULL;
612         win = 0;
613         ctx = NULL;
614
615         GL_CloseLibrary();
616         Key_ClearStates ();
617 }
618
619 void signal_handler(int sig)
620 {
621         Con_Printf("Received signal %d, exiting...\n", sig);
622         VID_RestoreSystemGamma();
623         Sys_Quit();
624         exit(0);
625 }
626
627 void InitSig(void)
628 {
629         signal(SIGHUP, signal_handler);
630         signal(SIGINT, signal_handler);
631         signal(SIGQUIT, signal_handler);
632         signal(SIGILL, signal_handler);
633         signal(SIGTRAP, signal_handler);
634         signal(SIGIOT, signal_handler);
635         signal(SIGBUS, signal_handler);
636         signal(SIGFPE, signal_handler);
637         signal(SIGSEGV, signal_handler);
638         signal(SIGTERM, signal_handler);
639 }
640
641 /*
642 =================
643 VID_GetWindowSize
644 =================
645 */
646 void VID_GetWindowSize (int *x, int *y, int *width, int *height)
647 {
648         *x = *y = 0;
649         *width = scr_width;
650         *height = scr_height;
651 }
652
653 void VID_Finish (void)
654 {
655         vid_usevsync = vid_vsync.integer && !cls.timedemo && gl_videosyncavailable;
656         if (vid_usingvsync != vid_usevsync && gl_videosyncavailable)
657         {
658                 vid_usingvsync = vid_usevsync;
659                 if (qglXSwapIntervalSGI (vid_usevsync))
660                         Con_Print("glXSwapIntervalSGI didn't accept the vid_vsync change, it will take effect on next vid_restart (GLX_SGI_swap_control does not allow turning off vsync)\n");
661         }
662
663 // handle the mouse state when windowed if that's changed
664         vid_usemouse = false;
665         if (vid_mouse.integer && !key_consoleactive && !cls.demoplayback)
666                 vid_usemouse = true;
667         if (!vid_activewindow)
668                 vid_usemouse = false;
669         if (vid_isfullscreen)
670                 vid_usemouse = true;
671         if (vid_usemouse)
672         {
673                 if (!vid_usingmouse)
674                 {
675                         vid_usingmouse = true;
676                         IN_ActivateMouse ();
677                 }
678         }
679         else
680         {
681                 if (vid_usingmouse)
682                 {
683                         vid_usingmouse = false;
684                         IN_DeactivateMouse ();
685                 }
686         }
687
688         if (r_render.integer)
689         {
690                 if (r_speeds.integer || gl_finish.integer)
691                         qglFinish();
692                 qglXSwapBuffers(vidx11_display, win);
693         }
694 }
695
696 int VID_SetGamma(unsigned short *ramps)
697 {
698         return XF86VidModeSetGammaRamp(vidx11_display, vidx11_screen, 256, ramps, ramps + 256, ramps + 512);
699 }
700
701 int VID_GetGamma(unsigned short *ramps)
702 {
703         return XF86VidModeGetGammaRamp(vidx11_display, vidx11_screen, 256, ramps, ramps + 256, ramps + 512);
704 }
705
706 void VID_Init(void)
707 {
708 #ifndef __APPLE__
709         Cvar_RegisterVariable (&vid_dga);
710         Cvar_RegisterVariable (&vid_dga_mouseaccel);
711 #endif
712         InitSig(); // trap evil signals
713 // COMMANDLINEOPTION: Input: -nomouse disables mouse support (see also vid_mouse cvar)
714         if (COM_CheckParm ("-nomouse") || COM_CheckParm("-safe"))
715                 mouse_avail = false;
716 }
717
718 void VID_BuildGLXAttrib(int *attrib, int stencil)
719 {
720         *attrib++ = GLX_RGBA;
721         *attrib++ = GLX_RED_SIZE;*attrib++ = 1;
722         *attrib++ = GLX_GREEN_SIZE;*attrib++ = 1;
723         *attrib++ = GLX_BLUE_SIZE;*attrib++ = 1;
724         *attrib++ = GLX_DOUBLEBUFFER;
725         *attrib++ = GLX_DEPTH_SIZE;*attrib++ = 1;
726         // if stencil is enabled, ask for alpha too
727         if (stencil)
728         {
729                 *attrib++ = GLX_STENCIL_SIZE;*attrib++ = 8;
730                 *attrib++ = GLX_ALPHA_SIZE;*attrib++ = 1;
731         }
732         *attrib++ = None;
733 }
734
735 int VID_InitMode(int fullscreen, int width, int height, int bpp)
736 {
737         int i;
738         int attrib[32];
739         XSetWindowAttributes attr;
740         unsigned long mask;
741         Window root;
742         XVisualInfo *visinfo;
743         int MajorVersion, MinorVersion;
744         const char *drivername;
745
746 #if defined(__APPLE__) && defined(__MACH__)
747         drivername = "/usr/X11R6/lib/libGL.1.dylib";
748 #else
749         drivername = "libGL.so.1";
750 #endif
751 // COMMANDLINEOPTION: Linux GLX: -gl_driver <drivername> selects a GL driver library, default is libGL.so.1, useful only for using fxmesa or similar, if you don't know what this is for, you don't need it
752 // COMMANDLINEOPTION: BSD GLX: -gl_driver <drivername> selects a GL driver library, default is libGL.so.1, useful only for using fxmesa or similar, if you don't know what this is for, you don't need it
753 // LordHavoc: although this works on MacOSX, it's useless there (as there is only one system libGL)
754         i = COM_CheckParm("-gl_driver");
755         if (i && i < com_argc - 1)
756                 drivername = com_argv[i + 1];
757         if (!GL_OpenLibrary(drivername))
758         {
759                 Con_Printf("Unable to load GL driver \"%s\"\n", drivername);
760                 return false;
761         }
762
763         if (!(vidx11_display = XOpenDisplay(NULL)))
764         {
765                 Con_Print("Couldn't open the X display\n");
766                 return false;
767         }
768
769         vidx11_screen = DefaultScreen(vidx11_display);
770         root = RootWindow(vidx11_display, vidx11_screen);
771
772         // Get video mode list
773         MajorVersion = MinorVersion = 0;
774         if (!XF86VidModeQueryVersion(vidx11_display, &MajorVersion, &MinorVersion))
775                 vidmode_ext = false;
776         else
777         {
778                 Con_DPrintf("Using XFree86-VidModeExtension Version %d.%d\n", MajorVersion, MinorVersion);
779                 vidmode_ext = true;
780         }
781
782         if ((qglXChooseVisual = GL_GetProcAddress("glXChooseVisual")) == NULL
783          || (qglXCreateContext = GL_GetProcAddress("glXCreateContext")) == NULL
784          || (qglXMakeCurrent = GL_GetProcAddress("glXMakeCurrent")) == NULL
785          || (qglXSwapBuffers = GL_GetProcAddress("glXSwapBuffers")) == NULL
786          || (qglXQueryExtensionsString = GL_GetProcAddress("glXQueryExtensionsString")) == NULL)
787         {
788                 Con_Printf("glX functions not found in %s\n", gl_driver);
789                 return false;
790         }
791
792         VID_BuildGLXAttrib(attrib, bpp == 32);
793         visinfo = qglXChooseVisual(vidx11_display, vidx11_screen, attrib);
794         if (!visinfo)
795         {
796                 Con_Print("Couldn't get an RGB, Double-buffered, Depth visual\n");
797                 return false;
798         }
799
800         if (vidmode_ext)
801         {
802                 int best_fit, best_dist, dist, x, y;
803
804                 // Are we going fullscreen?  If so, let's change video mode
805                 if (fullscreen)
806                 {
807                         XF86VidModeGetAllModeLines(vidx11_display, vidx11_screen, &num_vidmodes, &vidmodes);
808                         best_dist = 9999999;
809                         best_fit = -1;
810
811                         for (i = 0; i < num_vidmodes; i++)
812                         {
813                                 if (width > vidmodes[i]->hdisplay || height > vidmodes[i]->vdisplay)
814                                         continue;
815
816                                 x = width - vidmodes[i]->hdisplay;
817                                 y = height - vidmodes[i]->vdisplay;
818                                 dist = (x * x) + (y * y);
819                                 if (dist < best_dist)
820                                 {
821                                         best_dist = dist;
822                                         best_fit = i;
823                                 }
824                         }
825
826                         if (best_fit != -1)
827                         {
828                                 // LordHavoc: changed from ActualWidth/ActualHeight =,
829                                 // to width/height =, so the window will take the full area of
830                                 // the mode chosen
831                                 width = vidmodes[best_fit]->hdisplay;
832                                 height = vidmodes[best_fit]->vdisplay;
833
834                                 // change to the mode
835                                 XF86VidModeSwitchToMode(vidx11_display, vidx11_screen, vidmodes[best_fit]);
836                                 vid_isfullscreen = true;
837
838                                 // Move the viewport to top left
839                                 XF86VidModeSetViewPort(vidx11_display, vidx11_screen, 0, 0);
840                         }
841                         else
842                                 fullscreen = 0;
843                 }
844         }
845
846         // LordHavoc: save the visual for use in gamma ramp settings later
847         vidx11_visual = visinfo->visual;
848
849         /* window attributes */
850         attr.background_pixel = 0;
851         attr.border_pixel = 0;
852         // LordHavoc: save the colormap for later, too
853         vidx11_colormap = attr.colormap = XCreateColormap(vidx11_display, root, visinfo->visual, AllocNone);
854         attr.event_mask = X_MASK;
855         if (vid_isfullscreen)
856         {
857                 mask = CWBackPixel | CWColormap | CWSaveUnder | CWBackingStore | CWEventMask | CWOverrideRedirect;
858                 attr.override_redirect = True;
859                 attr.backing_store = NotUseful;
860                 attr.save_under = False;
861         }
862         else
863                 mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
864
865         win = XCreateWindow(vidx11_display, root, 0, 0, width, height, 0, visinfo->depth, InputOutput, visinfo->visual, mask, &attr);
866         XStoreName(vidx11_display, win, gamename);
867         XMapWindow(vidx11_display, win);
868
869         // LordHavoc: making the close button on a window do the right thing
870         // seems to involve this mess, sigh...
871         wm_delete_window_atom = XInternAtom(vidx11_display, "WM_DELETE_WINDOW", false);
872         XSetWMProtocols(vidx11_display, win, &wm_delete_window_atom, 1);
873
874         if (vid_isfullscreen)
875         {
876                 XMoveWindow(vidx11_display, win, 0, 0);
877                 XRaiseWindow(vidx11_display, win);
878                 XWarpPointer(vidx11_display, None, win, 0, 0, 0, 0, 0, 0);
879                 XFlush(vidx11_display);
880                 // Move the viewport to top left
881                 XF86VidModeSetViewPort(vidx11_display, vidx11_screen, 0, 0);
882         }
883
884         //XSync(vidx11_display, False);
885
886         ctx = qglXCreateContext(vidx11_display, visinfo, NULL, True);
887         if (!ctx)
888                 Sys_Error ("glXCreateContext failed\n");
889
890         if (!qglXMakeCurrent(vidx11_display, win, ctx))
891                 Sys_Error ("glXMakeCurrent failed\n");
892
893         XSync(vidx11_display, False);
894
895         scr_width = width;
896         scr_height = height;
897
898         if ((qglGetString = GL_GetProcAddress("glGetString")) == NULL)
899                 Sys_Error("glGetString not found in %s", gl_driver);
900
901         gl_renderer = qglGetString(GL_RENDERER);
902         gl_vendor = qglGetString(GL_VENDOR);
903         gl_version = qglGetString(GL_VERSION);
904         gl_extensions = qglGetString(GL_EXTENSIONS);
905         gl_platform = "GLX";
906         gl_platformextensions = qglXQueryExtensionsString(vidx11_display, vidx11_screen);
907
908         gl_videosyncavailable = false;
909
910 // COMMANDLINEOPTION: Linux GLX: -nogetprocaddress disables GLX_ARB_get_proc_address (not required, more formal method of getting extension functions)
911 // COMMANDLINEOPTION: BSD GLX: -nogetprocaddress disables GLX_ARB_get_proc_address (not required, more formal method of getting extension functions)
912 // COMMANDLINEOPTION: MacOSX GLX: -nogetprocaddress disables GLX_ARB_get_proc_address (not required, more formal method of getting extension functions)
913         GL_CheckExtension("GLX_ARB_get_proc_address", getprocaddressfuncs, "-nogetprocaddress", false);
914 // COMMANDLINEOPTION: Linux GLX: -novideosync disables GLX_SGI_swap_control
915 // COMMANDLINEOPTION: BSD GLX: -novideosync disables GLX_SGI_swap_control
916 // COMMANDLINEOPTION: MacOSX GLX: -novideosync disables GLX_SGI_swap_control
917         gl_videosyncavailable = GL_CheckExtension("GLX_SGI_swap_control", swapcontrolfuncs, "-novideosync", false);
918
919         vid_usingmouse = false;
920         vid_usingvsync = false;
921         ignoremousemove = true;
922         vid_hidden = false;
923         vid_activewindow = true;
924         GL_Init();
925         return true;
926 }
927
928 void Sys_SendKeyEvents(void)
929 {
930         HandleEvents();
931 }
932
933 /*
934 ===========
935 IN_Commands
936 ===========
937 */
938 void IN_Commands (void)
939 {
940 }
941
942 void IN_Move (void)
943 {
944         if (mouse_avail)
945                 IN_Mouse(mouse_x, mouse_y);
946         mouse_x = 0;
947         mouse_y = 0;
948 }