~ubuntu-branches/ubuntu/jaunty/openarena/jaunty

« back to all changes in this revision

Viewing changes to code/unix/linux_glimp.c

  • Committer: Bazaar Package Importer
  • Author(s): Bruno "Fuddl" Kleinert, Bruno "Fuddl" Kleinert
  • Date: 2008-04-24 14:33:54 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20080424143354-0cuxsalv98ajw2js
Tags: 0.7.6-1
[ Bruno "Fuddl" Kleinert ]
* New upstream release
* Freshen 10_fix_build_and_binary_on_alpha.dpatch to apply to latest
  upstream sources
* Remove 10-fix_menudef.h_includes.dpatch which pulled in a missing header
  file. The header is now included in the upstream tarball.
* Remove debian/watch, because upstream places its new releases too often to
  different download locations
* Updated debian/copyright to reflect the download location
* Expand copyright years in debian/copyright

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
===========================================================================
3
 
Copyright (C) 1999-2005 Id Software, Inc.
4
 
 
5
 
This file is part of Quake III Arena source code.
6
 
 
7
 
Quake III Arena source code is free software; you can redistribute it
8
 
and/or modify it under the terms of the GNU General Public License as
9
 
published by the Free Software Foundation; either version 2 of the License,
10
 
or (at your option) any later version.
11
 
 
12
 
Quake III Arena source code is distributed in the hope that it will be
13
 
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 
GNU General Public License for more details.
16
 
 
17
 
You should have received a copy of the GNU General Public License
18
 
along with Quake III Arena source code; if not, write to the Free Software
19
 
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20
 
===========================================================================
21
 
*/
22
 
/*
23
 
** GLW_IMP.C
24
 
**
25
 
** This file contains ALL Linux specific stuff having to do with the
26
 
** OpenGL refresh.  When a port is being made the following functions
27
 
** must be implemented by the port:
28
 
**
29
 
** GLimp_EndFrame
30
 
** GLimp_Init
31
 
** GLimp_Shutdown
32
 
** GLimp_SwitchFullscreen
33
 
** GLimp_SetGamma
34
 
**
35
 
*/
36
 
 
37
 
#if !USE_SDL_VIDEO
38
 
 
39
 
#include <termios.h>
40
 
#include <sys/ioctl.h>
41
 
#ifdef __linux__
42
 
  #include <sys/stat.h>
43
 
  #include <sys/vt.h>
44
 
#endif
45
 
#include <stdarg.h>
46
 
#include <stdio.h>
47
 
#include <signal.h>
48
 
#include <pthread.h>
49
 
#include <semaphore.h>
50
 
 
51
 
// bk001204
52
 
#include <dlfcn.h>
53
 
 
54
 
// bk001206 - from my Heretic2 by way of Ryan's Fakk2
55
 
// Needed for the new X11_PendingInput() function.
56
 
#include <sys/time.h>
57
 
#include <sys/types.h>
58
 
#include <unistd.h>
59
 
 
60
 
#include "../renderer/tr_local.h"
61
 
#include "../client/client.h"
62
 
#include "linux_local.h" // bk001130
63
 
 
64
 
#include "unix_glw.h"
65
 
 
66
 
#include <GL/glx.h>
67
 
 
68
 
#include <X11/keysym.h>
69
 
#include <X11/cursorfont.h>
70
 
 
71
 
#if !defined(__sun)
72
 
#include <X11/extensions/xf86dga.h>
73
 
#include <X11/extensions/xf86vmode.h>
74
 
#endif
75
 
 
76
 
#if defined(__sun)
77
 
#include <X11/Sunkeysym.h>
78
 
#endif
79
 
 
80
 
#ifdef _XF86DGA_H_
81
 
#define HAVE_XF86DGA
82
 
#endif
83
 
 
84
 
typedef enum
85
 
{
86
 
  RSERR_OK,
87
 
 
88
 
  RSERR_INVALID_FULLSCREEN,
89
 
  RSERR_INVALID_MODE,
90
 
 
91
 
  RSERR_UNKNOWN
92
 
} rserr_t;
93
 
 
94
 
glwstate_t glw_state;
95
 
 
96
 
static Display *dpy = NULL;
97
 
static int scrnum;
98
 
static Window win = 0;
99
 
static GLXContext ctx = NULL;
100
 
 
101
 
// bk001206 - not needed anymore
102
 
// static qboolean autorepeaton = qtrue;
103
 
 
104
 
#define KEY_MASK (KeyPressMask | KeyReleaseMask)
105
 
#define MOUSE_MASK (ButtonPressMask | ButtonReleaseMask | \
106
 
                    PointerMotionMask | ButtonMotionMask )
107
 
#define X_MASK (KEY_MASK | MOUSE_MASK | VisibilityChangeMask | StructureNotifyMask )
108
 
 
109
 
static qboolean mouse_avail;
110
 
static qboolean mouse_active = qfalse;
111
 
static int mwx, mwy;
112
 
static int mx = 0, my = 0;
113
 
 
114
 
// Time mouse was reset, we ignore the first 50ms of the mouse to allow settling of events
115
 
static int mouseResetTime = 0;
116
 
#define MOUSE_RESET_DELAY 50
117
 
 
118
 
static cvar_t *in_mouse;
119
 
static cvar_t *in_dgamouse; // user pref for dga mouse
120
 
static cvar_t *in_shiftedKeys; // obey modifiers for certain keys in non-console (comma, numbers, etc)
121
 
cvar_t *in_subframe;
122
 
cvar_t *in_nograb; // this is strictly for developers
123
 
 
124
 
// bk001130 - from cvs1.17 (mkv), but not static
125
 
cvar_t   *in_joystick      = NULL;
126
 
cvar_t   *in_joystickDebug = NULL;
127
 
cvar_t   *joy_threshold    = NULL;
128
 
 
129
 
cvar_t  *r_allowSoftwareGL;   // don't abort out if the pixelformat claims software
130
 
cvar_t  *r_previousglDriver;
131
 
 
132
 
qboolean vidmode_ext = qfalse;
133
 
#ifdef HAVE_XF86DGA
134
 
static int vidmode_MajorVersion = 0, vidmode_MinorVersion = 0; // major and minor of XF86VidExtensions
135
 
 
136
 
// gamma value of the X display before we start playing with it
137
 
static XF86VidModeGamma vidmode_InitialGamma;
138
 
#endif /* HAVE_XF86DGA */
139
 
 
140
 
static int win_x, win_y;
141
 
 
142
 
#ifdef HAVE_XF86DGA
143
 
static XF86VidModeModeInfo **vidmodes;
144
 
#endif /* HAVE_XF86DGA */
145
 
//static int default_dotclock_vidmode; // bk001204 - unused
146
 
static int num_vidmodes;
147
 
static qboolean vidmode_active = qfalse;
148
 
 
149
 
static int mouse_accel_numerator;
150
 
static int mouse_accel_denominator;
151
 
static int mouse_threshold;    
152
 
 
153
 
/*
154
 
* Find the first occurrence of find in s.
155
 
*/
156
 
// bk001130 - from cvs1.17 (mkv), const
157
 
// bk001130 - made first argument const
158
 
static const char *Q_stristr( const char *s, const char *find)
159
 
{
160
 
  register char c, sc;
161
 
  register size_t len;
162
 
 
163
 
  if ((c = *find++) != 0)
164
 
  {
165
 
    if (c >= 'a' && c <= 'z')
166
 
    {
167
 
      c -= ('a' - 'A');
168
 
    }
169
 
    len = strlen(find);
170
 
    do
171
 
    {
172
 
      do
173
 
      {
174
 
        if ((sc = *s++) == 0)
175
 
          return NULL;
176
 
        if (sc >= 'a' && sc <= 'z')
177
 
        {
178
 
          sc -= ('a' - 'A');
179
 
        }
180
 
      } while (sc != c);
181
 
    } while (Q_stricmpn(s, find, len) != 0);
182
 
    s--;
183
 
  }
184
 
  return s;
185
 
}
186
 
 
187
 
/*****************************************************************************
188
 
** KEYBOARD
189
 
** NOTE TTimo the keyboard handling is done with KeySyms
190
 
**   that means relying on the keyboard mapping provided by X
191
 
**   in-game it would probably be better to use KeyCode (i.e. hardware key codes)
192
 
**   you would still need the KeySyms in some cases, such as for the console and all entry textboxes
193
 
**     (cause there's nothing worse than a qwerty mapping on a french keyboard)
194
 
**
195
 
** you can turn on some debugging and verbose of the keyboard code with #define KBD_DBG
196
 
******************************************************************************/
197
 
 
198
 
//#define KBD_DBG
199
 
 
200
 
static char *XLateKey(XKeyEvent *ev, int *key)
201
 
