linux_glimp.c 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388
  1. /*
  2. ** GLW_IMP.C
  3. **
  4. ** This file contains ALL Linux specific stuff having to do with the
  5. ** OpenGL refresh. When a port is being made the following functions
  6. ** must be implemented by the port:
  7. **
  8. ** GLimp_EndFrame
  9. ** GLimp_Init
  10. ** GLimp_Shutdown
  11. ** GLimp_SwitchFullscreen
  12. **
  13. */
  14. #include <termios.h>
  15. #include <sys/ioctl.h>
  16. #include <sys/stat.h>
  17. #include <sys/vt.h>
  18. #include <stdarg.h>
  19. #include <stdio.h>
  20. #include <signal.h>
  21. #include <pthread.h>
  22. #include <semaphore.h>
  23. //#include "../qcommon/qcommon.h"
  24. //#include "../client/keys.h"
  25. #include "../renderer/tr_local.h"
  26. #include "../client/client.h"
  27. #include "unix_glw.h"
  28. #include <GL/glx.h>
  29. #include <X11/keysym.h>
  30. #include <X11/cursorfont.h>
  31. #include <X11/extensions/xf86dga.h>
  32. #include <X11/extensions/xf86vmode.h>
  33. typedef enum {
  34. RSERR_OK,
  35. RSERR_INVALID_FULLSCREEN,
  36. RSERR_INVALID_MODE,
  37. RSERR_UNKNOWN
  38. } rserr_t;
  39. glwstate_t glw_state;
  40. static Display *dpy = NULL;
  41. static int scrnum;
  42. static Window win = 0;
  43. static GLXContext ctx = NULL;
  44. static qboolean autorepeaton = qtrue;
  45. #define KEY_MASK (KeyPressMask | KeyReleaseMask)
  46. #define MOUSE_MASK (ButtonPressMask | ButtonReleaseMask | \
  47. PointerMotionMask | ButtonMotionMask )
  48. #define X_MASK (KEY_MASK | MOUSE_MASK | VisibilityChangeMask | StructureNotifyMask )
  49. static qboolean mouse_avail;
  50. static qboolean mouse_active;
  51. static int mx, my;
  52. static cvar_t *in_mouse;
  53. static cvar_t *in_dgamouse;
  54. static cvar_t *r_fakeFullscreen;
  55. qboolean dgamouse = qfalse;
  56. qboolean vidmode_ext = qfalse;
  57. static int win_x, win_y;
  58. static XF86VidModeModeInfo **vidmodes;
  59. static int default_dotclock_vidmode;
  60. static int num_vidmodes;
  61. static qboolean vidmode_active = qfalse;
  62. static int mouse_accel_numerator;
  63. static int mouse_accel_denominator;
  64. static int mouse_threshold;
  65. /*****************************************************************************/
  66. /* KEYBOARD */
  67. /*****************************************************************************/
  68. static unsigned int keyshift[256]; // key to map to if shift held down in console
  69. static qboolean shift_down=qfalse;
  70. static char *XLateKey(XKeyEvent *ev, int *key)
  71. {
  72. static char buf[64];
  73. KeySym keysym;
  74. static qboolean setup = qfalse;
  75. int i;
  76. *key = 0;
  77. XLookupString(ev, buf, sizeof buf, &keysym, 0);
  78. // ri.Printf( PRINT_ALL, "keysym=%04X\n", (int)keysym);
  79. switch(keysym)
  80. {
  81. case XK_KP_Page_Up:
  82. case XK_KP_9: *key = K_KP_PGUP; break;
  83. case XK_Page_Up: *key = K_PGUP; break;
  84. case XK_KP_Page_Down:
  85. case XK_KP_3: *key = K_KP_PGDN; break;
  86. case XK_Page_Down: *key = K_PGDN; break;
  87. case XK_KP_Home: *key = K_KP_HOME; break;
  88. case XK_KP_7: *key = K_KP_HOME; break;
  89. case XK_Home: *key = K_HOME; break;
  90. case XK_KP_End:
  91. case XK_KP_1: *key = K_KP_END; break;
  92. case XK_End: *key = K_END; break;
  93. case XK_KP_Left: *key = K_KP_LEFTARROW; break;
  94. case XK_KP_4: *key = K_KP_LEFTARROW; break;
  95. case XK_Left: *key = K_LEFTARROW; break;
  96. case XK_KP_Right: *key = K_KP_RIGHTARROW; break;
  97. case XK_KP_6: *key = K_KP_RIGHTARROW; break;
  98. case XK_Right: *key = K_RIGHTARROW; break;
  99. case XK_KP_Down:
  100. case XK_KP_2: *key = K_KP_DOWNARROW; break;
  101. case XK_Down: *key = K_DOWNARROW; break;
  102. case XK_KP_Up:
  103. case XK_KP_8: *key = K_KP_UPARROW; break;
  104. case XK_Up: *key = K_UPARROW; break;
  105. case XK_Escape: *key = K_ESCAPE; break;
  106. case XK_KP_Enter: *key = K_KP_ENTER; break;
  107. case XK_Return: *key = K_ENTER; break;
  108. case XK_Tab: *key = K_TAB; break;
  109. case XK_F1: *key = K_F1; break;
  110. case XK_F2: *key = K_F2; break;
  111. case XK_F3: *key = K_F3; break;
  112. case XK_F4: *key = K_F4; break;
  113. case XK_F5: *key = K_F5; break;
  114. case XK_F6: *key = K_F6; break;
  115. case XK_F7: *key = K_F7; break;
  116. case XK_F8: *key = K_F8; break;
  117. case XK_F9: *key = K_F9; break;
  118. case XK_F10: *key = K_F10; break;
  119. case XK_F11: *key = K_F11; break;
  120. case XK_F12: *key = K_F12; break;
  121. // case XK_BackSpace: *key = K_BACKSPACE; break;
  122. case XK_BackSpace: *key = 8; break; // ctrl-h
  123. case XK_KP_Delete:
  124. case XK_KP_Decimal: *key = K_KP_DEL; break;
  125. case XK_Delete: *key = K_DEL; break;
  126. case XK_Pause: *key = K_PAUSE; break;
  127. case XK_Shift_L:
  128. case XK_Shift_R: *key = K_SHIFT; break;
  129. case XK_Execute:
  130. case XK_Control_L:
  131. case XK_Control_R: *key = K_CTRL; break;
  132. case XK_Alt_L:
  133. case XK_Meta_L:
  134. case XK_Alt_R:
  135. case XK_Meta_R: *key = K_ALT; break;
  136. case XK_KP_Begin: *key = K_KP_5; break;
  137. case XK_Insert: *key = K_INS; break;
  138. case XK_KP_Insert:
  139. case XK_KP_0: *key = K_KP_INS; break;
  140. case XK_KP_Multiply: *key = '*'; break;
  141. case XK_KP_Add: *key = K_KP_PLUS; break;
  142. case XK_KP_Subtract: *key = K_KP_MINUS; break;
  143. case XK_KP_Divide: *key = K_KP_SLASH; break;
  144. default:
  145. *key = *(unsigned char *)buf;
  146. if (*key >= 'A' && *key <= 'Z')
  147. *key = *key - 'A' + 'a';
  148. break;
  149. }
  150. return buf;
  151. }
  152. // ========================================================================
  153. // makes a null cursor
  154. // ========================================================================
  155. static Cursor CreateNullCursor(Display *display, Window root)
  156. {
  157. Pixmap cursormask;
  158. XGCValues xgc;
  159. GC gc;
  160. XColor dummycolour;
  161. Cursor cursor;
  162. cursormask = XCreatePixmap(display, root, 1, 1, 1/*depth*/);
  163. xgc.function = GXclear;
  164. gc = XCreateGC(display, cursormask, GCFunction, &xgc);
  165. XFillRectangle(display, cursormask, gc, 0, 0, 1, 1);
  166. dummycolour.pixel = 0;
  167. dummycolour.red = 0;
  168. dummycolour.flags = 04;
  169. cursor = XCreatePixmapCursor(display, cursormask, cursormask,
  170. &dummycolour,&dummycolour, 0,0);
  171. XFreePixmap(display,cursormask);
  172. XFreeGC(display,gc);
  173. return cursor;
  174. }
  175. static void install_grabs(void)
  176. {
  177. // inviso cursor
  178. XDefineCursor(dpy, win, CreateNullCursor(dpy, win));
  179. XGrabPointer(dpy, win,
  180. False,
  181. MOUSE_MASK,
  182. GrabModeAsync, GrabModeAsync,
  183. win,
  184. None,
  185. CurrentTime);
  186. XGetPointerControl(dpy, &mouse_accel_numerator, &mouse_accel_denominator,
  187. &mouse_threshold);
  188. XChangePointerControl(dpy, qtrue, qtrue, 2, 1, 0);
  189. if (in_dgamouse->value) {
  190. int MajorVersion, MinorVersion;
  191. if (!XF86DGAQueryVersion(dpy, &MajorVersion, &MinorVersion)) {
  192. // unable to query, probalby not supported
  193. ri.Printf( PRINT_ALL, "Failed to detect XF86DGA Mouse\n" );
  194. ri.Cvar_Set( "in_dgamouse", "0" );
  195. } else {
  196. dgamouse = qtrue;
  197. XF86DGADirectVideo(dpy, DefaultScreen(dpy), XF86DGADirectMouse);
  198. XWarpPointer(dpy, None, win, 0, 0, 0, 0, 0, 0);
  199. }
  200. } else {
  201. XWarpPointer(dpy, None, win,
  202. 0, 0, 0, 0,
  203. glConfig.vidWidth / 2, glConfig.vidHeight / 2);
  204. }
  205. XGrabKeyboard(dpy, win,
  206. False,
  207. GrabModeAsync, GrabModeAsync,
  208. CurrentTime);
  209. // XSync(dpy, True);
  210. }
  211. static void uninstall_grabs(void)
  212. {
  213. if (dgamouse) {
  214. dgamouse = qfalse;
  215. XF86DGADirectVideo(dpy, DefaultScreen(dpy), 0);
  216. }
  217. XChangePointerControl(dpy, qtrue, qtrue, mouse_accel_numerator,
  218. mouse_accel_denominator, mouse_threshold);
  219. XUngrabPointer(dpy, CurrentTime);
  220. XUngrabKeyboard(dpy, CurrentTime);
  221. // inviso cursor
  222. XUndefineCursor(dpy, win);
  223. // XAutoRepeatOn(dpy);
  224. // XSync(dpy, True);
  225. }
  226. static void HandleEvents(void)
  227. {
  228. int b;
  229. int key;
  230. XEvent event;
  231. qboolean dowarp = qfalse;
  232. int mwx = glConfig.vidWidth/2;
  233. int mwy = glConfig.vidHeight/2;
  234. char *p;
  235. if (!dpy)
  236. return;
  237. while (XPending(dpy)) {
  238. XNextEvent(dpy, &event);
  239. switch(event.type) {
  240. case KeyPress:
  241. p = XLateKey(&event.xkey, &key);
  242. if (key)
  243. Sys_QueEvent( 0, SE_KEY, key, qtrue, 0, NULL );
  244. while (*p)
  245. Sys_QueEvent( 0, SE_CHAR, *p++, 0, 0, NULL );
  246. break;
  247. case KeyRelease:
  248. XLateKey(&event.xkey, &key);
  249. Sys_QueEvent( 0, SE_KEY, key, qfalse, 0, NULL );
  250. break;
  251. #if 0
  252. case KeyPress:
  253. case KeyRelease:
  254. key = XLateKey(&event.xkey);
  255. Sys_QueEvent( 0, SE_KEY, key, event.type == KeyPress, 0, NULL );
  256. if (key == K_SHIFT)
  257. shift_down = (event.type == KeyPress);
  258. if (key < 128 && (event.type == KeyPress)) {
  259. if (shift_down)
  260. key = keyshift[key];
  261. Sys_QueEvent( 0, SE_CHAR, key, 0, 0, NULL );
  262. }
  263. #endif
  264. break;
  265. case MotionNotify:
  266. if (mouse_active) {
  267. if (dgamouse) {
  268. if (abs(event.xmotion.x_root) > 1)
  269. mx += event.xmotion.x_root * 2;
  270. else
  271. mx += event.xmotion.x_root;
  272. if (abs(event.xmotion.y_root) > 1)
  273. my += event.xmotion.y_root * 2;
  274. else
  275. my += event.xmotion.y_root;
  276. // ri.Printf(PRINT_ALL, "mouse (%d,%d) (root=%d,%d)\n", event.xmotion.x + win_x, event.xmotion.y + win_y, event.xmotion.x_root, event.xmotion.y_root);
  277. }
  278. else
  279. {
  280. // ri.Printf(PRINT_ALL, "mouse x=%d,y=%d\n", (int)event.xmotion.x - mwx, (int)event.xmotion.y - mwy);
  281. mx += ((int)event.xmotion.x - mwx);
  282. my += ((int)event.xmotion.y - mwy);
  283. mwx = event.xmotion.x;
  284. mwy = event.xmotion.y;
  285. if (mx || my)
  286. dowarp = qtrue;
  287. }
  288. }
  289. break;
  290. case ButtonPress:
  291. b=-1;
  292. if (event.xbutton.button == 1)
  293. b = 0;
  294. else if (event.xbutton.button == 2)
  295. b = 2;
  296. else if (event.xbutton.button == 3)
  297. b = 1;
  298. Sys_QueEvent( 0, SE_KEY, K_MOUSE1 + b, qtrue, 0, NULL );
  299. break;
  300. case ButtonRelease:
  301. b=-1;
  302. if (event.xbutton.button == 1)
  303. b = 0;
  304. else if (event.xbutton.button == 2)
  305. b = 2;
  306. else if (event.xbutton.button == 3)
  307. b = 1;
  308. Sys_QueEvent( 0, SE_KEY, K_MOUSE1 + b, qfalse, 0, NULL );
  309. break;
  310. case CreateNotify :
  311. win_x = event.xcreatewindow.x;
  312. win_y = event.xcreatewindow.y;
  313. break;
  314. case ConfigureNotify :
  315. win_x = event.xconfigure.x;
  316. win_y = event.xconfigure.y;
  317. break;
  318. }
  319. }
  320. if (dowarp) {
  321. /* move the mouse to the window center again */
  322. XWarpPointer(dpy,None,win,0,0,0,0,
  323. (glConfig.vidWidth/2),(glConfig.vidHeight/2));
  324. }
  325. }
  326. void KBD_Init(void)
  327. {
  328. }
  329. void KBD_Close(void)
  330. {
  331. }
  332. void IN_ActivateMouse( void )
  333. {
  334. if (!mouse_avail || !dpy || !win)
  335. return;
  336. if (!mouse_active) {
  337. mx = my = 0; // don't spazz
  338. install_grabs();
  339. mouse_active = qtrue;
  340. }
  341. }
  342. void IN_DeactivateMouse( void )
  343. {
  344. if (!mouse_avail || !dpy || !win)
  345. return;
  346. if (mouse_active) {
  347. uninstall_grabs();
  348. mouse_active = qfalse;
  349. }
  350. }
  351. /*****************************************************************************/
  352. static qboolean signalcaught = qfalse;;
  353. static void signal_handler(int sig)
  354. {
  355. if (signalcaught) {
  356. printf("DOUBLE SIGNAL FAULT: Received signal %d, exiting...\n", sig);
  357. _exit(1);
  358. }
  359. signalcaught = qtrue;
  360. printf("Received signal %d, exiting...\n", sig);
  361. GLimp_Shutdown();
  362. _exit(1);
  363. }
  364. static void InitSig(void)
  365. {
  366. signal(SIGHUP, signal_handler);
  367. signal(SIGQUIT, signal_handler);
  368. signal(SIGILL, signal_handler);
  369. signal(SIGTRAP, signal_handler);
  370. signal(SIGIOT, signal_handler);
  371. signal(SIGBUS, signal_handler);
  372. signal(SIGFPE, signal_handler);
  373. signal(SIGSEGV, signal_handler);
  374. signal(SIGTERM, signal_handler);
  375. }
  376. /*
  377. ** GLimp_SetGamma
  378. **
  379. ** This routine should only be called if glConfig.deviceSupportsGamma is TRUE
  380. */
  381. void GLimp_SetGamma( unsigned char red[256], unsigned char green[256], unsigned char blue[256] )
  382. {
  383. }
  384. /*
  385. ** GLimp_Shutdown
  386. **
  387. ** This routine does all OS specific shutdown procedures for the OpenGL
  388. ** subsystem. Under OpenGL this means NULLing out the current DC and
  389. ** HGLRC, deleting the rendering context, and releasing the DC acquired
  390. ** for the window. The state structure is also nulled out.
  391. **
  392. */
  393. void GLimp_Shutdown( void )
  394. {
  395. if (!ctx || !dpy)
  396. return;
  397. IN_DeactivateMouse();
  398. XAutoRepeatOn(dpy);
  399. if (dpy) {
  400. if (ctx)
  401. qglXDestroyContext(dpy, ctx);
  402. if (win)
  403. XDestroyWindow(dpy, win);
  404. if (vidmode_active)
  405. XF86VidModeSwitchToMode(dpy, scrnum, vidmodes[0]);
  406. XCloseDisplay(dpy);
  407. }
  408. vidmode_active = qfalse;
  409. dpy = NULL;
  410. win = 0;
  411. ctx = NULL;
  412. memset( &glConfig, 0, sizeof( glConfig ) );
  413. memset( &glState, 0, sizeof( glState ) );
  414. QGL_Shutdown();
  415. }
  416. /*
  417. ** GLimp_LogComment
  418. */
  419. void GLimp_LogComment( char *comment )
  420. {
  421. if ( glw_state.log_fp ) {
  422. fprintf( glw_state.log_fp, "%s", comment );
  423. }
  424. }
  425. /*
  426. ** GLW_StartDriverAndSetMode
  427. */
  428. static qboolean GLW_StartDriverAndSetMode( const char *drivername,
  429. int mode,
  430. qboolean fullscreen )
  431. {
  432. rserr_t err;
  433. // don't ever bother going into fullscreen with a voodoo card
  434. #if 1 // JDC: I reenabled this
  435. if ( strstr( drivername, "Voodoo" ) ) {
  436. ri.Cvar_Set( "r_fullscreen", "0" );
  437. r_fullscreen->modified = qfalse;
  438. fullscreen = qfalse;
  439. }
  440. #endif
  441. err = GLW_SetMode( drivername, mode, fullscreen );
  442. switch ( err )
  443. {
  444. case RSERR_INVALID_FULLSCREEN:
  445. ri.Printf( PRINT_ALL, "...WARNING: fullscreen unavailable in this mode\n" );
  446. return qfalse;
  447. case RSERR_INVALID_MODE:
  448. ri.Printf( PRINT_ALL, "...WARNING: could not set the given mode (%d)\n", mode );
  449. return qfalse;
  450. default:
  451. break;
  452. }
  453. return qtrue;
  454. }
  455. /*
  456. ** GLW_SetMode
  457. */
  458. int GLW_SetMode( const char *drivername, int mode, qboolean fullscreen )
  459. {
  460. int attrib[] = {
  461. GLX_RGBA, // 0
  462. GLX_RED_SIZE, 4, // 1, 2
  463. GLX_GREEN_SIZE, 4, // 3, 4
  464. GLX_BLUE_SIZE, 4, // 5, 6
  465. GLX_DOUBLEBUFFER, // 7
  466. GLX_DEPTH_SIZE, 1, // 8, 9
  467. GLX_STENCIL_SIZE, 1, // 10, 11
  468. None
  469. };
  470. // these match in the array
  471. #define ATTR_RED_IDX 2
  472. #define ATTR_GREEN_IDX 4
  473. #define ATTR_BLUE_IDX 6
  474. #define ATTR_DEPTH_IDX 9
  475. #define ATTR_STENCIL_IDX 11
  476. Window root;
  477. XVisualInfo *visinfo;
  478. XSetWindowAttributes attr;
  479. unsigned long mask;
  480. int colorbits, depthbits, stencilbits;
  481. int tcolorbits, tdepthbits, tstencilbits;
  482. int MajorVersion, MinorVersion;
  483. int actualWidth, actualHeight;
  484. int i;
  485. r_fakeFullscreen = ri.Cvar_Get( "r_fakeFullscreen", "0", CVAR_ARCHIVE);
  486. ri.Printf( PRINT_ALL, "Initializing OpenGL display\n");
  487. ri.Printf (PRINT_ALL, "...setting mode %d:", mode );
  488. if ( !R_GetModeInfo( &glConfig.vidWidth, &glConfig.vidHeight, &glConfig.windowAspect, mode ) )
  489. {
  490. ri.Printf( PRINT_ALL, " invalid mode\n" );
  491. return RSERR_INVALID_MODE;
  492. }
  493. ri.Printf( PRINT_ALL, " %d %d\n", glConfig.vidWidth, glConfig.vidHeight);
  494. if (!(dpy = XOpenDisplay(NULL))) {
  495. fprintf(stderr, "Error couldn't open the X display\n");
  496. return RSERR_INVALID_MODE;
  497. }
  498. scrnum = DefaultScreen(dpy);
  499. root = RootWindow(dpy, scrnum);
  500. actualWidth = glConfig.vidWidth;
  501. actualHeight = glConfig.vidHeight;
  502. // Get video mode list
  503. MajorVersion = MinorVersion = 0;
  504. if (!XF86VidModeQueryVersion(dpy, &MajorVersion, &MinorVersion)) {
  505. vidmode_ext = qfalse;
  506. } else {
  507. ri.Printf(PRINT_ALL, "Using XFree86-VidModeExtension Version %d.%d\n",
  508. MajorVersion, MinorVersion);
  509. vidmode_ext = qtrue;
  510. }
  511. if (vidmode_ext) {
  512. int best_fit, best_dist, dist, x, y;
  513. XF86VidModeGetAllModeLines(dpy, scrnum, &num_vidmodes, &vidmodes);
  514. // Are we going fullscreen? If so, let's change video mode
  515. if (fullscreen && !r_fakeFullscreen->integer) {
  516. best_dist = 9999999;
  517. best_fit = -1;
  518. for (i = 0; i < num_vidmodes; i++) {
  519. if (glConfig.vidWidth > vidmodes[i]->hdisplay ||
  520. glConfig.vidHeight > vidmodes[i]->vdisplay)
  521. continue;
  522. x = glConfig.vidWidth - vidmodes[i]->hdisplay;
  523. y = glConfig.vidHeight - vidmodes[i]->vdisplay;
  524. dist = (x * x) + (y * y);
  525. if (dist < best_dist) {
  526. best_dist = dist;
  527. best_fit = i;
  528. }
  529. }
  530. if (best_fit != -1) {
  531. actualWidth = vidmodes[best_fit]->hdisplay;
  532. actualHeight = vidmodes[best_fit]->vdisplay;
  533. // change to the mode
  534. XF86VidModeSwitchToMode(dpy, scrnum, vidmodes[best_fit]);
  535. vidmode_active = qtrue;
  536. // Move the viewport to top left
  537. XF86VidModeSetViewPort(dpy, scrnum, 0, 0);
  538. } else
  539. fullscreen = 0;
  540. }
  541. }
  542. if (!r_colorbits->value)
  543. colorbits = 24;
  544. else
  545. colorbits = r_colorbits->value;
  546. if ( !Q_stricmp( r_glDriver->string, _3DFX_DRIVER_NAME ) )
  547. colorbits = 16;
  548. if (!r_depthbits->value)
  549. depthbits = 24;
  550. else
  551. depthbits = r_depthbits->value;
  552. stencilbits = r_stencilbits->value;
  553. for (i = 0; i < 16; i++) {
  554. // 0 - default
  555. // 1 - minus colorbits
  556. // 2 - minus depthbits
  557. // 3 - minus stencil
  558. if ((i % 4) == 0 && i) {
  559. // one pass, reduce
  560. switch (i / 4) {
  561. case 2 :
  562. if (colorbits == 24)
  563. colorbits = 16;
  564. break;
  565. case 1 :
  566. if (depthbits == 24)
  567. depthbits = 16;
  568. else if (depthbits == 16)
  569. depthbits = 8;
  570. case 3 :
  571. if (stencilbits == 24)
  572. stencilbits = 16;
  573. else if (stencilbits == 16)
  574. stencilbits = 8;
  575. }
  576. }
  577. tcolorbits = colorbits;
  578. tdepthbits = depthbits;
  579. tstencilbits = stencilbits;
  580. if ((i % 4) == 3) { // reduce colorbits
  581. if (tcolorbits == 24)
  582. tcolorbits = 16;
  583. }
  584. if ((i % 4) == 2) { // reduce depthbits
  585. if (tdepthbits == 24)
  586. tdepthbits = 16;
  587. else if (tdepthbits == 16)
  588. tdepthbits = 8;
  589. }
  590. if ((i % 4) == 1) { // reduce stencilbits
  591. if (tstencilbits == 24)
  592. tstencilbits = 16;
  593. else if (tstencilbits == 16)
  594. tstencilbits = 8;
  595. else
  596. tstencilbits = 0;
  597. }
  598. if (tcolorbits == 24) {
  599. attrib[ATTR_RED_IDX] = 8;
  600. attrib[ATTR_GREEN_IDX] = 8;
  601. attrib[ATTR_BLUE_IDX] = 8;
  602. } else {
  603. // must be 16 bit
  604. attrib[ATTR_RED_IDX] = 4;
  605. attrib[ATTR_GREEN_IDX] = 4;
  606. attrib[ATTR_BLUE_IDX] = 4;
  607. }
  608. attrib[ATTR_DEPTH_IDX] = tdepthbits; // default to 24 depth
  609. attrib[ATTR_STENCIL_IDX] = tstencilbits;
  610. #if 0
  611. ri.Printf( PRINT_DEVELOPER, "Attempting %d/%d/%d Color bits, %d depth, %d stencil display...",
  612. attrib[ATTR_RED_IDX], attrib[ATTR_GREEN_IDX], attrib[ATTR_BLUE_IDX],
  613. attrib[ATTR_DEPTH_IDX], attrib[ATTR_STENCIL_IDX]);
  614. #endif
  615. visinfo = qglXChooseVisual(dpy, scrnum, attrib);
  616. if (!visinfo) {
  617. #if 0
  618. ri.Printf( PRINT_DEVELOPER, "failed\n");
  619. #endif
  620. continue;
  621. }
  622. #if 0
  623. ri.Printf( PRINT_DEVELOPER, "Successful\n");
  624. #endif
  625. ri.Printf( PRINT_ALL, "Using %d/%d/%d Color bits, %d depth, %d stencil display.\n",
  626. attrib[ATTR_RED_IDX], attrib[ATTR_GREEN_IDX], attrib[ATTR_BLUE_IDX],
  627. attrib[ATTR_DEPTH_IDX], attrib[ATTR_STENCIL_IDX]);
  628. glConfig.colorBits = tcolorbits;
  629. glConfig.depthBits = tdepthbits;
  630. glConfig.stencilBits = tstencilbits;
  631. break;
  632. }
  633. if (!visinfo) {
  634. ri.Printf( PRINT_ALL, "Couldn't get a visual\n" );
  635. return RSERR_INVALID_MODE;
  636. }
  637. /* window attributes */
  638. attr.background_pixel = BlackPixel(dpy, scrnum);
  639. attr.border_pixel = 0;
  640. attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone);
  641. attr.event_mask = X_MASK;
  642. if (vidmode_active) {
  643. mask = CWBackPixel | CWColormap | CWSaveUnder | CWBackingStore |
  644. CWEventMask | CWOverrideRedirect;
  645. attr.override_redirect = True;
  646. attr.backing_store = NotUseful;
  647. attr.save_under = False;
  648. } else
  649. mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
  650. win = XCreateWindow(dpy, root, 0, 0,
  651. actualWidth, actualHeight,
  652. 0, visinfo->depth, InputOutput,
  653. visinfo->visual, mask, &attr);
  654. XMapWindow(dpy, win);
  655. if (vidmode_active)
  656. XMoveWindow(dpy, win, 0, 0);
  657. // Check for DGA
  658. if (in_dgamouse->value) {
  659. if (!XF86DGAQueryVersion(dpy, &MajorVersion, &MinorVersion)) {
  660. // unable to query, probalby not supported
  661. ri.Printf( PRINT_ALL, "Failed to detect XF86DGA Mouse\n" );
  662. ri.Cvar_Set( "in_dgamouse", "0" );
  663. } else
  664. ri.Printf( PRINT_ALL, "XF86DGA Mouse (Version %d.%d) initialized\n",
  665. MajorVersion, MinorVersion);
  666. }
  667. XFlush(dpy);
  668. ctx = qglXCreateContext(dpy, visinfo, NULL, True);
  669. qglXMakeCurrent(dpy, win, ctx);
  670. return RSERR_OK;
  671. }
  672. /*
  673. ** GLW_InitExtensions
  674. */
  675. static void GLW_InitExtensions( void )
  676. {
  677. // Use modern texture compression extensions
  678. if ( strstr( glConfig.extensions_string, "ARB_texture_compression" ) && strstr( glConfig.extensions_string, "EXT_texture_compression_s3tc" ) )
  679. {
  680. if ( r_ext_compressed_textures->value )
  681. {
  682. glConfig.textureCompression = TC_S3TC_DXT;
  683. ri.Printf( PRINT_ALL, "...using GL_EXT_texture_compression_s3tc\n" );
  684. }
  685. else
  686. {
  687. glConfig.textureCompression = TC_NONE;
  688. ri.Printf( PRINT_ALL, "...ignoring GL_EXT_texture_compression_s3tc\n" );
  689. }
  690. }
  691. // Or check for old ones
  692. else if ( strstr( glConfig.extensions_string, "GL_S3_s3tc" ) )
  693. {
  694. if ( r_ext_compressed_textures->value )
  695. {
  696. glConfig.textureCompression = TC_S3TC;
  697. ri.Printf( PRINT_ALL, "...using GL_S3_s3tc\n" );
  698. }
  699. else
  700. {
  701. glConfig.textureCompression = TC_NONE;
  702. ri.Printf( PRINT_ALL, "...ignoring GL_S3_s3tc\n" );
  703. }
  704. }
  705. else
  706. {
  707. glConfig.textureCompression = TC_NONE;
  708. ri.Printf( PRINT_ALL, "...no texture compression found\n" );
  709. }
  710. #if 0
  711. // WGL_EXT_swap_control
  712. if ( strstr( glConfig.extensions_string, "WGL_EXT_swap_control" ) )
  713. {
  714. qwglSwapIntervalEXT = ( BOOL (WINAPI *)(int)) qwglGetProcAddress( "wglSwapIntervalEXT" );
  715. ri.Printf( PRINT_ALL, "...using WGL_EXT_swap_control\n" );
  716. }
  717. else
  718. {
  719. ri.Printf( PRINT_ALL, "...WGL_EXT_swap_control not found\n" );
  720. }
  721. #endif
  722. // GL_ARB_multitexture
  723. qglMultiTexCoord2fARB = NULL;
  724. qglActiveTextureARB = NULL;
  725. qglClientActiveTextureARB = NULL;
  726. if ( strstr( glConfig.extensions_string, "GL_ARB_multitexture" ) )
  727. {
  728. if ( r_ext_multitexture->value )
  729. {
  730. qglMultiTexCoord2fARB = ( PFNGLMULTITEXCOORD2FARBPROC ) dlsym( glw_state.OpenGLLib, "glMultiTexCoord2fARB" );
  731. qglActiveTextureARB = ( PFNGLACTIVETEXTUREARBPROC ) dlsym( glw_state.OpenGLLib, "glActiveTextureARB" );
  732. qglClientActiveTextureARB = ( PFNGLCLIENTACTIVETEXTUREARBPROC ) dlsym( glw_state.OpenGLLib, "glClientActiveTextureARB" );
  733. if ( qglActiveTextureARB )
  734. {
  735. ri.Printf( PRINT_ALL, "...using GL_ARB_multitexture\n" );
  736. }
  737. else
  738. {
  739. ri.Printf( PRINT_ALL, "...blind search for ARB_multitexture failed\n" );
  740. }
  741. }
  742. else
  743. {
  744. ri.Printf( PRINT_ALL, "...ignoring GL_ARB_multitexture\n" );
  745. }
  746. }
  747. else
  748. {
  749. ri.Printf( PRINT_ALL, "...GL_ARB_multitexture not found\n" );
  750. }
  751. // GL_EXT_texture_filter_anisotropic
  752. glConfig.textureFilterAnisotropicAvailable = qfalse;
  753. if ( strstr( glConfig.extensions_string, "EXT_texture_filter_anisotropic" ) )
  754. {
  755. glConfig.textureFilterAnisotropicAvailable = qtrue;
  756. ri.Printf( PRINT_ALL, "...GL_EXT_texture_filter_anisotropic available\n" );
  757. if ( r_ext_texture_filter_anisotropic->integer )
  758. {
  759. ri.Printf( PRINT_ALL, "...using GL_EXT_texture_filter_anisotropic\n" );
  760. }
  761. else
  762. {
  763. ri.Printf( PRINT_ALL, "...ignoring GL_EXT_texture_filter_anisotropic\n" );
  764. }
  765. ri.Cvar_Set( "r_ext_texture_filter_anisotropic_avail", "1" );
  766. }
  767. else
  768. {
  769. ri.Printf( PRINT_ALL, "...GL_EXT_texture_filter_anisotropic not found\n" );
  770. ri.Cvar_Set( "r_ext_texture_filter_anisotropic_avail", "0" );
  771. }
  772. // GL_EXT_compiled_vertex_array
  773. if ( strstr( glConfig.extensions_string, "GL_EXT_compiled_vertex_array" ) )
  774. {
  775. if ( r_ext_compiled_vertex_array->value )
  776. {
  777. ri.Printf( PRINT_ALL, "...using GL_EXT_compiled_vertex_array\n" );
  778. qglLockArraysEXT = ( void ( APIENTRY * )( int, int ) ) dlsym( glw_state.OpenGLLib, "glLockArraysEXT" );
  779. qglUnlockArraysEXT = ( void ( APIENTRY * )( void ) ) dlsym( glw_state.OpenGLLib, "glUnlockArraysEXT" );
  780. if (!qglLockArraysEXT || !qglUnlockArraysEXT) {
  781. ri.Error (ERR_FATAL, "bad getprocaddress");
  782. }
  783. }
  784. else
  785. {
  786. ri.Printf( PRINT_ALL, "...ignoring GL_EXT_compiled_vertex_array\n" );
  787. }
  788. }
  789. else
  790. {
  791. ri.Printf( PRINT_ALL, "...GL_EXT_compiled_vertex_array not found\n" );
  792. }
  793. }
  794. /*
  795. ** GLW_LoadOpenGL
  796. **
  797. ** GLimp_win.c internal function that that attempts to load and use
  798. ** a specific OpenGL DLL.
  799. */
  800. static qboolean GLW_LoadOpenGL( const char *name )
  801. {
  802. qboolean fullscreen;
  803. ri.Printf( PRINT_ALL, "...loading %s: ", name );
  804. // disable the 3Dfx splash screen and set gamma
  805. // we do this all the time, but it shouldn't hurt anything
  806. // on non-3Dfx stuff
  807. putenv("FX_GLIDE_NO_SPLASH=0");
  808. // Mesa VooDoo hacks
  809. putenv("MESA_GLX_FX=fullscreen\n");
  810. // load the QGL layer
  811. if ( QGL_Init( name ) )
  812. {
  813. fullscreen = r_fullscreen->integer;
  814. // create the window and set up the context
  815. if ( !GLW_StartDriverAndSetMode( name, r_mode->integer, fullscreen ) )
  816. {
  817. if (r_mode->integer != 3) {
  818. if ( !GLW_StartDriverAndSetMode( name, 3, fullscreen ) ) {
  819. goto fail;
  820. }
  821. } else
  822. goto fail;
  823. }
  824. return qtrue;
  825. }
  826. else
  827. {
  828. ri.Printf( PRINT_ALL, "failed\n" );
  829. }
  830. fail:
  831. QGL_Shutdown();
  832. return qfalse;
  833. }
  834. /*
  835. ** GLimp_Init
  836. **
  837. ** This routine is responsible for initializing the OS specific portions
  838. ** of OpenGL.
  839. */
  840. void GLimp_Init( void )
  841. {
  842. qboolean attemptedlibGL = qfalse;
  843. qboolean attempted3Dfx = qfalse;
  844. qboolean success = qfalse;
  845. char buf[1024];
  846. cvar_t *lastValidRenderer = ri.Cvar_Get( "r_lastValidRenderer", "(uninitialized)", CVAR_ARCHIVE );
  847. cvar_t *cv;
  848. glConfig.deviceSupportsGamma = qfalse;
  849. InitSig();
  850. //
  851. // load and initialize the specific OpenGL driver
  852. //
  853. if ( !GLW_LoadOpenGL( r_glDriver->string ) )
  854. {
  855. if ( !Q_stricmp( r_glDriver->string, OPENGL_DRIVER_NAME ) )
  856. {
  857. attemptedlibGL = qtrue;
  858. }
  859. else if ( !Q_stricmp( r_glDriver->string, _3DFX_DRIVER_NAME ) )
  860. {
  861. attempted3Dfx = qtrue;
  862. }
  863. if ( !attempted3Dfx && !success )
  864. {
  865. attempted3Dfx = qtrue;
  866. if ( GLW_LoadOpenGL( _3DFX_DRIVER_NAME ) )
  867. {
  868. ri.Cvar_Set( "r_glDriver", _3DFX_DRIVER_NAME );
  869. r_glDriver->modified = qfalse;
  870. success = qtrue;
  871. }
  872. }
  873. // try ICD before trying 3Dfx standalone driver
  874. if ( !attemptedlibGL && !success )
  875. {
  876. attemptedlibGL = qtrue;
  877. if ( GLW_LoadOpenGL( OPENGL_DRIVER_NAME ) )
  878. {
  879. ri.Cvar_Set( "r_glDriver", OPENGL_DRIVER_NAME );
  880. r_glDriver->modified = qfalse;
  881. success = qtrue;
  882. }
  883. }
  884. if (!success)
  885. ri.Error( ERR_FATAL, "GLimp_Init() - could not load OpenGL subsystem\n" );
  886. }
  887. // get our config strings
  888. Q_strncpyz( glConfig.vendor_string, qglGetString (GL_VENDOR), sizeof( glConfig.vendor_string ) );
  889. Q_strncpyz( glConfig.renderer_string, qglGetString (GL_RENDERER), sizeof( glConfig.renderer_string ) );
  890. if (*glConfig.renderer_string && glConfig.renderer_string[strlen(glConfig.renderer_string) - 1] == '\n')
  891. glConfig.renderer_string[strlen(glConfig.renderer_string) - 1] = 0;
  892. Q_strncpyz( glConfig.version_string, qglGetString (GL_VERSION), sizeof( glConfig.version_string ) );
  893. Q_strncpyz( glConfig.extensions_string, qglGetString (GL_EXTENSIONS), sizeof( glConfig.extensions_string ) );
  894. //
  895. // chipset specific configuration
  896. //
  897. strcpy( buf, glConfig.renderer_string );
  898. strlwr( buf );
  899. if ( Q_stricmp( lastValidRenderer->string, glConfig.renderer_string ) )
  900. {
  901. ri.Cvar_Set( "r_picmip", "1" );
  902. ri.Cvar_Set( "r_twopartfog", "0" );
  903. ri.Cvar_Set( "r_textureMode", "GL_LINEAR_MIPMAP_NEAREST" );
  904. //
  905. // voodoo issues
  906. //
  907. if ( strstr( buf, "voodoo" ) && !strstr( buf, "banshee" ) )
  908. {
  909. ri.Cvar_Set( "r_fakeFullscreen", "1");
  910. }
  911. //
  912. // Riva128 issues
  913. //
  914. if ( strstr( buf, "riva 128" ) )
  915. {
  916. ri.Cvar_Set( "r_twopartfog", "1" );
  917. }
  918. //
  919. // Rage Pro issues
  920. //
  921. if ( strstr( buf, "rage pro" ) )
  922. {
  923. ri.Cvar_Set( "r_mode", "2" );
  924. ri.Cvar_Set( "r_twopartfog", "1" );
  925. }
  926. //
  927. // Permedia2 issues
  928. //
  929. if ( strstr( buf, "permedia2" ) )
  930. {
  931. ri.Cvar_Set( "r_vertexLight", "1" );
  932. }
  933. //
  934. // Riva TNT issues
  935. //
  936. if ( strstr( buf, "riva tnt " ) )
  937. {
  938. if ( r_texturebits->integer == 32 ||
  939. ( ( r_texturebits->integer == 0 ) && glConfig.colorBits > 16 ) )
  940. {
  941. ri.Cvar_Set( "r_picmip", "1" );
  942. }
  943. }
  944. ri.Cvar_Set( "r_lastValidRenderer", glConfig.renderer_string );
  945. }
  946. // initialize extensions
  947. GLW_InitExtensions();
  948. InitSig();
  949. return;
  950. }
  951. /*
  952. ** GLimp_EndFrame
  953. **
  954. ** Responsible for doing a swapbuffers and possibly for other stuff
  955. ** as yet to be determined. Probably better not to make this a GLimp
  956. ** function and instead do a call to GLimp_SwapBuffers.
  957. */
  958. void GLimp_EndFrame (void)
  959. {
  960. #if 0
  961. int err;
  962. if ( !glState.finishCalled )
  963. qglFinish();
  964. // check for errors
  965. if ( !gl_ignore_errors->value ) {
  966. if ( ( err = qglGetError() ) != GL_NO_ERROR )
  967. {
  968. ri.Error( ERR_FATAL, "GLimp_EndFrame() - glGetError() failed (0x%x)!\n", err );
  969. }
  970. }
  971. #endif
  972. // don't flip if drawing to front buffer
  973. if ( stricmp( r_drawBuffer->string, "GL_FRONT" ) != 0 )
  974. {
  975. qglXSwapBuffers(dpy, win);
  976. }
  977. // check logging
  978. QGL_EnableLogging( r_logFile->value );
  979. #if 0
  980. GLimp_LogComment( "*** RE_EndFrame ***\n" );
  981. // decrement log
  982. if ( gl_log->value )
  983. {
  984. ri.Cvar_Set( "gl_log", va("%i",gl_log->value - 1 ) );
  985. }
  986. #endif
  987. }
  988. /*
  989. ===========================================================
  990. SMP acceleration
  991. ===========================================================
  992. */
  993. sem_t renderCommandsEvent;
  994. sem_t renderCompletedEvent;
  995. sem_t renderActiveEvent;
  996. void (*glimpRenderThread)( void );
  997. void GLimp_RenderThreadWrapper( void *stub ) {
  998. glimpRenderThread();
  999. #if 0
  1000. // unbind the context before we die
  1001. qglXMakeCurrent(dpy, None, NULL);
  1002. #endif
  1003. }
  1004. /*
  1005. =======================
  1006. GLimp_SpawnRenderThread
  1007. =======================
  1008. */
  1009. pthread_t renderThreadHandle;
  1010. qboolean GLimp_SpawnRenderThread( void (*function)( void ) ) {
  1011. sem_init( &renderCommandsEvent, 0, 0 );
  1012. sem_init( &renderCompletedEvent, 0, 0 );
  1013. sem_init( &renderActiveEvent, 0, 0 );
  1014. glimpRenderThread = function;
  1015. if (pthread_create( &renderThreadHandle, NULL,
  1016. GLimp_RenderThreadWrapper, NULL)) {
  1017. return qfalse;
  1018. }
  1019. return qtrue;
  1020. }
  1021. static void *smpData;
  1022. static int glXErrors;
  1023. void *GLimp_RendererSleep( void ) {
  1024. void *data;
  1025. #if 0
  1026. if ( !qglXMakeCurrent(dpy, None, NULL) ) {
  1027. glXErrors++;
  1028. }
  1029. #endif
  1030. // ResetEvent( renderActiveEvent );
  1031. // after this, the front end can exit GLimp_FrontEndSleep
  1032. sem_post ( &renderCompletedEvent );
  1033. sem_wait ( &renderCommandsEvent );
  1034. #if 0
  1035. if ( !qglXMakeCurrent(dpy, win, ctx) ) {
  1036. glXErrors++;
  1037. }
  1038. #endif
  1039. // ResetEvent( renderCompletedEvent );
  1040. // ResetEvent( renderCommandsEvent );
  1041. data = smpData;
  1042. // after this, the main thread can exit GLimp_WakeRenderer
  1043. sem_post ( &renderActiveEvent );
  1044. return data;
  1045. }
  1046. void GLimp_FrontEndSleep( void ) {
  1047. sem_wait ( &renderCompletedEvent );
  1048. #if 0
  1049. if ( !qglXMakeCurrent(dpy, win, ctx) ) {
  1050. glXErrors++;
  1051. }
  1052. #endif
  1053. }
  1054. void GLimp_WakeRenderer( void *data ) {
  1055. smpData = data;
  1056. #if 0
  1057. if ( !qglXMakeCurrent(dpy, None, NULL) ) {
  1058. glXErrors++;
  1059. }
  1060. #endif
  1061. // after this, the renderer can continue through GLimp_RendererSleep
  1062. sem_post( &renderCommandsEvent );
  1063. sem_wait( &renderActiveEvent );
  1064. }
  1065. /*===========================================================*/
  1066. /*****************************************************************************/
  1067. /* MOUSE */
  1068. /*****************************************************************************/
  1069. void IN_Init(void)
  1070. {
  1071. // mouse variables
  1072. in_mouse = Cvar_Get ("in_mouse", "1", CVAR_ARCHIVE);
  1073. in_dgamouse = Cvar_Get ("in_dgamouse", "1", CVAR_ARCHIVE);
  1074. if (in_mouse->value)
  1075. mouse_avail = qtrue;
  1076. else
  1077. mouse_avail = qfalse;
  1078. }
  1079. void IN_Shutdown(void)
  1080. {
  1081. mouse_avail = qfalse;
  1082. }
  1083. void IN_MouseMove(void)
  1084. {
  1085. if (!mouse_avail || !dpy || !win)
  1086. return;
  1087. #if 0
  1088. if (!dgamouse) {
  1089. Window root, child;
  1090. int root_x, root_y;
  1091. int win_x, win_y;
  1092. unsigned int mask_return;
  1093. int mwx = glConfig.vidWidth/2;
  1094. int mwy = glConfig.vidHeight/2;
  1095. XQueryPointer(dpy, win, &root, &child,
  1096. &root_x, &root_y, &win_x, &win_y, &mask_return);
  1097. mx = win_x - mwx;
  1098. my = win_y - mwy;
  1099. XWarpPointer(dpy,None,win,0,0,0,0, mwx, mwy);
  1100. }
  1101. #endif
  1102. if (mx || my)
  1103. Sys_QueEvent( 0, SE_MOUSE, mx, my, 0, NULL );
  1104. mx = my = 0;
  1105. }
  1106. void IN_Frame (void)
  1107. {
  1108. if ( cls.keyCatchers || cls.state != CA_ACTIVE ) {
  1109. // temporarily deactivate if not in the game and
  1110. // running on the desktop
  1111. // voodoo always counts as full screen
  1112. if (Cvar_VariableValue ("r_fullscreen") == 0
  1113. && strcmp( Cvar_VariableString("r_glDriver"), _3DFX_DRIVER_NAME ) ) {
  1114. IN_DeactivateMouse ();
  1115. return;
  1116. }
  1117. if (dpy && !autorepeaton) {
  1118. XAutoRepeatOn(dpy);
  1119. autorepeaton = qtrue;
  1120. }
  1121. } else if (dpy && autorepeaton) {
  1122. XAutoRepeatOff(dpy);
  1123. autorepeaton = qfalse;
  1124. }
  1125. IN_ActivateMouse();
  1126. // post events to the system que
  1127. IN_MouseMove();
  1128. }
  1129. void IN_Activate(void)
  1130. {
  1131. }
  1132. void Sys_SendKeyEvents (void)
  1133. {
  1134. XEvent event;
  1135. if (!dpy)
  1136. return;
  1137. HandleEvents();
  1138. // while (XCheckMaskEvent(dpy,KEY_MASK|MOUSE_MASK,&event))
  1139. // HandleEvent(&event);
  1140. }