{
202
 
  static unsigned char buf[64];
203
 
  static unsigned char bufnomod[2];
204
 
  KeySym keysym;
205
 
  int XLookupRet;
206
 
 
207
 
  *key = 0;
208
 
 
209
 
  XLookupRet = XLookupString(ev, buf, sizeof buf, &keysym, 0);
210
 
#ifdef KBD_DBG
211
 
  ri.Printf(PRINT_ALL, "XLookupString ret: %d buf: %s keysym: %x\n", XLookupRet, buf, keysym);
212
 
#endif
213
 
 
214
 
  if (!in_shiftedKeys->integer) {
215
 
    // also get a buffer without modifiers held
216
 
    ev->state = 0;
217
 
    XLookupRet = XLookupString(ev, bufnomod, sizeof bufnomod, &keysym, 0);
218
 
#ifdef KBD_DBG
219
 
  ri.Printf(PRINT_ALL, "XLookupString (minus modifiers) ret: %d buf: %s keysym: %x\n", XLookupRet, buf, keysym);
220
 
#endif
221
 
  }
222
 
 
223
 
  switch (keysym)
224
 
  {
225
 
  case XK_KP_Page_Up:
226
 
  case XK_KP_9:  *key = K_KP_PGUP; break;
227
 
  case XK_Page_Up:   *key = K_PGUP; break;
228
 
 
229
 
  case XK_KP_Page_Down:
230
 
  case XK_KP_3: *key = K_KP_PGDN; break;
231
 
  case XK_Page_Down:   *key = K_PGDN; break;
232
 
 
233
 
  case XK_KP_Home: *key = K_KP_HOME; break;
234
 
  case XK_KP_7: *key = K_KP_HOME; break;
235
 
  case XK_Home:  *key = K_HOME; break;
236
 
 
237
 
  case XK_KP_End:
238
 
  case XK_KP_1:   *key = K_KP_END; break;
239
 
  case XK_End:   *key = K_END; break;
240
 
 
241
 
  case XK_KP_Left: *key = K_KP_LEFTARROW; break;
242
 
  case XK_KP_4: *key = K_KP_LEFTARROW; break;
243
 
  case XK_Left:  *key = K_LEFTARROW; break;
244
 
 
245
 
  case XK_KP_Right: *key = K_KP_RIGHTARROW; break;
246
 
  case XK_KP_6: *key = K_KP_RIGHTARROW; break;
247
 
  case XK_Right:  *key = K_RIGHTARROW;    break;
248
 
 
249
 
  case XK_KP_Down:
250
 
  case XK_KP_2:    *key = K_KP_DOWNARROW; break;
251
 
  case XK_Down:  *key = K_DOWNARROW; break;
252
 
 
253
 
  case XK_KP_Up:
254
 
  case XK_KP_8:    *key = K_KP_UPARROW; break;
255
 
  case XK_Up:    *key = K_UPARROW;   break;
256
 
 
257
 
  case XK_Escape: *key = K_ESCAPE;    break;
258
 
 
259
 
  case XK_KP_Enter: *key = K_KP_ENTER;  break;
260
 
  case XK_Return: *key = K_ENTER;    break;
261
 
 
262
 
  case XK_Tab:    *key = K_TAB;      break;
263
 
 
264
 
  case XK_F1:    *key = K_F1;       break;
265
 
 
266
 
  case XK_F2:    *key = K_F2;       break;
267
 
 
268
 
  case XK_F3:    *key = K_F3;       break;
269
 
 
270
 
  case XK_F4:    *key = K_F4;       break;
271
 
 
272
 
  case XK_F5:    *key = K_F5;       break;
273
 
 
274
 
  case XK_F6:    *key = K_F6;       break;
275
 
 
276
 
  case XK_F7:    *key = K_F7;       break;
277
 
 
278
 
  case XK_F8:    *key = K_F8;       break;
279
 
 
280
 
  case XK_F9:    *key = K_F9;       break;
281
 
 
282
 
  case XK_F10:    *key = K_F10;      break;
283
 
 
284
 
  case XK_F11:    *key = K_F11;      break;
285
 
 
286
 
  case XK_F12:    *key = K_F12;      break;
287
 
 
288
 
    // bk001206 - from Ryan's Fakk2
289
 
    //case XK_BackSpace: *key = 8; break; // ctrl-h
290
 
  case XK_BackSpace: *key = K_BACKSPACE; break; // ctrl-h
291
 
 
292
 
  case XK_KP_Delete:
293
 
  case XK_KP_Decimal: *key = K_KP_DEL; break;
294
 
  case XK_Delete: *key = K_DEL; break;
295
 
 
296
 
  case XK_Pause:  *key = K_PAUSE;    break;
297
 
 
298
 
  case XK_Shift_L:
299
 
  case XK_Shift_R:  *key = K_SHIFT;   break;
300
 
 
301
 
  case XK_Execute:
302
 
  case XK_Control_L:
303
 
  case XK_Control_R:  *key = K_CTRL;  break;
304
 
 
305
 
  case XK_Alt_L:
306
 
  case XK_Meta_L:
307
 
  case XK_Alt_R:
308
 
  case XK_Meta_R: *key = K_ALT;     break;
309
 
 
310
 
  case XK_KP_Begin: *key = K_KP_5;  break;
311
 
 
312
 
  case XK_Insert:   *key = K_INS; break;
313
 
  case XK_KP_Insert:
314
 
  case XK_KP_0: *key = K_KP_INS; break;
315
 
 
316
 
  case XK_KP_Multiply: *key = '*'; break;
317
 
  case XK_KP_Add:  *key = K_KP_PLUS; break;
318
 
  case XK_KP_Subtract: *key = K_KP_MINUS; break;
319
 
  case XK_KP_Divide: *key = K_KP_SLASH; break;
320
 
 
321
 
    // bk001130 - from cvs1.17 (mkv)
322
 
  case XK_exclam: *key = '1'; break;
323
 
  case XK_at: *key = '2'; break;
324
 
  case XK_numbersign: *key = '3'; break;
325
 
  case XK_dollar: *key = '4'; break;
326
 
  case XK_percent: *key = '5'; break;
327
 
  case XK_asciicircum: *key = '6'; break;
328
 
  case XK_ampersand: *key = '7'; break;
329
 
  case XK_asterisk: *key = '8'; break;
330
 
  case XK_parenleft: *key = '9'; break;
331
 
  case XK_parenright: *key = '0'; break;
332
 
 
333
 
  // weird french keyboards ..
334
 
  // NOTE: console toggle is hardcoded in cl_keys.c, can't be unbound
335
 
  //   cleaner would be .. using hardware key codes instead of the key syms
336
 
  //   could also add a new K_KP_CONSOLE
337
 
  case XK_twosuperior: *key = '~'; break;
338
 
 
339
 
  // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=472
340
 
  case XK_space:
341
 
  case XK_KP_Space: *key = K_SPACE; break;
342
 
 
343
 
  default:
344
 
    if (XLookupRet == 0)
345
 
    {
346
 
      if (com_developer->value)
347
 
      {
348
 
        ri.Printf(PRINT_ALL, "Warning: XLookupString failed on KeySym %d\n", keysym);
349
 
      }
350
 
      return NULL;
351
 
    }
352
 
    else
353
 
    {
354
 
      // XK_* tests failed, but XLookupString got a buffer, so let's try it
355
 
      if (in_shiftedKeys->integer) {
356
 
        *key = *(unsigned char *)buf;
357
 
        if (*key >= 'A' && *key <= 'Z')
358
 
          *key = *key - 'A' + 'a';
359
 
        // if ctrl is pressed, the keys are not between 'A' and 'Z', for instance ctrl-z == 26 ^Z ^C etc.
360
 
        // see https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=19
361
 
        else if (*key >= 1 && *key <= 26)
362
 
          *key = *key + 'a' - 1;
363
 
      } else {
364
 
        *key = bufnomod[0];
365
 
      }
366
 
    }
367
 
    break;
368
 
  }
369
 
 
370
 
  return buf;
371
 
}
372
 
 
373
 
// ========================================================================
374
 
// makes a null cursor
375
 
// ========================================================================
376
 
 
377
 
static Cursor CreateNullCursor(Display *display, Window root)
378
 
{
379
 
  Pixmap cursormask; 
380
 
  XGCValues xgc;
381
 
  GC gc;
382
 
  XColor dummycolour;
383
 
  Cursor cursor;
384
 
 
385
 
  cursormask = XCreatePixmap(display, root, 1, 1, 1/*depth*/);
386
 
  xgc.function = GXclear;
387
 
  gc =  XCreateGC(display, cursormask, GCFunction, &xgc);
388
 
  XFillRectangle(display, cursormask, gc, 0, 0, 1, 1);
389
 
  dummycolour.pixel = 0;
390
 
  dummycolour.red = 0;
391
 
  dummycolour.flags = 04;
392
 
  cursor = XCreatePixmapCursor(display, cursormask, cursormask,
393
 
                               &dummycolour,&dummycolour, 0,0);
394
 
  XFreePixmap(display,cursormask);
395
 
  XFreeGC(display,gc);
396
 
  return cursor;
397
 
}
398
 
 
399
 
static void install_grabs(void)
400
 
{
401
 
  // inviso cursor
402
 
  XWarpPointer(dpy, None, win,
403
 
               0, 0, 0, 0,
404
 
               glConfig.vidWidth / 2, glConfig.vidHeight / 2);
405
 
  XSync(dpy, False);
406
 
 
407
 
  XDefineCursor(dpy, win, CreateNullCursor(dpy, win));
408
 
 
409
 
  XGrabPointer(dpy, win, // bk010108 - do this earlier?
410
 
               False,
411
 
               MOUSE_MASK,
412
 
               GrabModeAsync, GrabModeAsync,
413
 
               win,
414
 
               None,
415
 
               CurrentTime);
416
 
 
417
 
  XGetPointerControl(dpy, &mouse_accel_numerator, &mouse_accel_denominator,
418
 
                     &mouse_threshold);
419
 
 
420
 
  XChangePointerControl(dpy, True, True, 1, 1, 0);
421
 
 
422
 
  XSync(dpy, False);
423
 
 
424
 
  mouseResetTime = Sys_Milliseconds ();
425
 
 
426
 
#ifdef HAVE_XF86DGA
427
 
  if (in_dgamouse->value)
428
 
  {
429
 
    int MajorVersion, MinorVersion;
430
 
 
431
 
    if (!XF86DGAQueryVersion(dpy, &MajorVersion, &MinorVersion))
432
 
    {
433
 
      // unable to query, probalby not supported, force the setting to 0
434
 
      ri.Printf( PRINT_ALL, "Failed to detect XF86DGA Mouse\n" );
435
 
      ri.Cvar_Set( "in_dgamouse", "0" );
436
 
    } else
437
 
    {
438
 
      XF86DGADirectVideo(dpy, DefaultScreen(dpy), XF86DGADirectMouse);
439
 
      XWarpPointer(dpy, None, win, 0, 0, 0, 0, 0, 0);
440
 
    }
441
 
  } else
442
 
#endif /* HAVE_XF86DGA */
443
 
  {
444
 
    mwx = glConfig.vidWidth / 2;
445
 
    mwy = glConfig.vidHeight / 2;
446
 
    mx = my = 0;
447
 
  }
448
 
 
449
 
  XGrabKeyboard(dpy, win,
450
 
                False,
451
 
                GrabModeAsync, GrabModeAsync,
452
 
                CurrentTime);
453
 
 
454
 
  XSync(dpy, False);
455
 
}
456
 
 
457
 
static void uninstall_grabs(void)
458
 
{
459
 
#ifdef HAVE_XF86DGA
460
 
  if (in_dgamouse->value)
461
 
  {
462
 
                if (com_developer->value)
463
 
                        ri.Printf( PRINT_ALL, "DGA Mouse - Disabling DGA DirectVideo\n" );
464
 
    XF86DGADirectVideo(dpy, DefaultScreen(dpy), 0);
465
 
  }
466
 
#endif /* HAVE_XF86DGA */
467
 
 
468
 
  XChangePointerControl(dpy, qtrue, qtrue, mouse_accel_numerator, 
469
 
                        mouse_accel_denominator, mouse_threshold);
470
 
 
471
 
  XUngrabPointer(dpy, CurrentTime);
472
 
  XUngrabKeyboard(dpy, CurrentTime);
473
 
 
474
 
  XWarpPointer(dpy, None, win,
475
 
               0, 0, 0, 0,
476
 
               glConfig.vidWidth / 2, glConfig.vidHeight / 2);
477
 
 
478
 
  // inviso cursor
479
 
  XUndefineCursor(dpy, win);
480
 
}
481
 
 
482
 
// bk001206 - from Ryan's Fakk2
483
 
/**
484
 
 * XPending() actually performs a blocking read 
485
 
 *  if no events available. From Fakk2, by way of
486
 
 *  Heretic2, by way of SDL, original idea GGI project.
487
 
 * The benefit of this approach over the quite
488
 
 *  badly behaved XAutoRepeatOn/Off is that you get
489
 
 *  focus handling for free, which is a major win
490
 
 *  with debug and windowed mode. It rests on the
491
 
 *  assumption that the X server will use the
492
 
 *  same timestamp on press/release event pairs 
493
 
 *  for key repeats. 
494
 
 */
495
 
static qboolean X11_PendingInput(void) {
496
 
 
497
 
  assert(dpy != NULL);
498
 
 
499
 
  // Flush the display connection
500
 
  //  and look to see if events are queued
501
 
  XFlush( dpy );
502
 
  if ( XEventsQueued( dpy, QueuedAlready) )
503
 
  {
504
 
    return qtrue;
505
 
  }
506
 
 
507
 
  // More drastic measures are required -- see if X is ready to talk
508
 
  {
509
 
    static struct timeval zero_time;
510
 
    int x11_fd;
511
 
    fd_set fdset;
512
 
 
513
 
    x11_fd = ConnectionNumber( dpy );
514
 
    FD_ZERO(&fdset);
515
 
    FD_SET(x11_fd, &fdset);
516
 
    if ( select(x11_fd+1, &fdset, NULL, NULL, &zero_time) == 1 )
517
 
    {
518
 
      return(XPending(dpy));
519
 
    }
520
 
  }
521
 
 
522
 
  // Oh well, nothing is ready ..
523
 
  return qfalse;
524
 
}
525
 
 
526
 
// bk001206 - from Ryan's Fakk2. See above.
527
 
static qboolean repeated_press(XEvent *event)
528
 
{
529
 
  XEvent        peekevent;
530
 
  qboolean      repeated = qfalse;
531
 
 
532
 
  assert(dpy != NULL);
533
 
 
534
 
  if (X11_PendingInput())
535
 
  {
536
 
    XPeekEvent(dpy, &peekevent);
537
 
 
538
 
    if ((peekevent.type == KeyPress) &&
539
 
        (peekevent.xkey.keycode == event->xkey.keycode) &&
540
 
        (peekevent.xkey.time == event->xkey.time))
541
 
    {
542
 
      repeated = qtrue;
543
 
      XNextEvent(dpy, &peekevent);  // skip event.
544
 
    } // if
545
 
  } // if
546
 
 
547
 
  return(repeated);
548
 
} // repeated_press
549
 
 
550
 
int Sys_XTimeToSysTime (Time xtime);
551
 
static void HandleEvents(void)
552
 
{
553
 
  int b;
554
 
  int key;
555
 
  XEvent event;
556
 
  qboolean dowarp = qfalse;
557
 
  char *p;
558
 
  int dx, dy;
559
 
  int t = 0; // default to 0 in case we don't set
560
 
        
561
 
  if (!dpy)
562
 
    return;
563
 
 
564
 
  while (XPending(dpy))
565
 
  {
566
 
    XNextEvent(dpy, &event);
567
 
    switch (event.type)
568
 
    {
569
 
    case KeyPress:
570
 
                        t = Sys_XTimeToSysTime(event.xkey.time);
571
 
      p = XLateKey(&event.xkey, &key);
572
 
      if (key)
573
 
      {
574
 
        Sys_QueEvent( t, SE_KEY, key, qtrue, 0, NULL );
575
 
      }
576
 
      if (p)
577
 
      {
578
 
        while (*p)
579
 
        {
580
 
          Sys_QueEvent( t, SE_CHAR, *p++, 0, 0, NULL );
581
 
        }
582
 
      }
583
 
      break;
584
 
 
585
 
    case KeyRelease:
586
 
                        t = Sys_XTimeToSysTime(event.xkey.time);
587
 
      // bk001206 - handle key repeat w/o XAutRepatOn/Off
588
 
      //            also: not done if console/menu is active.
589
 
      // From Ryan's Fakk2.
590
 
      // see game/q_shared.h, KEYCATCH_* . 0 == in 3d game.  
591
 
      if (cls.keyCatchers == 0)
592
 
      {   // FIXME: KEYCATCH_NONE
593
 
        if (repeated_press(&event) == qtrue)
594
 
          continue;
595
 
      } // if
596
 
      XLateKey(&event.xkey, &key);
597
 
 
598
 
      Sys_QueEvent( t, SE_KEY, key, qfalse, 0, NULL );
599
 
      break;
600
 
 
601
 
    case MotionNotify:
602
 
                        t = Sys_XTimeToSysTime(event.xkey.time);
603
 
      if (mouse_active)
604
 
      {
605
 
#ifdef HAVE_XF86DGA
606
 
        if (in_dgamouse->value)
607
 
        {
608
 
          mx += event.xmotion.x_root;
609
 
          my += event.xmotion.y_root;
610
 
          if (t - mouseResetTime > MOUSE_RESET_DELAY )
611
 
          {
612
 
            Sys_QueEvent( t, SE_MOUSE, mx, my, 0, NULL );
613
 
          }
614
 
          mx = my = 0;
615
 
        } else
616
 
#endif /* HAVE_XF86DGA */
617
 
        {
618
 
          // If it's a center motion, we've just returned from our warp
619
 
          if (event.xmotion.x == glConfig.vidWidth/2 &&
620
 
              event.xmotion.y == glConfig.vidHeight/2)
621
 
          {
622
 
            mwx = glConfig.vidWidth/2;
623
 
            mwy = glConfig.vidHeight/2;
624
 
            if (t - mouseResetTime > MOUSE_RESET_DELAY )
625
 
            {
626
 
              Sys_QueEvent( t, SE_MOUSE, mx, my, 0, NULL );
627
 
            }
628
 
            mx = my = 0;
629
 
            break;
630
 
          }
631
 
 
632
 
          dx = ((int)event.xmotion.x - mwx);
633
 
          dy = ((int)event.xmotion.y - mwy);
634
 
                                        mx += dx;
635
 
                                        my += dy;
636
 
 
637
 
          mwx = event.xmotion.x;
638
 
          mwy = event.xmotion.y;
639
 
          dowarp = qtrue;
640
 
        }
641
 
      }
642
 
      break;
643
 
 
644
 
    case ButtonPress:
645
 
                  t = Sys_XTimeToSysTime(event.xkey.time);
646
 
      if (event.xbutton.button == 4)
647
 
      {
648
 
        Sys_QueEvent( t, SE_KEY, K_MWHEELUP, qtrue, 0, NULL );
649
 
      } else if (event.xbutton.button == 5)
650
 
      {
651
 
        Sys_QueEvent( t, SE_KEY, K_MWHEELDOWN, qtrue, 0, NULL );
652
 
      } else
653
 
      {
654
 
        // NOTE TTimo there seems to be a weird mapping for K_MOUSE1 K_MOUSE2 K_MOUSE3 ..
655
 
        b=-1;
656
 
        if (event.xbutton.button == 1)
657
 
        {
658
 
          b = 0; // K_MOUSE1
659
 
        } else if (event.xbutton.button == 2)
660
 
        {
661
 
          b = 2; // K_MOUSE3
662
 
        } else if (event.xbutton.button == 3)
663
 
        {
664
 
          b = 1; // K_MOUSE2
665
 
        } else if (event.xbutton.button == 6)
666
 
        {
667
 
          b = 3; // K_MOUSE4
668
 
        } else if (event.xbutton.button == 7)
669
 
        {
670
 
          b = 4; // K_MOUSE5
671
 
        };
672
 
 
673
 
        Sys_QueEvent( t, SE_KEY, K_MOUSE1 + b, qtrue, 0, NULL );
674
 
      }
675
 
      break;
676
 
 
677
 
    case ButtonRelease:
678
 
                  t = Sys_XTimeToSysTime(event.xkey.time);
679
 
      if (event.xbutton.button == 4)
680
 
      {
681
 
        Sys_QueEvent( t, SE_KEY, K_MWHEELUP, qfalse, 0, NULL );
682
 
      } else if (event.xbutton.button == 5)
683
 
      {
684
 
        Sys_QueEvent( t, SE_KEY, K_MWHEELDOWN, qfalse, 0, NULL );
685
 
      } else
686
 
      {
687
 
        b=-1;
688
 
        if (event.xbutton.button == 1)
689
 
        {
690
 
          b = 0;
691
 
        } else if (event.xbutton.button == 2)
692
 
        {
693
 
          b = 2;
694
 
        } else if (event.xbutton.button == 3)
695
 
        {
696
 
          b = 1;
697
 
        } else if (event.xbutton.button == 6)
698
 
        {
699
 
          b = 3; // K_MOUSE4
700
 
        } else if (event.xbutton.button == 7)
701
 
        {
702
 
          b = 4; // K_MOUSE5
703
 
        };
704
 
        Sys_QueEvent( t, SE_KEY, K_MOUSE1 + b, qfalse, 0, NULL );
705
 
      }
706
 
      break;
707
 
 
708
 
    case CreateNotify :
709
 
      win_x = event.xcreatewindow.x;
710
 
      win_y = event.xcreatewindow.y;
711
 
      break;
712
 
 
713
 
    case ConfigureNotify :
714
 
      win_x = event.xconfigure.x;
715
 
      win_y = event.xconfigure.y;
716
 
      break;
717
 
    }
718
 
  }
719
 
 
720
 
  if (dowarp)
721
 
  {
722
 
    XWarpPointer(dpy,None,win,0,0,0,0, 
723
 
                 (glConfig.vidWidth/2),(glConfig.vidHeight/2));
724
 
  }
725
 
}
726
 
 
727
 
// NOTE TTimo for the tty console input, we didn't rely on those .. 
728
 
//   it's not very surprising actually cause they are not used otherwise
729
 
void KBD_Init(void)
730
 
{
731
 
}
732
 
 
733
 
void KBD_Close(void)
734
 
{
735
 
}
736
 
 
737
 
void IN_ActivateMouse( void ) 
738
 
{
739
 
  if (!mouse_avail || !dpy || !win)
740
 
    return;
741
 
 
742
 
  if (!mouse_active)
743
 
  {
744
 
                if (!in_nograb->value)
745
 
      install_grabs();
746
 
                else if (in_dgamouse->value) // force dga mouse to 0 if using nograb
747
 
                        ri.Cvar_Set("in_dgamouse", "0");
748
 
    mouse_active = qtrue;
749
 
  }
750
 
}
751
 
 
752
 
void IN_DeactivateMouse( void ) 
753
 
{
754
 
  if (!mouse_avail || !dpy || !win)
755
 
    return;
756
 
 
757
 
  if (mouse_active)
758
 
  {
759
 
                if (!in_nograb->value)
760
 
      uninstall_grabs();
761
 
                else if (in_dgamouse->value) // force dga mouse to 0 if using nograb
762
 
                        ri.Cvar_Set("in_dgamouse", "0");
763
 
    mouse_active = qfalse;
764
 
  }
765
 
}
766
 
/*****************************************************************************/
767
 
 
768
 
/*
769
 
** GLimp_SetGamma
770
 
**
771
 
** This routine should only be called if glConfig.deviceSupportsGamma is TRUE
772
 
*/
773
 
void GLimp_SetGamma( unsigned char red[256], unsigned char green[256], unsigned char blue[256] )
774
 
{
775
 
  // NOTE TTimo we get the gamma value from cvar, because we can't work with the s_gammatable
776
 
  //   the API wasn't changed to avoid breaking other OSes
777
 
#ifdef HAVE_XF86DGA
778
 
  float g = Cvar_Get("r_gamma", "1.0", 0)->value;
779
 
  XF86VidModeGamma gamma;
780
 
  assert(glConfig.deviceSupportsGamma);
781
 
  gamma.red = g;
782
 
  gamma.green = g;
783
 
  gamma.blue = g;
784
 
  XF86VidModeSetGamma(dpy, scrnum, &gamma);
785
 
#endif /* HAVE_XF86DGA */
786
 
}
787
 
 
788
 
/*
789
 
** GLimp_Shutdown
790
 
**
791
 
** This routine does all OS specific shutdown procedures for the OpenGL
792
 
** subsystem.  Under OpenGL this means NULLing out the current DC and
793
 
** HGLRC, deleting the rendering context, and releasing the DC acquired
794
 
** for the window.  The state structure is also nulled out.
795
 
**
796
 
*/
797
 
void GLimp_Shutdown( void )
798
 
{
799
 
  if (!ctx || !dpy)
800
 
    return;
801
 
  IN_DeactivateMouse();
802
 
  // bk001206 - replaced with H2/Fakk2 solution
803
 
  // XAutoRepeatOn(dpy);
804
 
  // autorepeaton = qfalse; // bk001130 - from cvs1.17 (mkv)
805
 
  if (dpy)
806
 
  {
807
 
    if (ctx)
808
 
      qglXDestroyContext(dpy, ctx);
809
 
    if (win)
810
 
      XDestroyWindow(dpy, win);
811
 
#ifdef HAVE_XF86DGA
812
 
    if (vidmode_active)
813
 
      XF86VidModeSwitchToMode(dpy, scrnum, vidmodes[0]);
814
 
    if (glConfig.deviceSupportsGamma)
815
 
    {
816
 
      XF86VidModeSetGamma(dpy, scrnum, &vidmode_InitialGamma);
817
 
    }
818
 
#endif /* HAVE_XF86DGA */
819
 
    // NOTE TTimo opening/closing the display should be necessary only once per run
820
 
    //   but it seems QGL_Shutdown gets called in a lot of occasion
821
 
    //   in some cases, this XCloseDisplay is known to raise some X errors
822
 
    //   ( https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=33 )
823
 
    XCloseDisplay(dpy);
824
 
  }
825
 
  vidmode_active = qfalse;
826
 
  dpy = NULL;
827
 
  win = 0;
828
 
  ctx = NULL;
829
 
 
830
 
  memset( &glConfig, 0, sizeof( glConfig ) );
831
 
  memset( &glState, 0, sizeof( glState ) );
832
 
 
833
 
  QGL_Shutdown();
834
 
}
835
 
 
836
 
/*
837
 
** GLimp_LogComment
838
 
*/
839
 
void GLimp_LogComment( char *comment ) 
840
 
{
841
 
  if ( glw_state.log_fp )
842
 
  {
843
 
    fprintf( glw_state.log_fp, "%s", comment );
844
 
  }
845
 
}
846
 
 
847
 
/*
848
 
** GLW_StartDriverAndSetMode
849
 
*/
850
 
// bk001204 - prototype needed
851
 
int GLW_SetMode( const char *drivername, int mode, qboolean fullscreen );
852
 
static qboolean GLW_StartDriverAndSetMode( const char *drivername, 
853
 
                                           int mode, 
854
 
                                           qboolean fullscreen )
855
 
{
856
 
  rserr_t err;
857
 
 
858
 
  // don't ever bother going into fullscreen with a voodoo card
859
 
#if 1   // JDC: I reenabled this
860
 
  if ( Q_stristr( drivername, "Voodoo" ) )
861
 
  {
862
 
    ri.Cvar_Set( "r_fullscreen", "0" );
863
 
    r_fullscreen->modified = qfalse;
864
 
    fullscreen = qfalse;
865
 
  }
866
 
#endif
867
 
        
868
 
        if (fullscreen && in_nograb->value)
869
 
        {
870
 
                ri.Printf( PRINT_ALL, "Fullscreen not allowed with in_nograb 1\n");
871
 
    ri.Cvar_Set( "r_fullscreen", "0" );
872
 
    r_fullscreen->modified = qfalse;
873
 
    fullscreen = qfalse;                
874
 
        }
875
 
 
876
 
  err = GLW_SetMode( drivername, mode, fullscreen );
877
 
 
878
 
  switch ( err )
879
 
  {
880
 
  case RSERR_INVALID_FULLSCREEN:
881
 
    ri.Printf( PRINT_ALL, "...WARNING: fullscreen unavailable in this mode\n" );
882
 
    return qfalse;
883
 
  case RSERR_INVALID_MODE:
884
 
    ri.Printf( PRINT_ALL, "...WARNING: could not set the given mode (%d)\n", mode );
885
 
    return qfalse;
886
 
  default:
887
 
    break;
888
 
  }
889
 
  return qtrue;
890
 
}
891
 
 
892
 
/*
893
 
** GLW_SetMode
894
 
*/
895
 
int GLW_SetMode( const char *drivername, int mode, qboolean fullscreen )
896
 
{
897
 
  int attrib[] = {
898
 
    GLX_RGBA,         // 0
899
 
    GLX_RED_SIZE, 4,      // 1, 2
900
 
    GLX_GREEN_SIZE, 4,      // 3, 4
901
 
    GLX_BLUE_SIZE, 4,     // 5, 6
902
 
    GLX_DOUBLEBUFFER,     // 7
903
 
    GLX_DEPTH_SIZE, 1,      // 8, 9
904
 
    GLX_STENCIL_SIZE, 1,    // 10, 11
905
 
    None
906
 
  };
907
 
  // these match in the array
908
 
#define ATTR_RED_IDX 2
909
 
#define ATTR_GREEN_IDX 4
910
 
#define ATTR_BLUE_IDX 6
911
 
#define ATTR_DEPTH_IDX 9
912
 
#define ATTR_STENCIL_IDX 11
913
 
  Window root;
914
 
  XVisualInfo *visinfo;
915
 
  XSetWindowAttributes attr;
916
 
  XSizeHints sizehints;
917
 
  unsigned long mask;
918
 
  int colorbits, depthbits, stencilbits;
919
 
  int tcolorbits, tdepthbits, tstencilbits;
920
 
  int dga_MajorVersion, dga_MinorVersion;
921
 
  int actualWidth, actualHeight;
922
 
  int i;
923
 
  const char*   glstring; // bk001130 - from cvs1.17 (mkv)
924
 
 
925
 
  ri.Printf( PRINT_ALL, "Initializing OpenGL display\n");
926
 
 
927
 
  ri.Printf (PRINT_ALL, "...setting mode %d:", mode );
928
 
 
929
 
  if ( !R_GetModeInfo( &glConfig.vidWidth, &glConfig.vidHeight, &glConfig.windowAspect, mode ) )
930
 
  {
931
 
    ri.Printf( PRINT_ALL, " invalid mode\n" );
932
 
    return RSERR_INVALID_MODE;
933
 
  }
934
 
  ri.Printf( PRINT_ALL, " %d %d\n", glConfig.vidWidth, glConfig.vidHeight);
935
 
 
936
 
  if (!(dpy = XOpenDisplay(NULL)))
937
 
  {
938
 
    fprintf(stderr, "Error couldn't open the X display\n");
939
 
    return RSERR_INVALID_MODE;
940
 
  }
941
 
  
942
 
  scrnum = DefaultScreen(dpy);
943
 
  root = RootWindow(dpy, scrnum);
944
 
 
945
 
  actualWidth = glConfig.vidWidth;
946
 
  actualHeight = glConfig.vidHeight;
947
 
 
948
 
  // Get video mode list
949
 
#ifdef HAVE_XF86DGA
950
 
  if (!XF86VidModeQueryVersion(dpy, &vidmode_MajorVersion, &vidmode_MinorVersion))
951
 
  {
952
 
#endif /* HAVE_XF86DGA */
953
 
    vidmode_ext = qfalse;
954
 
#ifdef HAVE_XF86DGA
955
 
  } else
956
 
  {
957
 
    ri.Printf(PRINT_ALL, "Using XFree86-VidModeExtension Version %d.%d\n",
958
 
              vidmode_MajorVersion, vidmode_MinorVersion);
959
 
    vidmode_ext = qtrue;
960
 
  }
961
 
#endif /* HAVE_XF86DGA */
962
 
 
963
 
  // Check for DGA      
964
 
  dga_MajorVersion = 0, dga_MinorVersion = 0;
965
 
#ifdef HAVE_XF86DGA
966
 
  if (in_dgamouse->value)
967
 
  {
968
 
    if (!XF86DGAQueryVersion(dpy, &dga_MajorVersion, &dga_MinorVersion))
969
 
    {
970
 
      // unable to query, probably not supported
971
 
      ri.Printf( PRINT_ALL, "Failed to detect XF86DGA Mouse\n" );
972
 
      ri.Cvar_Set( "in_dgamouse", "0" );
973
 
    } else
974
 
    {
975
 
      ri.Printf( PRINT_ALL, "XF86DGA Mouse (Version %d.%d) initialized\n",
976
 
                 dga_MajorVersion, dga_MinorVersion);
977
 
    }
978
 
  }
979
 
#endif /* HAVE_XF86DGA */
980
 
 
981
 
#ifdef HAVE_XF86DGA
982
 
  if (vidmode_ext)
983
 
  {
984
 
    int best_fit, best_dist, dist, x, y;
985
 
 
986
 
    XF86VidModeGetAllModeLines(dpy, scrnum, &num_vidmodes, &vidmodes);
987
 
 
988
 
    // Are we going fullscreen?  If so, let's change video mode
989
 
    if (fullscreen)
990
 
    {
991
 
      best_dist = 9999999;
992
 
      best_fit = -1;
993
 
 
994
 
      for (i = 0; i < num_vidmodes; i++)
995
 
      {
996
 
        if (glConfig.vidWidth > vidmodes[i]->hdisplay ||
997
 
            glConfig.vidHeight > vidmodes[i]->vdisplay)
998
 
          continue;
999
 
 
1000
 
        x = glConfig.vidWidth - vidmodes[i]->hdisplay;
1001
 
        y = glConfig.vidHeight - vidmodes[i]->vdisplay;
1002
 
        dist = (x * x) + (y * y);
1003
 
        if (dist < best_dist)
1004
 
        {
1005
 
          best_dist = dist;
1006
 
          best_fit = i;
1007
 
        }
1008
 
      }
1009
 
 
1010
 
      if (best_fit != -1)
1011
 
      {
1012
 
        actualWidth = vidmodes[best_fit]->hdisplay;
1013
 
        actualHeight = vidmodes[best_fit]->vdisplay;
1014
 
 
1015
 
        // change to the mode
1016
 
        XF86VidModeSwitchToMode(dpy, scrnum, vidmodes[best_fit]);
1017
 
        vidmode_active = qtrue;
1018
 
 
1019
 
        // Move the viewport to top left
1020
 
        XF86VidModeSetViewPort(dpy, scrnum, 0, 0);
1021
 
 
1022
 
        ri.Printf(PRINT_ALL, "XFree86-VidModeExtension Activated at %dx%d\n",
1023
 
                  actualWidth, actualHeight);
1024
 
 
1025
 
      } else
1026
 
      {
1027
 
        fullscreen = 0;
1028
 
        ri.Printf(PRINT_ALL, "XFree86-VidModeExtension: No acceptable modes found\n");
1029
 
      }
1030
 
    } else
1031
 
    {
1032
 
      ri.Printf(PRINT_ALL, "XFree86-VidModeExtension:  Ignored on non-fullscreen/Voodoo\n");
1033
 
    }
1034
 
  }
1035
 
#endif /* HAVE_XF86DGA */
1036
 
 
1037
 
 
1038
 
  if (!r_colorbits->value)
1039
 
    colorbits = 24;
1040
 
  else
1041
 
    colorbits = r_colorbits->value;
1042
 
 
1043
 
  if ( !Q_stricmp( r_glDriver->string, _3DFX_DRIVER_NAME ) )
1044
 
    colorbits = 16;
1045
 
 
1046
 
  if (!r_depthbits->value)
1047
 
    depthbits = 24;
1048
 
  else
1049
 
    depthbits = r_depthbits->value;
1050
 
  stencilbits = r_stencilbits->value;
1051
 
 
1052
 
  for (i = 0; i < 16; i++)
1053
 
  {
1054
 
    // 0 - default
1055
 
    // 1 - minus colorbits
1056
 
    // 2 - minus depthbits
1057
 
    // 3 - minus stencil
1058
 
    if ((i % 4) == 0 && i)
1059
 
    {
1060
 
      // one pass, reduce
1061
 
      switch (i / 4)
1062
 
      {
1063
 
      case 2 :
1064
 
        if (colorbits == 24)
1065
 
          colorbits = 16;
1066
 
        break;
1067
 
      case 1 :
1068
 
        if (depthbits == 24)
1069
 
          depthbits = 16;
1070
 
        else if (depthbits == 16)
1071
 
          depthbits = 8;
1072
 
      case 3 :
1073
 
        if (stencilbits == 24)
1074
 
          stencilbits = 16;
1075
 
        else if (stencilbits == 16)
1076
 
          stencilbits = 8;
1077
 
      }
1078
 
    }
1079
 
 
1080
 
    tcolorbits = colorbits;
1081
 
    tdepthbits = depthbits;
1082
 
    tstencilbits = stencilbits;
1083
 
 
1084
 
    if ((i % 4) == 3)
1085
 
    { // reduce colorbits
1086
 
      if (tcolorbits == 24)
1087
 
        tcolorbits = 16;
1088
 
    }
1089
 
 
1090
 
    if ((i % 4) == 2)
1091
 
    { // reduce depthbits
1092
 
      if (tdepthbits == 24)
1093
 
        tdepthbits = 16;
1094
 
      else if (tdepthbits == 16)
1095
 
        tdepthbits = 8;
1096
 
    }
1097
 
 
1098
 
    if ((i % 4) == 1)
1099
 
    { // reduce stencilbits
1100
 
      if (tstencilbits == 24)
1101
 
        tstencilbits = 16;
1102
 
      else if (tstencilbits == 16)
1103
 
        tstencilbits = 8;
1104
 
      else
1105
 
        tstencilbits = 0;
1106
 
    }
1107
 
 
1108
 
    if (tcolorbits == 24)
1109
 
    {
1110
 
      attrib[ATTR_RED_IDX] = 8;
1111
 
      attrib[ATTR_GREEN_IDX] = 8;
1112
 
      attrib[ATTR_BLUE_IDX] = 8;
1113
 
    } else
1114
 
    {
1115
 
      // must be 16 bit
1116
 
      attrib[ATTR_RED_IDX] = 4;
1117
 
      attrib[ATTR_GREEN_IDX] = 4;
1118
 
      attrib[ATTR_BLUE_IDX] = 4;
1119
 
    }
1120
 
 
1121
 
    attrib[ATTR_DEPTH_IDX] = tdepthbits; // default to 24 depth
1122
 
    attrib[ATTR_STENCIL_IDX] = tstencilbits;
1123
 
 
1124
 
    visinfo = qglXChooseVisual(dpy, scrnum, attrib);
1125
 
    if (!visinfo)
1126
 
    {
1127
 
      continue;
1128
 
    }
1129
 
 
1130
 
    ri.Printf( PRINT_ALL, "Using %d/%d/%d Color bits, %d depth, %d stencil display.\n", 
1131
 
               attrib[ATTR_RED_IDX], attrib[ATTR_GREEN_IDX], attrib[ATTR_BLUE_IDX],
1132
 
               attrib[ATTR_DEPTH_IDX], attrib[ATTR_STENCIL_IDX]);
1133
 
 
1134
 
    glConfig.colorBits = tcolorbits;
1135
 
    glConfig.depthBits = tdepthbits;
1136
 
    glConfig.stencilBits = tstencilbits;
1137
 
    break;
1138
 
  }
1139
 
 
1140
 
  if (!visinfo)
1141
 
  {
1142
 
    ri.Printf( PRINT_ALL, "Couldn't get a visual\n" );
1143
 
    return RSERR_INVALID_MODE;
1144
 
  }
1145
 
 
1146
 
  /* window attributes */
1147
 
  attr.background_pixel = BlackPixel(dpy, scrnum);
1148
 
  attr.border_pixel = 0;
1149
 
  attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone);
1150
 
  attr.event_mask = X_MASK;
1151
 
  if (vidmode_active)
1152
 
  {
1153
 
    mask = CWBackPixel | CWColormap | CWSaveUnder | CWBackingStore | 
1154
 
           CWEventMask | CWOverrideRedirect;
1155
 
    attr.override_redirect = True;
1156
 
    attr.backing_store = NotUseful;
1157
 
    attr.save_under = False;
1158
 
  } else
1159
 
    mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
1160
 
 
1161
 
  win = XCreateWindow(dpy, root, 0, 0, 
1162
 
                      actualWidth, actualHeight, 
1163
 
                      0, visinfo->depth, InputOutput,
1164
 
                      visinfo->visual, mask, &attr);
1165
 
 
1166
 
  XStoreName( dpy, win, CLIENT_WINDOW_TITLE );
1167
 
 
1168
 
  /* GH: Don't let the window be resized */
1169
 
  sizehints.flags = PMinSize | PMaxSize;
1170
 
  sizehints.min_width = sizehints.max_width = actualWidth;
1171
 
  sizehints.min_height = sizehints.max_height = actualHeight;
1172
 
 
1173
 
  XSetWMNormalHints( dpy, win, &sizehints );
1174
 
 
1175
 
  XMapWindow( dpy, win );
1176
 
 
1177
 
  if (vidmode_active)
1178
 
    XMoveWindow(dpy, win, 0, 0);
1179
 
 
1180
 
  XFlush(dpy);
1181
 
  XSync(dpy,False); // bk001130 - from cvs1.17 (mkv)
1182
 
  ctx = qglXCreateContext(dpy, visinfo, NULL, True);
1183
 
  XSync(dpy,False); // bk001130 - from cvs1.17 (mkv)
1184
 
 
1185
 
  /* GH: Free the visinfo after we're done with it */
1186
 
  XFree( visinfo );
1187
 
 
1188
 
  qglXMakeCurrent(dpy, win, ctx);
1189
 
 
1190
 
  // bk001130 - from cvs1.17 (mkv)
1191
 
  glstring = (char *)qglGetString (GL_RENDERER);
1192
 
  ri.Printf( PRINT_ALL, "GL_RENDERER: %s\n", glstring );
1193
 
 
1194
 
  // bk010122 - new software token (Indirect)
1195
 
  if ( !Q_stricmp( glstring, "Mesa X11")
1196
 
       || !Q_stricmp( glstring, "Mesa GLX Indirect") )
1197
 
  {
1198
 
    if ( !r_allowSoftwareGL->integer )
1199
 
    {
1200
 
      ri.Printf( PRINT_ALL, "\n\n***********************************************************\n" );
1201
 
      ri.Printf( PRINT_ALL, " You are using software Mesa (no hardware acceleration)!   \n" );
1202
 
      ri.Printf( PRINT_ALL, " Driver DLL used: %s\n", drivername ); 
1203
 
      ri.Printf( PRINT_ALL, " If this is intentional, add\n" );
1204
 
      ri.Printf( PRINT_ALL, "       \"+set r_allowSoftwareGL 1\"\n" );
1205
 
      ri.Printf( PRINT_ALL, " to the command line when starting the game.\n" );
1206
 
      ri.Printf( PRINT_ALL, "***********************************************************\n");
1207
 
      GLimp_Shutdown( );
1208
 
      return RSERR_INVALID_MODE;
1209
 
    } else
1210
 
    {
1211
 
      ri.Printf( PRINT_ALL, "...using software Mesa (r_allowSoftwareGL==1).\n" );
1212
 
    }
1213
 
  }
1214
 
 
1215
 
  return RSERR_OK;
1216
 
}
1217
 
 
1218
 
/*
1219
 
** GLW_InitExtensions
1220
 
*/
1221
 
static void GLW_InitExtensions( void )
1222
 
{
1223
 
  if ( !r_allowExtensions->integer )
1224
 
  {
1225
 
    ri.Printf( PRINT_ALL, "*** IGNORING OPENGL EXTENSIONS ***\n" );
1226
 
    return;
1227
 
  }
1228
 
 
1229
 
  ri.Printf( PRINT_ALL, "Initializing OpenGL extensions\n" );
1230
 
 
1231
 
  // GL_S3_s3tc
1232
 
  if ( Q_stristr( glConfig.extensions_string, "GL_S3_s3tc" ) )
1233
 
  {
1234
 
    if ( r_ext_compressed_textures->value )
1235
 
    {
1236
 
      glConfig.textureCompression = TC_S3TC;
1237
 
      ri.Printf( PRINT_ALL, "...using GL_S3_s3tc\n" );
1238
 
    } else
1239
 
    {
1240
 
      glConfig.textureCompression = TC_NONE;
1241
 
      ri.Printf( PRINT_ALL, "...ignoring GL_S3_s3tc\n" );
1242
 
    }
1243
 
  } else
1244
 
  {
1245
 
    glConfig.textureCompression = TC_NONE;
1246
 
    ri.Printf( PRINT_ALL, "...GL_S3_s3tc not found\n" );
1247
 
  }
1248
 
 
1249
 
  // GL_EXT_texture_env_add
1250
 
  glConfig.textureEnvAddAvailable = qfalse;
1251
 
  if ( Q_stristr( glConfig.extensions_string, "EXT_texture_env_add" ) )
1252
 
  {
1253
 
    if ( r_ext_texture_env_add->integer )
1254
 
    {
1255
 
      glConfig.textureEnvAddAvailable = qtrue;
1256
 
      ri.Printf( PRINT_ALL, "...using GL_EXT_texture_env_add\n" );
1257
 
    } else
1258
 
    {
1259
 
      glConfig.textureEnvAddAvailable = qfalse;
1260
 
      ri.Printf( PRINT_ALL, "...ignoring GL_EXT_texture_env_add\n" );
1261
 
    }
1262
 
  } else
1263
 
  {
1264
 
    ri.Printf( PRINT_ALL, "...GL_EXT_texture_env_add not found\n" );
1265
 
  }
1266
 
 
1267
 
  // GL_ARB_multitexture
1268
 
  qglMultiTexCoord2fARB = NULL;
1269
 
  qglActiveTextureARB = NULL;
1270
 
  qglClientActiveTextureARB = NULL;
1271
 
  if ( Q_stristr( glConfig.extensions_string, "GL_ARB_multitexture" ) )
1272
 
  {
1273
 
    if ( r_ext_multitexture->value )
1274
 
    {
1275
 
      qglMultiTexCoord2fARB = ( PFNGLMULTITEXCOORD2FARBPROC ) dlsym( glw_state.OpenGLLib, "glMultiTexCoord2fARB" );
1276
 
      qglActiveTextureARB = ( PFNGLACTIVETEXTUREARBPROC ) dlsym( glw_state.OpenGLLib, "glActiveTextureARB" );
1277
 
      qglClientActiveTextureARB = ( PFNGLCLIENTACTIVETEXTUREARBPROC ) dlsym( glw_state.OpenGLLib, "glClientActiveTextureARB" );
1278
 
 
1279
 
      if ( qglActiveTextureARB )
1280
 
      {
1281
 
        GLint glint = 0;
1282
 
        qglGetIntegerv( GL_MAX_ACTIVE_TEXTURES_ARB, &glint );
1283
 
        glConfig.maxActiveTextures = (int) glint;
1284
 
 
1285
 
        if ( glConfig.maxActiveTextures > 1 )
1286
 
        {
1287
 
          ri.Printf( PRINT_ALL, "...using GL_ARB_multitexture\n" );
1288
 
        } else
1289
 
        {
1290
 
          qglMultiTexCoord2fARB = NULL;
1291
 
          qglActiveTextureARB = NULL;
1292
 
          qglClientActiveTextureARB = NULL;
1293
 
          ri.Printf( PRINT_ALL, "...not using GL_ARB_multitexture, < 2 texture units\n" );
1294
 
        }
1295
 
      }
1296
 
    } else
1297
 
    {
1298
 
      ri.Printf( PRINT_ALL, "...ignoring GL_ARB_multitexture\n" );
1299
 
    }
1300
 
  } else
1301
 
  {
1302
 
    ri.Printf( PRINT_ALL, "...GL_ARB_multitexture not found\n" );
1303
 
  }
1304
 
 
1305
 
  // GL_EXT_compiled_vertex_array
1306
 
  if ( Q_stristr( glConfig.extensions_string, "GL_EXT_compiled_vertex_array" ) )
1307
 
  {
1308
 
    if ( r_ext_compiled_vertex_array->value )
1309
 
    {
1310
 
      ri.Printf( PRINT_ALL, "...using GL_EXT_compiled_vertex_array\n" );
1311
 
      qglLockArraysEXT = ( void ( APIENTRY * )( int, int ) ) dlsym( glw_state.OpenGLLib, "glLockArraysEXT" );
1312
 
      qglUnlockArraysEXT = ( void ( APIENTRY * )( void ) ) dlsym( glw_state.OpenGLLib, "glUnlockArraysEXT" );
1313
 
      if (!qglLockArraysEXT || !qglUnlockArraysEXT)
1314
 
      {
1315
 
        ri.Error (ERR_FATAL, "bad getprocaddress");
1316
 
      }
1317
 
    } else
1318
 
    {
1319
 
      ri.Printf( PRINT_ALL, "...ignoring GL_EXT_compiled_vertex_array\n" );
1320
 
    }
1321
 
  } else
1322
 
  {
1323
 
    ri.Printf( PRINT_ALL, "...GL_EXT_compiled_vertex_array not found\n" );
1324
 
  }
1325
 
 
1326
 
  textureFilterAnisotropic = qfalse;
1327
 
  if ( strstr( glConfig.extensions_string, "GL_EXT_texture_filter_anisotropic" ) )
1328
 
  {
1329
 
    if ( r_ext_texture_filter_anisotropic->integer ) {
1330
 
      qglGetIntegerv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisotropy );
1331
 
      if ( maxAnisotropy <= 0 ) {
1332
 
        ri.Printf( PRINT_ALL, "...GL_EXT_texture_filter_anisotropic not properly supported!\n" );
1333
 
        maxAnisotropy = 0;
1334
 
      }
1335
 
      else
1336
 
      {
1337
 
        ri.Printf( PRINT_ALL, "...using GL_EXT_texture_filter_anisotropic (max: %i)\n", maxAnisotropy );
1338
 
        textureFilterAnisotropic = qtrue;
1339
 
      }
1340
 
    }
1341
 
    else
1342
 
    {
1343
 
      ri.Printf( PRINT_ALL, "...ignoring GL_EXT_texture_filter_anisotropic\n" );
1344
 
    }
1345
 
  }
1346
 
  else
1347
 
  {
1348
 
    ri.Printf( PRINT_ALL, "...GL_EXT_texture_filter_anisotropic not found\n" );
1349
 
  }
1350
 
}
1351
 
 
1352
 
static void GLW_InitGamma(void)
1353
 
{
1354
 
  /* Minimum extension version required */
1355
 
  #define GAMMA_MINMAJOR 2
1356
 
  #define GAMMA_MINMINOR 0
1357
 
  
1358
 
  glConfig.deviceSupportsGamma = qfalse;
1359
 
 
1360
 
#ifdef HAVE_XF86DGA
1361
 
  if (vidmode_ext)
1362
 
  {
1363
 
    if (vidmode_MajorVersion < GAMMA_MINMAJOR || 
1364
 
        (vidmode_MajorVersion == GAMMA_MINMAJOR && vidmode_MinorVersion < GAMMA_MINMINOR)) {
1365
 
      ri.Printf( PRINT_ALL, "XF86 Gamma extension not supported in this version\n");
1366
 
      return;
1367
 
    }
1368
 
    XF86VidModeGetGamma(dpy, scrnum, &vidmode_InitialGamma);
1369
 
    ri.Printf( PRINT_ALL, "XF86 Gamma extension initialized\n");
1370
 
    glConfig.deviceSupportsGamma = qtrue;
1371
 
  }
1372
 
#endif /* HAVE_XF86DGA */
1373
 
}
1374
 
 
1375
 
/*
1376
 
** GLW_LoadOpenGL
1377
 
**
1378
 
** GLimp_win.c internal function that that attempts to load and use 
1379
 
** a specific OpenGL DLL.
1380
 
*/
1381
 
static qboolean GLW_LoadOpenGL( const char *name )
1382
 
{
1383
 
  qboolean fullscreen;
1384
 
 
1385
 
  ri.Printf( PRINT_ALL, "...loading %s: ", name );
1386
 
 
1387
 
  // disable the 3Dfx splash screen and set gamma
1388
 
  // we do this all the time, but it shouldn't hurt anything
1389
 
  // on non-3Dfx stuff
1390
 
  putenv("FX_GLIDE_NO_SPLASH=0");
1391
 
 
1392
 
  // Mesa VooDoo hacks
1393
 
  putenv("MESA_GLX_FX=fullscreen\n");
1394
 
 
1395
 
  // load the QGL layer
1396
 
  if ( QGL_Init( name ) )
1397
 
  {
1398
 
    fullscreen = r_fullscreen->integer;
1399
 
 
1400
 
    // create the window and set up the context
1401
 
    if ( !GLW_StartDriverAndSetMode( name, r_mode->integer, fullscreen ) )
1402
 
    {
1403
 
      if (r_mode->integer != 3)
1404
 
      {
1405
 
        if ( !GLW_StartDriverAndSetMode( name, 3, fullscreen ) )
1406
 
        {
1407
 
          goto fail;
1408
 
        }
1409
 
      } else
1410
 
        goto fail;
1411
 
    }
1412
 
 
1413
 
    return qtrue;
1414
 
  } else
1415
 
  {
1416
 
    ri.Printf( PRINT_ALL, "failed\n" );
1417
 
  }
1418
 
  fail:
1419
 
 
1420
 
  QGL_Shutdown();
1421
 
 
1422
 
  return qfalse;
1423
 
}
1424
 
 
1425
 
/*
1426
 
** XErrorHandler
1427
 
**   the default X error handler exits the application
1428
 
**   I found out that on some hosts some operations would raise X errors (GLXUnsupportedPrivateRequest)
1429
 
**   but those don't seem to be fatal .. so the default would be to just ignore them
1430
 
**   our implementation mimics the default handler behaviour (not completely cause I'm lazy)
1431
 
*/
1432
 
int qXErrorHandler(Display *dpy, XErrorEvent *ev)
1433
 
{
1434
 
  static char buf[1024];
1435
 
  XGetErrorText(dpy, ev->error_code, buf, 1024);
1436
 
  ri.Printf( PRINT_ALL, "X Error of failed request: %s\n", buf);
1437
 
  ri.Printf( PRINT_ALL, "  Major opcode of failed request: %d\n", ev->request_code, buf);
1438
 
  ri.Printf( PRINT_ALL, "  Minor opcode of failed request: %d\n", ev->minor_code);  
1439
 
  ri.Printf( PRINT_ALL, "  Serial number of failed request: %d\n", ev->serial);
1440
 
  return 0;
1441
 
}
1442
 
 
1443
 
/*
1444
 
** GLimp_Init
1445
 
**
1446
 
** This routine is responsible for initializing the OS specific portions
1447
 
** of OpenGL.  
1448
 
*/
1449
 
void GLimp_Init( void )
1450
 
{
1451
 
  qboolean attemptedlibGL = qfalse;
1452
 
  qboolean attempted3Dfx = qfalse;
1453
 
  qboolean success = qfalse;
1454
 
  char  buf[1024];
1455
 
  cvar_t *lastValidRenderer = ri.Cvar_Get( "r_lastValidRenderer", "(uninitialized)", CVAR_ARCHIVE );
1456
 
 
1457
 
  // guarded, as this is only relevant to SMP renderer thread
1458
 
#ifdef SMP
1459
 
  if (!XInitThreads())
1460
 
  {
1461
 
    Com_Printf("GLimp_Init() - XInitThreads() failed, disabling r_smp\n");
1462
 
    ri.Cvar_Set( "r_smp", "0" );
1463
 
  }
1464
 
#endif
1465
 
 
1466
 
  r_allowSoftwareGL = ri.Cvar_Get( "r_allowSoftwareGL", "0", CVAR_LATCH );
1467
 
 
1468
 
  r_previousglDriver = ri.Cvar_Get( "r_previousglDriver", "", CVAR_ROM );
1469
 
 
1470
 
  InitSig();
1471
 
 
1472
 
  IN_Init();   // rcg08312005 moved into glimp.
1473
 
 
1474
 
  // Hack here so that if the UI 
1475
 
  if ( *r_previousglDriver->string )
1476
 
  {
1477
 
    // The UI changed it on us, hack it back
1478
 
    // This means the renderer can't be changed on the fly
1479
 
    ri.Cvar_Set( "r_glDriver", r_previousglDriver->string );
1480
 
  }
1481
 
  
1482
 
  // set up our custom error handler for X failures
1483
 
  XSetErrorHandler(&qXErrorHandler);
1484
 
 
1485
 
  //
1486
 
  // load and initialize the specific OpenGL driver
1487
 
  //
1488
 
  if ( !GLW_LoadOpenGL( r_glDriver->string ) )
1489
 
  {
1490
 
    if ( !Q_stricmp( r_glDriver->string, OPENGL_DRIVER_NAME ) )
1491
 
    {
1492
 
      attemptedlibGL = qtrue;
1493
 
    } else if ( !Q_stricmp( r_glDriver->string, _3DFX_DRIVER_NAME ) )
1494
 
    {
1495
 
      attempted3Dfx = qtrue;
1496
 
    }
1497
 
 
1498
 
    #if 0
1499
 
    // TTimo
1500
 
    // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=455
1501
 
    // old legacy load code, was confusing people who had a bad OpenGL setup
1502
 
    if ( !attempted3Dfx && !success )
1503
 
    {
1504
 
      attempted3Dfx = qtrue;
1505
 
      if ( GLW_LoadOpenGL( _3DFX_DRIVER_NAME ) )
1506
 
      {
1507
 
        ri.Cvar_Set( "r_glDriver", _3DFX_DRIVER_NAME );
1508
 
        r_glDriver->modified = qfalse;
1509
 
        success = qtrue;
1510
 
      }
1511
 
    }
1512
 
    #endif
1513
 
 
1514
 
    // try ICD before trying 3Dfx standalone driver
1515
 
    if ( !attemptedlibGL && !success )
1516
 
    {
1517
 
      attemptedlibGL = qtrue;
1518
 
      if ( GLW_LoadOpenGL( OPENGL_DRIVER_NAME ) )
1519
 
      {
1520
 
        ri.Cvar_Set( "r_glDriver", OPENGL_DRIVER_NAME );
1521
 
        r_glDriver->modified = qfalse;
1522
 
        success = qtrue;
1523
 
      }
1524
 
    }
1525
 
 
1526
 
    if (!success)
1527
 
      ri.Error( ERR_FATAL, "GLimp_Init() - could not load OpenGL subsystem\n" );
1528
 
 
1529
 
  }
1530
 
 
1531
 
  // Save it in case the UI stomps it
1532
 
  ri.Cvar_Set( "r_previousglDriver", r_glDriver->string );
1533
 
 
1534
 
  // This values force the UI to disable driver selection
1535
 
  glConfig.driverType = GLDRV_ICD;
1536
 
  glConfig.hardwareType = GLHW_GENERIC;
1537
 
 
1538
 
  // get our config strings
1539
 
  Q_strncpyz( glConfig.vendor_string, (char *)qglGetString (GL_VENDOR), sizeof( glConfig.vendor_string ) );
1540
 
  Q_strncpyz( glConfig.renderer_string, (char *)qglGetString (GL_RENDERER), sizeof( glConfig.renderer_string ) );
1541
 
  if (*glConfig.renderer_string && glConfig.renderer_string[strlen(glConfig.renderer_string) - 1] == '\n')
1542
 
    glConfig.renderer_string[strlen(glConfig.renderer_string) - 1] = 0;
1543
 
  Q_strncpyz( glConfig.version_string, (char *)qglGetString (GL_VERSION), sizeof( glConfig.version_string ) );
1544
 
  Q_strncpyz( glConfig.extensions_string, (char *)qglGetString (GL_EXTENSIONS), sizeof( glConfig.extensions_string ) );
1545
 
 
1546
 
  //
1547
 
  // chipset specific configuration
1548
 
  //
1549
 
  strcpy( buf, glConfig.renderer_string );
1550
 
  strlwr( buf );
1551
 
 
1552
 
  //
1553
 
  // NOTE: if changing cvars, do it within this block.  This allows them
1554
 
  // to be overridden when testing driver fixes, etc. but only sets
1555
 
  // them to their default state when the hardware is first installed/run.
1556
 
  //
1557
 
  if ( Q_stricmp( lastValidRenderer->string, glConfig.renderer_string ) )
1558
 
  {
1559
 
    glConfig.hardwareType = GLHW_GENERIC;
1560
 
 
1561
 
    ri.Cvar_Set( "r_textureMode", "GL_LINEAR_MIPMAP_NEAREST" );
1562
 
 
1563
 
    // VOODOO GRAPHICS w/ 2MB
1564
 
    if ( Q_stristr( buf, "voodoo graphics/1 tmu/2 mb" ) )
1565
 
    {
1566
 
      ri.Cvar_Set( "r_picmip", "2" );
1567
 
      ri.Cvar_Get( "r_picmip", "1", CVAR_ARCHIVE | CVAR_LATCH );
1568
 
    } else
1569
 
    {
1570
 
      ri.Cvar_Set( "r_picmip", "1" );
1571
 
 
1572
 
      if ( Q_stristr( buf, "rage 128" ) || Q_stristr( buf, "rage128" ) )
1573
 
      {
1574
 
        ri.Cvar_Set( "r_finish", "0" );
1575
 
      }
1576
 
      // Savage3D and Savage4 should always have trilinear enabled
1577
 
      else if ( Q_stristr( buf, "savage3d" ) || Q_stristr( buf, "s3 savage4" ) )
1578
 
      {
1579
 
        ri.Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_LINEAR" );
1580
 
      }
1581
 
    }
1582
 
  }
1583
 
 
1584
 
  //
1585
 
  // this is where hardware specific workarounds that should be
1586
 
  // detected/initialized every startup should go.
1587
 
  //
1588
 
  if ( Q_stristr( buf, "banshee" ) || Q_stristr( buf, "Voodoo_Graphics" ) )
1589
 
  {
1590
 
    glConfig.hardwareType = GLHW_3DFX_2D3D;
1591
 
  } else if ( Q_stristr( buf, "rage pro" ) || Q_stristr( buf, "RagePro" ) )
1592
 
  {
1593
 
    glConfig.hardwareType = GLHW_RAGEPRO;
1594
 
  } else if ( Q_stristr( buf, "permedia2" ) )
1595
 
  {
1596
 
    glConfig.hardwareType = GLHW_PERMEDIA2;
1597
 
  } else if ( Q_stristr( buf, "riva 128" ) )
1598
 
  {
1599
 
    glConfig.hardwareType = GLHW_RIVA128;
1600
 
  } else if ( Q_stristr( buf, "riva tnt " ) )
1601
 
  {
1602
 
  }
1603
 
 
1604
 
  ri.Cvar_Set( "r_lastValidRenderer", glConfig.renderer_string );
1605
 
 
1606
 
  // initialize extensions
1607
 
  GLW_InitExtensions();
1608
 
  GLW_InitGamma();
1609
 
 
1610
 
  InitSig(); // not clear why this is at begin & end of function
1611
 
 
1612
 
  return;
1613
 
}
1614
 
 
1615
 
 
1616
 
/*
1617
 
** GLimp_EndFrame
1618
 
** 
1619
 
** Responsible for doing a swapbuffers and possibly for other stuff
1620
 
** as yet to be determined.  Probably better not to make this a GLimp
1621
 
** function and instead do a call to GLimp_SwapBuffers.
1622
 
*/
1623
 
void GLimp_EndFrame (void)
1624
 
{
1625
 
  // don't flip if drawing to front buffer
1626
 
  if ( Q_stricmp( r_drawBuffer->string, "GL_FRONT" ) != 0 )
1627
 
  {
1628
 
    qglXSwapBuffers(dpy, win);
1629
 
  }
1630
 
 
1631
 
  // check logging
1632
 
  QGL_EnableLogging( (qboolean)r_logFile->integer ); // bk001205 - was ->value
1633
 
}
1634
 
 
1635
 
#ifdef SMP
1636
 
/*
1637
 
===========================================================
1638
 
 
1639
 
SMP acceleration
1640
 
 
1641
 
===========================================================
1642
 
*/
1643
 
 
1644
 
static pthread_mutex_t  smpMutex = PTHREAD_MUTEX_INITIALIZER;
1645
 
 
1646
 
static pthread_cond_t           renderCommandsEvent = PTHREAD_COND_INITIALIZER;
1647
 
static pthread_cond_t           renderCompletedEvent = PTHREAD_COND_INITIALIZER;
1648
 
 
1649
 
static void (*glimpRenderThread)( void );
1650
 
 
1651
 
static void *GLimp_RenderThreadWrapper( void *arg )
1652
 
{
1653
 
        Com_Printf( "Render thread starting\n" );
1654
 
 
1655
 
  glimpRenderThread();
1656
 
 
1657
 
        qglXMakeCurrent( dpy, None, NULL );
1658
 
 
1659
 
        Com_Printf( "Render thread terminating\n" );
1660
 
 
1661
 
        return arg;
1662
 
}
1663
 
 
1664
 
qboolean GLimp_SpawnRenderThread( void (*function)( void ) )
1665
 
{
1666
 
        pthread_t renderThread;
1667
 
        int ret;
1668
 
 
1669
 
        pthread_mutex_init( &smpMutex, NULL );
1670
 
 
1671
 
        pthread_cond_init( &renderCommandsEvent, NULL );
1672
 
        pthread_cond_init( &renderCompletedEvent, NULL );
1673
 
 
1674
 
  glimpRenderThread = function;
1675
 
 
1676
 
        ret = pthread_create( &renderThread,
1677
 
                                                  NULL,                 // attributes
1678
 
                                                  GLimp_RenderThreadWrapper,
1679
 
                                                  NULL );               // argument
1680
 
        if ( ret ) {
1681
 
                ri.Printf( PRINT_ALL, "pthread_create returned %d: %s", ret, strerror( ret ) );
1682
 
    return qfalse;
1683
 
        } else {
1684
 
                ret = pthread_detach( renderThread );
1685
 
                if ( ret ) {
1686
 
                        ri.Printf( PRINT_ALL, "pthread_detach returned %d: %s", ret, strerror( ret ) );
1687
 
                }
1688
 
  }
1689
 
 
1690
 
  return qtrue;
1691
 
}
1692
 
 
1693
 
static volatile void    *smpData = NULL;
1694
 
static volatile qboolean smpDataReady;
1695
 
 
1696
 
void *GLimp_RendererSleep( void )
1697
 
{
1698
 
        void  *data;
1699
 
 
1700
 
        qglXMakeCurrent( dpy, None, NULL );
1701
 
 
1702
 
        pthread_mutex_lock( &smpMutex );
1703
 
        {
1704
 
                smpData = NULL;
1705
 
                smpDataReady = qfalse;
1706
 
 
1707
 
                // after this, the front end can exit GLimp_FrontEndSleep
1708
 
                pthread_cond_signal( &renderCompletedEvent );
1709
 
 
1710
 
                while ( !smpDataReady ) {
1711
 
                        pthread_cond_wait( &renderCommandsEvent, &smpMutex );
1712
 
                }
1713
 
 
1714
 
                data = (void *)smpData;
1715
 
        }
1716
 
        pthread_mutex_unlock( &smpMutex );
1717
 
 
1718
 
        qglXMakeCurrent( dpy, win, ctx );
1719
 
 
1720
 
  return data;
1721
 
}
1722
 
 
1723
 
void GLimp_FrontEndSleep( void )
1724
 
{
1725
 
        pthread_mutex_lock( &smpMutex );
1726
 
        {
1727
 
                while ( smpData ) {
1728
 
                        pthread_cond_wait( &renderCompletedEvent, &smpMutex );
1729
 
                }
1730
 
        }
1731
 
        pthread_mutex_unlock( &smpMutex );
1732
 
 
1733
 
        qglXMakeCurrent( dpy, win, ctx );
1734
 
}
1735
 
 
1736
 
void GLimp_WakeRenderer( void *data )
1737
 
{
1738
 
        qglXMakeCurrent( dpy, None, NULL );
1739
 
 
1740
 
        pthread_mutex_lock( &smpMutex );
1741
 
        {
1742
 
                assert( smpData == NULL );
1743
 
                smpData = data;
1744
 
                smpDataReady = qtrue;
1745
 
 
1746
 
                // after this, the renderer can continue through GLimp_RendererSleep
1747
 
                pthread_cond_signal( &renderCommandsEvent );
1748
 
        }
1749
 
        pthread_mutex_unlock( &smpMutex );
1750
 
}
1751
 
 
1752
 
#else
1753
 
 
1754
 
void GLimp_RenderThreadWrapper( void *stub ) {}
1755
 
qboolean GLimp_SpawnRenderThread( void (*function)( void ) ) {
1756
 
        ri.Printf( PRINT_WARNING, "ERROR: SMP support was disabled at compile time\n");
1757
 
  return qfalse;
1758
 
}
1759
 
void *GLimp_RendererSleep( void ) {
1760
 
  return NULL;
1761
 
}
1762
 
void GLimp_FrontEndSleep( void ) {}
1763
 
void GLimp_WakeRenderer( void *data ) {}
1764
 
 
1765
 
#endif
1766
 
 
1767
 
/*****************************************************************************/
1768
 
/* MOUSE                                                                     */
1769
 
/*****************************************************************************/
1770
 
 
1771
 
void IN_Init(void) {
1772
 
        Com_Printf ("\n------- Input Initialization -------\n");
1773
 
  // mouse variables
1774
 
  in_mouse = Cvar_Get ("in_mouse", "1", CVAR_ARCHIVE);
1775
 
  in_dgamouse = Cvar_Get ("in_dgamouse", "1", CVAR_ARCHIVE);
1776
 
  in_shiftedKeys = Cvar_Get ("in_shiftedKeys", "0", CVAR_ARCHIVE);
1777
 
        
1778
 
        // turn on-off sub-frame timing of X events
1779
 
        in_subframe = Cvar_Get ("in_subframe", "1", CVAR_ARCHIVE);
1780
 
        
1781
 
        // developer feature, allows to break without loosing mouse pointer
1782
 
        in_nograb = Cvar_Get ("in_nograb", "0", 0);
1783
 
 
1784
 
  // bk001130 - from cvs.17 (mkv), joystick variables
1785
 
  in_joystick = Cvar_Get ("in_joystick", "0", CVAR_ARCHIVE|CVAR_LATCH);
1786
 
  // bk001130 - changed this to match win32
1787
 
  in_joystickDebug = Cvar_Get ("in_debugjoystick", "0", CVAR_TEMP);
1788
 
  joy_threshold = Cvar_Get ("joy_threshold", "0.15", CVAR_ARCHIVE); // FIXME: in_joythreshold
1789
 
 
1790
 
  Cvar_Set( "cl_platformSensitivity", "2.0" );
1791
 
 
1792
 
  if (in_mouse->value)
1793
 
    mouse_avail = qtrue;
1794
 
  else
1795
 
    mouse_avail = qfalse;
1796
 
 
1797
 
  IN_StartupJoystick( ); // bk001130 - from cvs1.17 (mkv)
1798
 
        Com_Printf ("------------------------------------\n");
1799
 
}
1800
 
 
1801
 
void IN_Shutdown(void)
1802
 
{
1803
 
  mouse_avail = qfalse;
1804
 
}
1805
 
 
1806
 
void IN_Frame (void) {
1807
 
 
1808
 
  // bk001130 - from cvs 1.17 (mkv)
1809
 
  IN_JoyMove(); // FIXME: disable if on desktop?
1810
 
 
1811
 
  if ( cls.keyCatchers & KEYCATCH_CONSOLE )
1812
 
  {
1813
 
    // temporarily deactivate if not in the game and
1814
 
    // running on the desktop
1815
 
    // voodoo always counts as full screen
1816
 
    if (Cvar_VariableValue ("r_fullscreen") == 0
1817
 
        && strcmp( Cvar_VariableString("r_glDriver"), _3DFX_DRIVER_NAME ) )
1818
 
    {
1819
 
      IN_DeactivateMouse ();
1820
 
      return;
1821
 
    }
1822
 
  }
1823
 
 
1824
 
  IN_ActivateMouse();
1825
 
}
1826
 
 
1827
 
void IN_Activate(void)
1828
 
{
1829
 
}
1830
 
 
1831
 
// bk001130 - cvs1.17 joystick code (mkv) was here, no linux_joystick.c
1832
 
 
1833
 
void Sys_SendKeyEvents (void) {
1834
 
  // XEvent event; // bk001204 - unused
1835
 
 
1836
 
  if (!dpy)
1837
 
    return;
1838
 
  HandleEvents();
1839
 
}
1840
 
 
1841
 
 
1842
 
// bk010216 - added stubs for non-Linux UNIXes here
1843
 
// FIXME - use NO_JOYSTICK or something else generic
1844
 
 
1845
 
#if (defined( __FreeBSD__ ) || defined( __sun)) // rb010123
1846
 
void IN_StartupJoystick( void ) {}
1847
 
void IN_JoyMove( void ) {}
1848
 
#endif
1849
 
 
1850
 
#endif  // !USE_SDL_VIDEO
1851