1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id: i_video_xshm.c 1543 2020-08-22 02:36:35Z wesleyjohnson $
5 //
6 // Copyright (C) 1993-1996 by id Software, Inc.
7 // Portions Copyright (C) 1998-2012 by DooM Legacy Team.
8 //
9 // This program is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU General Public License
11 // as published by the Free Software Foundation; either version 2
12 // of the License, or (at your option) any later version.
13 //
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU General Public License for more details.
18 //
19 //
20 // $Log: i_video_xshm.c,v $
21 // Revision 1.32 2004/05/16 19:11:53 hurdler
22 // that should fix issues some people were having in 1280x1024 mode (and now support up to 1600x1200)
23 //
24 // Revision 1.31 2004/05/13 11:09:38 andyp
25 // Removed extern int errno references for Linux
26 //
27 // Revision 1.30 2002/07/01 19:59:59 metzgermeister
28 // *** empty log message ***
29 //
30 // Revision 1.29 2001/12/31 16:56:39 metzgermeister
31 // see Dec 31 log
32 //
33 // Revision 1.28 2001/08/20 20:40:42 metzgermeister
34 // *** empty log message ***
35 //
36 // Revision 1.27 2001/04/27 13:32:14 bpereira
37 // no message
38 //
39 // Revision 1.26 2001/04/14 14:17:52 metzgermeister
40 // clean up
41 //
42 // Revision 1.25 2001/03/30 17:12:52 bpereira
43 // no message
44 //
45 // Revision 1.24 2001/03/12 21:03:10 metzgermeister
46 // * new symbols for rendererlib added in SDL
47 // * console printout fixed for Linux&SDL
48 // * Crash fixed in Linux SW renderer initialization
49 //
50 // Revision 1.23 2001/02/24 13:35:22 bpereira
51 // no message
52 //
53 // Revision 1.22 2001/02/19 23:55:26 hurdler
54 // Update to match win32 source code
55 //
56 // Revision 1.21 2001/02/13 20:37:27 metzgermeister
57 // *** empty log message ***
58 //
59 // Revision 1.20 2001/01/25 22:15:45 bpereira
60 // added heretic support
61 //
62 // Revision 1.19 2000/11/04 16:23:45 bpereira
63 // no message
64 //
65 // Revision 1.18 2000/11/02 19:49:40 bpereira
66 // no message
67 //
68 // Revision 1.17 2000/10/08 13:30:02 bpereira
69 // no message
70 //
71 // Revision 1.16 2000/09/10 10:51:02 metzgermeister
72 // added vid_wait
73 //
74 // Revision 1.15 2000/08/21 21:14:31 metzgermeister
75 // Voodoo3/Banshee fix
76 //
77 // Revision 1.14 2000/08/11 19:11:07 metzgermeister
78 // *** empty log message ***
79 //
80 // Revision 1.12 2000/05/13 19:53:54 metzgermeister
81 // voodoo fullscreen & remote display
82 //
83 // Revision 1.11 2000/05/07 08:29:03 metzgermeister
84 // added windowed voodoo mode
85 //
86 // Revision 1.10 2000/04/22 20:27:35 metzgermeister
87 // support for immediate fullscreen switching
88 //
89 // Revision 1.9 2000/04/18 23:47:00 metzgermeister
90 // bugfixes
91 //
92 // Revision 1.8 2000/04/16 20:10:51 metzgermeister
93 // screensaver handling
94 //
95 // Revision 1.7 2000/04/12 19:32:50 metzgermeister
96 // new Voodoo and fullscreen support
97 //
98 // Revision 1.6 2000/04/07 23:10:15 metzgermeister
99 // fullscreen support under X in Linux
100 //
101 // Revision 1.5 2000/03/23 22:40:49 metzgermeister
102 // added support for automatic 3dfx fullscreen
103 //
104 // Revision 1.4 2000/03/07 03:30:49 hurdler
105 // fix linux compilation
106 //
107 // Revision 1.3 2000/03/06 15:19:58 hurdler
108 // Add Bell Kin's changes
109 //
110 // Revision 1.2 2000/02/27 00:42:12 hurdler
111 // fix CR+LF problem
112 //
113 // Revision 1.1.1.1 2000/02/22 20:32:33 hurdler
114 // Initial import into CVS (v1.29 pr3)
115 //
116 //
117 // DESCRIPTION:
118 // DOOM graphics stuff for X11, UNIX.
119 //
120 //-----------------------------------------------------------------------------
121
122 #include "doomincl.h"
123 // stdlib, stdio, defines
124
125 #include <stdlib.h>
126 #include <unistd.h>
127 #include <sys/ipc.h>
128 #include <sys/shm.h>
129
130 #include <X11/Xlib.h>
131 #include <X11/Xutil.h>
132 #include <X11/keysym.h>
133
134 #include <X11/extensions/XShm.h>
135 #include <X11/extensions/xf86vmode.h>
136
137 #ifdef WITH_DGA
138 #include <X11/extensions/xf86dga.h>
139 #endif
140
141 #define USE_XKB
142
143 #ifdef USE_XKB
144 // XKeycodeToKeysym is deprecated, refered to use XkbKeycodeToKeysym
145 #include <X11/XKBlib.h>
146 #endif
147
148 // Had to dig up XShm.c for this one.
149 // It is in the libXext, but not in the X headers.
150 //#if defined(LINUX)
151 int XShmGetEventBase( Display* dpy );
152 //#endif
153
154 #include <stdarg.h>
155 #include <sys/time.h>
156 #include <sys/types.h>
157 #include <dlfcn.h> // added 19990831 by Kin
158 #include <sys/socket.h>
159
160 #include <netinet/in.h>
161 #include <errno.h>
162 #include <signal.h>
163
164 #if defined(SCOOS5) || defined(SCOUW2) || defined(SCOUW7)
165 #include "strcmp.h"
166 #endif
167
168 // unknown flag DONTDEFINEBOOL, it is not in any DoomLegacy code
169 #define DONTDEFINEBOOL
170 #include "doomstat.h"
171 #include "i_system.h"
172 #include "v_video.h"
173 #include "m_argv.h"
174 #include "m_menu.h"
175 #include "d_main.h"
176 #include "s_sound.h"
177 // added for 1.27 19990220 by Kin
178 #include "g_input.h"
179 #include "st_stuff.h"
180 #include "g_game.h"
181 #include "i_video.h"
182 // vid_mode_table, etc
183 #include "screen.h"
184 // DRAW8PAL
185 #include "hardware/hw_main.h"
186 #include "hardware/hw_drv.h"
187 #include "hardware/hw_glob.h"
188 #include "console.h"
189 #include "command.h"
190 #include "d_clisrv.h"
191 // for dedicated
192 #include "r_data.h"
193 // R_Init_color8_translate, color8
194
195
196
197 // Voodoo card has video switch, produces fullscreen 3d graphics,
198 // and we cannot use window mode with it.
199 static boolean haveVoodoo = false; // have Voodoo card in hardware mode
200 static boolean showkey=false; // force to no 19990118 by Kin
201
202 static Display* X_display=NULL;
203 static Window X_mainWindow=0;
204 static Colormap X_cmap;
205 static XVisualInfo X_visualinfo;
206 static Visual* X_visual;
207 static GC X_gc;
208 static XEvent X_event;
209 static int X_screen;
210 static XSizeHints X_size;
211 static XWMHints X_wm;
212 static XClassHint X_class;
213 static Atom X_wm_delwin;
214 static XImage* image = NULL;
215
216 static Window dummy;
217 static int dont_care;
218 static unsigned int dont_care_ui;
219
220 static boolean localDisplay = true;
221
222 // MIT SHared Memory extension.
223 static boolean doShm;
224
225 static XShmSegmentInfo X_shminfo;
226 static int X_shmeventtype;
227
228 // Mouse handling.
229 static boolean Mousegrabbed = false;
230
231 // X visual mode
232 static byte x_drawmode=DRAW8PAL;
233 static int x_bitpp=8;
234 static int x_bytepp=1;
235 static uint16_t* x_colormap2 = 0;
236 static unsigned char* x_colormap3 = 0;
237 static unsigned long* x_colormap4 = 0;
238 static unsigned long x_red_mask = 0;
239 static unsigned long x_green_mask = 0;
240 static unsigned long x_blue_mask = 0;
241 static unsigned char x_red_offset = 0;
242 static unsigned char x_green_offset = 0;
243 static unsigned char x_blue_offset = 0;
244
245 // X11 video modes from which to choose from.
246
247 // maximum number of windowed modes for X11 (see windowedModes[][])
248 #define MAXWINMODES (8)
249 static int windowedModes[MAXWINMODES+1][2] = {
250 // hidden from display
251 {INITIAL_WINDOW_WIDTH, INITIAL_WINDOW_HEIGHT}, // initial mode
252 // public 1..
253 {1600, 1200},
254 {1280, 1024},
255 {1024, 768},
256 { 800, 600},
257 { 640, 480},
258 { 512, 384},
259 { 400, 300},
260 { 320, 200}
261 };
262
263 #define NUM_VOODOOMODES (3)
264 // These are modes for 3dfx voodoo graphics (loopthrough) cards
265 // 1..
266 static int voodooModes[NUM_VOODOOMODES][2] = {
267 {800, 600},
268 {640, 480},
269 {512, 384}
270 };
271
272 static boolean vidmode_ext; // Are videmode extensions available?
273 static boolean vidmode_active = false;
274 static XF86VidModeModeInfo **vidmodes;
275 static int num_fullvidmodes = 0; // num in vidmodes
276 static int lowest_vidmode = 0;
277
278 // [WDJ] Submitted by pld-linux patch lib. Handle larger number of vidmodes without crash.
279 #define MAX_NUM_VIDMODES (100)
280 #define MAX_LEN_VIDMODENAME 32
281 // [WDJ] Submitted by pld-linux patch lib. Handle larger number of vidmodes without crash.
282 // allow MAX_NUM_VIDMODES different modes
283 static char vidModeName[MAX_NUM_VIDMODES][MAX_LEN_VIDMODENAME+1];
284 static int num_vidmodes = 0; // num in vidmap, limited to MAX_NUM_VIDMODES
285 static int vidmap[MAX_NUM_VIDMODES];
286
287 // sort vidmodes into vidmap
288 // excluding those too large for our limits
vidmodes_to_vidmap(void)289 static void vidmodes_to_vidmap( void )
290 {
291 boolean finished = false; // bubble sort done
292 int i;
293
294 // initialize mapping
295 // exclude modes which are too large (to prevent X-Server problems)
296 num_vidmodes = 0;
297 for(i=0; i<num_fullvidmodes; i++)
298 {
299 if(vidmodes[i]->hdisplay <= MAXVIDWIDTH
300 && vidmodes[i]->vdisplay <= MAXVIDHEIGHT)
301 {
302 // only init vidmap when mode sizes are within our limits
303 vidmap[num_vidmodes++] = i;
304 // limit num of modes at usage of index
305 if( num_vidmodes >= MAX_NUM_VIDMODES )
306 break;
307 }
308 }
309
310 // bubble sort modes, largest first
311 do
312 {
313 finished = true;
314
315 for(i=0; i<num_vidmodes-1; i++)
316 {
317 int e1 = vidmap[i];
318 int e2 = vidmap[i+1];
319 // compare h*w of [i] with [i+1]
320 if(vidmodes[e1]->hdisplay * vidmodes[e1]->vdisplay <
321 vidmodes[e2]->hdisplay * vidmodes[e2]->vdisplay)
322 {
323 // swap entries
324 vidmap[i] = e2;
325 vidmap[i+1] = e1;
326 finished = false;
327 }
328 }
329 } while(!finished);
330 }
331
332 // Set hardware vidmodes and vidmap, from X_display, X_screen
determine_VidModes(void)333 static void determine_VidModes(void)
334 {
335 if(vidmode_ext)
336 {
337 // get fullscreen modes to vidmodes
338 XF86VidModeGetAllModeLines(X_display, X_screen, &num_fullvidmodes, &vidmodes);
339
340 vidmodes_to_vidmap();
341
342 lowest_vidmode = num_vidmodes - 1;
343 }
344 else
345 {
346 num_vidmodes = 0;
347 }
348 return;
349 }
350
351
352 // Set vidmode_ext
check_vidmode_extension(void)353 static void check_vidmode_extension(void)
354 {
355 int MajorVersion, MinorVersion;
356
357 MajorVersion = MinorVersion = 0;
358
359 // disable extensions for non-local displays
360 if(!localDisplay){
361 vidmode_ext = false;
362 return;
363 }
364
365 if (!XF86VidModeQueryVersion(X_display, &MajorVersion, &MinorVersion)) {
366 vidmode_ext = false;
367 } else {
368 CONS_Printf("Using XFree86-VidModeExtension Version %d.%d\n", MajorVersion, MinorVersion);
369 vidmode_ext = true;
370 }
371 return;
372 }
373
374
375 // Set X_screen, X_visualinfo, X_visual, x_drawmode
findVisual(void)376 static void findVisual(void)
377 {
378 // classes of interest are PseudoColor (dynamic colormap), TrueColor (static colormap)
379 X_screen = DefaultScreen(X_display); // screen number, usually 0
380 if (XMatchVisualInfo(X_display, X_screen, 8, PseudoColor, &X_visualinfo))
381 { x_drawmode = DRAW8PAL; }
382 else if
383 (XMatchVisualInfo(X_display, X_screen, 15, TrueColor, &X_visualinfo))
384 { x_drawmode = DRAW15; }
385 else if
386 (XMatchVisualInfo(X_display, X_screen, 16, TrueColor, &X_visualinfo))
387 { x_drawmode = DRAW16; }
388 else if
389 (XMatchVisualInfo(X_display, X_screen, 24, TrueColor, &X_visualinfo))
390 { x_drawmode = DRAW24; }
391 else if
392 (XMatchVisualInfo(X_display, X_screen, 32, TrueColor, &X_visualinfo))
393 { x_drawmode = DRAW32; }
394 else
395 I_Error("no supported visual found");
396 X_visual = X_visualinfo.visual;
397
398 return;
399 }
400
401 // Set color offset and masks from X_visual and x_drawmode
determineColorMask(void)402 static void determineColorMask(void)
403 {
404 x_red_mask = X_visual->red_mask;
405 x_green_mask = X_visual->green_mask;
406 x_blue_mask = X_visual->blue_mask;
407
408 if (x_drawmode==DRAW24 || x_drawmode==DRAW32) {
409 switch (x_red_mask) {
410 #ifdef BIGEND
411 case 0x000000ff: x_red_offset = 3; break;
412 case 0x0000ff00: x_red_offset = 2; break;
413 case 0x00ff0000: x_red_offset = 1; break;
414 case 0xff000000: x_red_offset = 0; break;
415 #else
416 case 0x000000ff: x_red_offset = 0; break;
417 case 0x0000ff00: x_red_offset = 1; break;
418 case 0x00ff0000: x_red_offset = 2; break;
419 case 0xff000000: x_red_offset = 3; break;
420 #endif
421 }
422 switch (x_green_mask) {
423 #ifdef BIGEND
424 case 0x000000ff: x_green_offset = 3; break;
425 case 0x0000ff00: x_green_offset = 2; break;
426 case 0x00ff0000: x_green_offset = 1; break;
427 case 0xff000000: x_green_offset = 0; break;
428 #else
429 case 0x000000ff: x_green_offset = 0; break;
430 case 0x0000ff00: x_green_offset = 1; break;
431 case 0x00ff0000: x_green_offset = 2; break;
432 case 0xff000000: x_green_offset = 3; break;
433 #endif
434 }
435 switch (x_blue_mask) {
436 #ifdef BIGEND
437 case 0x000000ff: x_blue_offset = 3; break;
438 case 0x0000ff00: x_blue_offset = 2; break;
439 case 0x00ff0000: x_blue_offset = 1; break;
440 case 0xff000000: x_blue_offset = 0; break;
441 #else
442 case 0x000000ff: x_blue_offset = 0; break;
443 case 0x0000ff00: x_blue_offset = 1; break;
444 case 0x00ff0000: x_blue_offset = 2; break;
445 case 0xff000000: x_blue_offset = 3; break;
446 #endif
447 }
448 }
449 if (x_drawmode==DRAW15 || x_drawmode==DRAW16) {
450 // for 16bpp, x_*_offset specifies the number of bits to shift
451 unsigned long mask;
452
453 mask = x_red_mask;
454 x_red_offset = 0;
455 while (!(mask&1)) {
456 x_red_offset++;
457 mask >>= 1;
458 }
459 x_red_mask = 8;
460 while (mask&1) {
461 x_red_mask--;
462 mask >>= 1;
463 }
464
465 mask = x_green_mask;
466 x_green_offset = 0;
467 while (!(mask&1)) {
468 x_green_offset++;
469 mask >>= 1;
470 }
471 x_green_mask = 8;
472 while (mask&1) {
473 x_green_mask--;
474 mask >>= 1;
475 }
476
477 mask = x_blue_mask;
478 x_blue_offset = 0;
479 while (!(mask&1)) {
480 x_blue_offset++;
481 mask >>= 1;
482 }
483 x_blue_mask = 8;
484 while (mask&1) {
485 x_blue_mask--;
486 mask >>= 1;
487 }
488 }
489 return;
490 }
491
492 // Sets x_bitpp and x_bytepp from X_visualinfo.depth
determineBPP(void)493 static void determineBPP(void)
494 {
495 int count;
496 XPixmapFormatValues* X_pixmapformats; // temp
497
498 X_pixmapformats = XListPixmapFormats(X_display,&count);
499
500 // valid depth are 1, 4, 8, 15, 16, 24, 32
501 if (X_pixmapformats) {
502 int i;
503 x_bitpp=0;
504 // search pixmapformats for the depth
505 for (i=0; i<count; i++) {
506 if (X_pixmapformats[i].depth == X_visualinfo.depth) {
507 x_bitpp = X_pixmapformats[i].bits_per_pixel;
508 break;
509 }
510 }
511 if (x_bitpp==0)
512 I_Error("Could not determine bits_per_pixel");
513 XFree(X_pixmapformats);
514 } else
515 I_Error("Could not get list of pixmap formats");
516 x_bytepp = (x_bitpp+7)/8;
517 if( verbose )
518 GenPrintf(EMSG_ver, "Video depth %i, x_bitpp %i, x_bytepp %i\n", X_visualinfo.depth, x_bitpp, x_bytepp );
519 return;
520 }
521
522
X_error_handler(Display * d,XErrorEvent * ev)523 int X_error_handler( Display * d, XErrorEvent * ev )
524 {
525 #define ERRBUF_SIZE 1024
526 char errbuf[ERRBUF_SIZE+1];
527 XGetErrorText( d, ev->error_code, errbuf, ERRBUF_SIZE );
528 I_SoftError( "%s\n", errbuf );
529 return 0;
530 }
531
532
533 // Set X_display
initDisplay(void)534 static char * initDisplay(void)
535 {
536 int pnum;
537 char *displayname, *d, displaycopy[256];
538
539 // check for command-line display name
540 if((pnum = M_CheckParm("-display")) && (pnum < myargc-1))
541 displayname = myargv[pnum+1];
542 else
543 displayname = NULL;
544
545 // open the display
546 X_display = XOpenDisplay(displayname);
547
548 if (!X_display)
549 {
550 if (displayname)
551 I_Error("Could not open display [%s]", displayname);
552 else
553 I_Error("Could not open display (DISPLAY=[%s])", getenv("DISPLAY"));
554 }
555
556 if(!displayname)
557 displayname = (char *) getenv("DISPLAY");
558
559 // check for local display
560 if(displayname) {
561 strncpy(displaycopy, displayname, 256);
562 d = displaycopy;
563 while (*d && (*d != ':')) d++;
564 if (*d) *d = 0;
565 if (!(!strcasecmp(displaycopy, "unix") || !*displaycopy))
566 localDisplay = false;
567 }
568
569 return displayname;
570 }
571
572 // Set doShm
checkForShm(void)573 static void checkForShm( void )
574 {
575 if(rendermode==render_soft) {
576 // check for the MITSHM extension
577 doShm = XShmQueryExtension(X_display);
578
579 // even if it's available, make sure it's a local connection
580 if(doShm && localDisplay) {
581 doShm = true;
582 GenPrintf(EMSG_info, "Using MITSHM extension\n");
583 }
584 else
585 doShm = false;
586 } else //if(rendermode==render_soft)
587 doShm = false;
588
589 return;
590 }
591
592 // Create X_cmap and x_colormap2/3/4, from x_drawnmode, x_bytepp
createColorMap()593 static void createColorMap()
594 {
595 if (x_drawmode == DRAW8PAL)
596 {
597 X_cmap = XCreateColormap(X_display, RootWindow(X_display, X_screen),
598 X_visual, AllocAll);
599 }
600 else if (x_bytepp==2)
601 {
602 #if defined( ENABLE_DRAW15 ) || defined( ENABLE_DRAW16 )
603 // [WDJ] Cannot work unless table is init too
604 vid.drawmode = (x_bitpp==15)? DRAW15 : DRAW16;
605 vid.bitpp = x_bitpp;
606 R_Init_color8_translate ( 0 );
607 vid.bitpp = 8; // all draw is 8 bpp
608 x_colormap2 = &color8.to16[0]; // cheat...19990119 by Kin
609 #else
610 x_colormap2 = malloc(2*256);
611 #endif
612 }
613 else if (x_bytepp==3)
614 x_colormap3 = malloc(3*256);
615 else if (x_bytepp==4)
616 x_colormap4 = malloc(4*256);
617 return;
618 }
619
620 #ifdef ALT_KEYMAPPING
621 int con_keymap = 0;
622
623 static int alt_keyboard_MapTable[256] =
624 {0, 0, 0, 0, 0, 0, 0, 0, 0,
625 XK_Escape, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', XK_BackSpace,
626 XK_Tab, 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', XK_Return,
627 XK_Control_L, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', 39, 96,
628 XK_Shift_L, 92, 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', XK_Shift_R,
629 XK_KP_Multiply,
630 XK_Meta_L, 32,
631 XK_Caps_Lock,
632 XK_F1, XK_F2, XK_F3, XK_F4, XK_F5, XK_F6, XK_F7, XK_F8, XK_F9, XK_F10,
633 XK_Num_Lock, XK_Scroll_Lock, XK_KP_Home, XK_KP_Up, XK_KP_Prior, XK_KP_Subtract, XK_KP_Left, XK_KP_Begin, XK_KP_Right, XK_KP_Add,
634 XK_KP_End, XK_KP_Down, XK_KP_Page_Down, XK_KP_Insert, XK_KP_Delete, 0, 0, 0,
635 XK_F11, XK_F12, XK_Home, XK_Up, XK_Prior,
636 XK_Left, 0, XK_Right, XK_End, XK_Down, XK_Next, XK_Insert, XK_Delete,
637 XK_KP_Enter, XK_Multi_key, XK_Pause, XK_Print,
638 XK_KP_Divide, XK_Alt_R, 0, XK_Super_L, XK_Super_R, XK_Hyper_R,
639 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
640 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
641 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
642 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
643 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
644 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
645 #endif
646
647 //
648 // Translates the key currently in X_event
649 //
xlatekey(KeyCode keycode,boolean keydown)650 static int xlatekey( KeyCode keycode, boolean keydown )
651 {
652 KeySym keysym;
653 int rc;
654
655 #ifdef ALT_KEYMAPPING
656 if( con_keymap ) {
657 rc = alt_keyboard_MapTable[keycode];
658 }
659 else {
660 // X keymapping
661 #ifdef USE_XKB
662 keysym = XkbKeycodeToKeysym(X_display, keycode, 0, 0);
663 #else
664 keysym = XKeycodeToKeysym(X_display, keycode, 0);
665 #endif
666 rc = keysym;
667 }
668 #else
669 // X keymapping
670 #ifdef USE_XKB
671 keysym = XkbKeycodeToKeysym(X_display, keycode, 0, 0);
672 #else
673 keysym = XKeycodeToKeysym(X_display, keycode, 0);
674 #endif
675 rc = keysym;
676 #endif
677
678 switch(rc)
679 {
680 case XK_Left : rc = KEY_LEFTARROW; break;
681 case XK_Right : rc = KEY_RIGHTARROW; break;
682 case XK_Down : rc = KEY_DOWNARROW; break;
683 case XK_Up : rc = KEY_UPARROW; break;
684
685 case XK_Escape: rc = KEY_ESCAPE; break;
686 case XK_Return: rc = KEY_ENTER; break;
687 case XK_Tab: rc = KEY_TAB; break;
688 case XK_F1: rc = KEY_F1; break;
689 case XK_F2: rc = KEY_F2; break;
690 case XK_F3: rc = KEY_F3; break;
691 case XK_F4: rc = KEY_F4; break;
692 case XK_F5: rc = KEY_F5; break;
693 case XK_F6: rc = KEY_F6; break;
694 case XK_F7: rc = KEY_F7; break;
695 case XK_F8: rc = KEY_F8; break;
696 case XK_F9: rc = KEY_F9; break;
697 case XK_F10: rc = KEY_F10; break;
698 case XK_F11: rc = KEY_F11; break;
699 case XK_F12: rc = KEY_F12; break;
700
701 case XK_Pause: rc = KEY_PAUSE; break;
702
703 // case XK_equal: rc = '='; break;
704 // case XK_minus: rc = '-'; break;
705
706 // [WDJ] Most important that they have unique values because they
707 // are assigned game actions by the user (by keypress sample).
708 case XK_Caps_Lock: rc = KEY_CAPSLOCK; break;
709 case XK_Num_Lock: rc = KEY_NUMLOCK; break;
710 case XK_Scroll_Lock: rc = KEY_SCROLLLOCK; break;
711 case XK_Multi_key: rc = KEY_MENU /* KEY_unused1 */; break;
712 case XK_Mode_switch: rc = KEY_MODE; break;
713
714 case XK_Shift_L: rc = KEY_LSHIFT; shiftdown = keydown; break;
715 case XK_Shift_R: rc = KEY_RSHIFT; shiftdown = keydown; break;
716 case XK_Control_L: rc = KEY_LCTRL; break;
717 case XK_Control_R: rc = KEY_RCTRL; break;
718 case XK_Alt_L: rc = KEY_LALT; altdown = keydown; break;
719 case XK_Alt_R: rc = KEY_RALT; altdown = keydown; break;
720 case XK_Meta_R: rc = KEY_RWIN; break;
721 case XK_Meta_L: rc = KEY_LWIN;
722
723 // I forgot them..... 19990128 by Kin
724 case XK_Page_Up: rc = KEY_PGUP; break;
725 case XK_Page_Down: rc = KEY_PGDN; break;
726 case XK_End: rc = KEY_END; break;
727 case XK_Home: rc = KEY_HOME; break;
728 case XK_Insert: rc = KEY_INS; break;
729 case XK_Delete: rc = KEY_DELETE; break;
730 // hey, it's not a sparc 19990128 by Kin
731 case XK_BackSpace: rc = KEY_BACKSPACE; break;
732
733 // metzgermeister: keypad layout as in g_input.c
734 case XK_KP_0 :
735 case XK_KP_Insert : rc = KEY_KEYPAD0; break;
736 case XK_KP_1 :
737 case XK_KP_End : rc = KEY_KEYPAD1; break;
738 case XK_KP_2 :
739 case XK_KP_Down : rc = KEY_KEYPAD2; break;
740 case XK_KP_3 :
741 case XK_KP_Page_Down : rc = KEY_KEYPAD3; break;
742 case XK_KP_4 :
743 case XK_KP_Left : rc = KEY_KEYPAD4; break;
744 case XK_KP_5 :
745 case XK_KP_Begin : rc = KEY_KEYPAD5; break;
746 case XK_KP_6 :
747 case XK_KP_Right : rc = KEY_KEYPAD6; break;
748 case XK_KP_7 :
749 case XK_KP_Home : rc = KEY_KEYPAD7; break;
750 case XK_KP_8 :
751 case XK_KP_Up : rc = KEY_KEYPAD8; break;
752 case XK_KP_9 :
753 case XK_KP_Page_Up : rc = KEY_KEYPAD9; break;
754 case XK_KP_Decimal :
755 case XK_KP_Delete : rc = KEY_KPADPERIOD; break;
756 case XK_KP_Divide : rc = KEY_KPADSLASH; break;
757 case XK_KP_Multiply : rc = KEY_KPADMULT; break;
758 case XK_KP_Subtract : rc = KEY_MINUSPAD; break;
759 case XK_KP_Add : rc = KEY_PLUSPAD; break;
760 case XK_KP_Enter : rc = KEY_ENTER; break;
761 case XK_KP_Equal : rc = KEY_KPADEQUALS; break;
762
763 default:
764 #if XK_space != ' '
765 if (rc >= XK_space && rc <= XK_asciitilde)
766 rc = rc - XK_space + ' ';
767 #endif
768 // GenPrintf(EMSG_debug, "Key: %X -> %X -> %X\n", keycode, (unsigned int)keysym, (unsigned int)rc);
769 break;
770 }
771
772 if (showkey)
773 fprintf(stdout,"Key: %d\n", rc);
774
775 return rc;
776 }
777
778 static char shift27[] =
779 { 0x22, // QUOTE
780 0,0,0,
781 '+', '<', '_', '>', '?', // '=', comma, '-', '.', '/'
782 ')', '!', '@', '#', '$', '%', '^', '&', '*', '(', // '0' .. '9'
783 0, ':', // ':', ';'
784 };
785
to_ASCII(int kcch,boolean shiftdown)786 int to_ASCII( int kcch, boolean shiftdown )
787 {
788 // SDL does this by -> Unicode -> ASCII
789 if( shiftdown )
790 {
791 if( kcch >= 'a' && kcch <= 'z' )
792 kcch = kcch - 'a' + 'A'; // to uppercase
793 else if( kcch >= 0x27 && kcch <= 0x3F )
794 kcch = shift27[ kcch - 0x27 ];
795 }
796 return (kcch <= 0x7F) ? kcch : 0; // ASCII key
797 }
798
799
800 //
801 // I_StartFrame
802 //
I_StartFrame(void)803 void I_StartFrame(void)
804 {
805 /* frame synchronous IO operations not needed for X11 */
806 }
807
808
809 static int lastmousex = 0;
810 static int lastmousey = 0;
811 #ifdef POLL_POINTER
812 static int newmousex;
813 static int newmousey;
814 // last button state from dos code... 19990110 by Kin
815 static int lastbuttons = 0;
816 #endif
817 boolean shmFinished;
818
819 #ifdef LJOYSTICK
820 extern void I_GetJoyEvent();
821 #endif
822 #ifdef LMOUSE2
823 extern void I_GetMouse2Event();
824 #endif
I_GetEvent(void)825 void I_GetEvent(void)
826 {
827
828 event_t event;
829 #ifdef LJOYSTICK
830 I_GetJoyEvent();
831 #endif
832 #ifdef LMOUSE2
833 I_GetMouse2Event();
834 #endif
835 // put event-grabbing stuff in here
836 XNextEvent(X_display, &X_event);
837 switch (X_event.type)
838 {
839 case KeyPress:
840 event.type = ev_keydown;
841 event.data1 = xlatekey(X_event.xkey.keycode, 1);
842 event.data2 = to_ASCII(event.data1, shiftdown);
843 D_PostEvent(&event);
844 break;
845
846 case KeyRelease:
847 event.type = ev_keyup;
848 event.data1 = xlatekey(X_event.xkey.keycode, 0);
849 event.data2 = to_ASCII(event.data1, shiftdown);
850 D_PostEvent(&event);
851 break;
852
853 #ifndef POLL_POINTER
854 case ButtonPress:
855 if (cv_usemouse[0].value) {
856 /*
857 int buttons,i,j=1,k;
858 event.type = ev_keydown;
859 buttons =
860 (X_event.xbutton.state & Button1Mask ? 1 : 0)
861 | (X_event.xbutton.state & Button2Mask ? 2 : 0)
862 | (X_event.xbutton.state & Button3Mask ? 4 : 0)
863 | (X_event.xbutton.button == Button1 ? 1 : 0)
864 | (X_event.xbutton.button == Button2 ? 2 : 0)
865 | (X_event.xbutton.button == Button3 ? 4 : 0);
866 k=(buttons ^ lastbuttons); // only changed bit to 1
867 lastbuttons = buttons;
868 for(i=0;i<MOUSEBUTTONS;i++,j<<=1)
869 if(k & j) {
870 event.data1=KEY_MOUSE1+i;
871 D_PostEvent(&event);
872 break; // right? 19990110 by Kin
873 }
874 */
875 int button = X_event.xbutton.button;
876 if(button && button-1 < MOUSEBUTTONS)
877 {
878 event.type = ev_keydown;
879 if(button==4)
880 {
881 event.data1 = KEY_MOUSEWHEELUP;
882 }
883 else if(button==5)
884 {
885 event.data1 = KEY_MOUSEWHEELDOWN;
886 }
887 else
888 {
889 event.data1=KEY_MOUSE1+button-1;
890 }
891 D_PostEvent(&event);
892 }
893 }
894 break;
895
896 case ButtonRelease:
897 if (cv_usemouse[0].value)
898 {
899 /*
900 int buttons,i,j=1,k;
901 event.type = ev_keyup;
902 buttons =
903 (X_event.xbutton.state & Button1Mask ? 1 : 0)
904 | (X_event.xbutton.state & Button2Mask ? 2 : 0)
905 | (X_event.xbutton.state & Button3Mask ? 4 : 0);
906 // suggest parentheses around arithmetic in operand of |
907 buttons =
908 buttons
909 ^ (X_event.xbutton.button == Button1 ? 1 : 0)
910 ^ (X_event.xbutton.button == Button2 ? 2 : 0)
911 ^ (X_event.xbutton.button == Button3 ? 4 : 0);
912 k=(buttons ^ lastbuttons); // only changed bit to 1
913 lastbuttons = buttons;
914 for(i=0;i<MOUSEBUTTONS;i++,j<<=1)
915 if(k & j)
916 {
917 event.data1=KEY_MOUSE1+i;
918 D_PostEvent(&event);
919 break; // right? 19990110 by Kin
920 }
921 */
922 int button = X_event.xbutton.button;
923 if(button && button-1 < MOUSEBUTTONS)
924 {
925 event.type = ev_keyup;
926 if(button==4||button==5)
927 {
928 //ignore
929 }
930 else
931 {
932 event.data1=KEY_MOUSE1+button-1;
933 D_PostEvent(&event);
934 }
935 }
936 }
937 break;
938
939 case MotionNotify:
940 if (cv_usemouse[0].value)
941 {
942 #ifdef WITH_DGA
943 event.type = ev_mouse;
944 event.data1 = 0;
945 event.data2 = X_event.xmotion.x_root << 2;
946 event.data3 = -X_event.xmotion.y_root << 2;
947 D_PostEvent(&event);
948 #else
949 // If the event is from warping the pointer back to middle
950 // of the screen then ignore it.
951 if ((X_event.xmotion.x == (vid.width>>1)) &&
952 (X_event.xmotion.y == (vid.height>>1))) {
953 lastmousex = X_event.xmotion.x;
954 lastmousey = X_event.xmotion.y;
955 break;
956 } else {
957 event.data2 = (X_event.xmotion.x - lastmousex) << 2;
958 lastmousex = X_event.xmotion.x;
959 event.data3 = (lastmousey - X_event.xmotion.y) << 2;
960 lastmousey = X_event.xmotion.y;
961 }
962 event.type = ev_mouse;
963 event.data1 =
964 (X_event.xmotion.state & Button1Mask ? 1 : 0)
965 | (X_event.xmotion.state & Button2Mask ? 2 : 0)
966 | (X_event.xmotion.state & Button3Mask ? 4 : 0);
967 D_PostEvent(&event);
968 // Warp the pointer back to the middle of the window
969 // or we cannot move any further if it's at a border.
970 if ((X_event.xmotion.x < 1) || (X_event.xmotion.y < 1)
971 || (X_event.xmotion.x > vid.width-2)
972 || (X_event.xmotion.y > vid.height-2))
973 {
974 XWarpPointer(X_display,
975 None,
976 X_mainWindow,
977 0, 0,
978 0, 0,
979 (vid.width>>1), (vid.height>>1) );
980 }
981 #endif // #WITH_DGA
982 }
983 break;
984 #endif
985
986 case UnmapNotify:
987 if (!demoplayback) {
988 paused = true;
989 S_PauseSound();
990 }
991 break;
992
993 case MapNotify:
994 if (!demoplayback) {
995 paused = false;
996 S_ResumeSound();
997 }
998 break;
999
1000 case ClientMessage:
1001 if (X_event.xclient.data.l[0] == X_wm_delwin) {
1002 M_QuitResponse('y');
1003 }
1004 break;
1005
1006 case Expose:
1007 case ConfigureNotify:
1008 break;
1009
1010 default:
1011 if (doShm && X_event.type == X_shmeventtype)
1012 shmFinished = true;
1013 break;
1014
1015 }
1016
1017 }
1018
createnullcursor(Display * display,Window root)1019 static Cursor createnullcursor(Display* display, Window root)
1020 {
1021 Pixmap cursormask;
1022 XGCValues xgc;
1023 GC gc;
1024 XColor dummycolour;
1025 Cursor cursor;
1026
1027 cursormask = XCreatePixmap(display, root, 1, 1, 1/*depth*/);
1028 xgc.function = GXclear;
1029 gc = XCreateGC(display, cursormask, GCFunction, &xgc);
1030 XFillRectangle(display, cursormask, gc, 0, 0, 1, 1);
1031 dummycolour.pixel = 0;
1032 dummycolour.red = 0;
1033 dummycolour.flags = 04;
1034 cursor = XCreatePixmapCursor(display, cursormask, cursormask,
1035 &dummycolour,&dummycolour, 0,0);
1036 XFreePixmap(display,cursormask);
1037 XFreeGC(display,gc);
1038 return cursor;
1039 }
1040
disableScreensaver()1041 static void disableScreensaver()
1042 {
1043 int timeout, interval, prefer_blanking, allow_exposures;
1044
1045 XGetScreenSaver(X_display, &timeout, &interval, &prefer_blanking, &allow_exposures);
1046 XSetScreenSaver(X_display, 0, interval, prefer_blanking, allow_exposures);
1047 XGetScreenSaver(X_display, &timeout, &interval, &prefer_blanking, &allow_exposures);
1048
1049 }
1050
enableScreensaver()1051 static void enableScreensaver()
1052 {
1053 int timeout, interval, prefer_blanking, allow_exposures;
1054
1055 XGetScreenSaver(X_display, &timeout, &interval, &prefer_blanking, &allow_exposures);
1056 XSetScreenSaver(X_display, -1, interval, prefer_blanking, allow_exposures);
1057 XGetScreenSaver(X_display, &timeout, &interval, &prefer_blanking, &allow_exposures);
1058
1059 }
1060
I_GrabMouse(void)1061 static void I_GrabMouse(void)
1062 {
1063 if(!X_display || cv_usemouse[0].value == 0 || M_CheckParm("-nomouse"))
1064 return;
1065
1066 if(!Mousegrabbed) {
1067 #ifdef WITH_DGA
1068 CONS_Printf("enable DGA mouse\n");
1069 XF86DGADirectVideo(X_display, X_screen, XF86DGADirectMouse);
1070 #endif
1071 XGrabPointer(X_display, X_mainWindow, True,
1072 #ifndef POLL_POINTER
1073 ButtonPressMask|ButtonReleaseMask|PointerMotionMask,
1074 #else
1075 0,
1076 #endif
1077 GrabModeAsync, GrabModeAsync,
1078 X_mainWindow, None, CurrentTime);
1079 XGrabKeyboard(X_display, X_mainWindow, True,
1080 GrabModeAsync, GrabModeAsync,
1081 CurrentTime);
1082 #ifdef POLL_POINTER
1083 XQueryPointer(X_display, X_mainWindow, &dummy, &dummy,
1084 &dont_care, &dont_care,
1085 &lastmousex, &lastmousey,
1086 &dont_care_ui);
1087 #endif
1088 disableScreensaver();
1089 }
1090
1091 Mousegrabbed = true;
1092 return;
1093 }
1094
I_UngrabMouse(void)1095 void I_UngrabMouse(void)
1096 {
1097 if(!X_display)
1098 return;
1099
1100 if(Mousegrabbed) {
1101 #ifdef WITH_DGA
1102 CONS_Printf("disable DGA mouse\n");
1103 XF86DGADirectVideo(X_display, X_screen, 0);
1104 #endif
1105 XUngrabKeyboard(X_display, CurrentTime);
1106 XUngrabPointer(X_display, CurrentTime);
1107 enableScreensaver();
1108 XSync(X_display, False);
1109 }
1110
1111 Mousegrabbed = false;
1112 return;
1113 }
1114
1115
1116 // Called on video mode change, usemouse change, mousemotion change,
1117 // and game paused.
1118 // play_mode : enable mouse containment during play
I_StartupMouse(boolean play_mode)1119 void I_StartupMouse( boolean play_mode )
1120 {
1121 if( ( vidmode_active && play_mode )
1122 || (haveVoodoo && !M_CheckParm("-winvoodoo"))) {
1123 I_GrabMouse();
1124 }
1125 else
1126 {
1127 if( cv_usemouse[0].value && play_mode ) {
1128 I_GrabMouse();
1129 }
1130 else {
1131 I_UngrabMouse();
1132 }
1133 }
1134 return;
1135 }
1136
1137 //
1138 // I_OsPolling
1139 //
I_OsPolling(void)1140 void I_OsPolling(void)
1141 {
1142 #ifdef POLL_POINTER
1143 unsigned int mask;
1144 #endif
1145
1146 if (!X_display)
1147 return;
1148
1149 if (cv_usemouse[0].value) {
1150 #ifdef POLL_POINTER
1151 XQueryPointer(X_display, X_mainWindow, &dummy, &dummy,
1152 &dont_care, &dont_care,
1153 &newmousex, &newmousey,
1154 &mask);
1155 { // process mouse 19990130 by Kin
1156 int buttons,i,j=1,k;
1157 buttons =
1158 (mask & Button1Mask ? 1 : 0)
1159 | (mask & Button2Mask ? 2 : 0)
1160 | (mask & Button3Mask ? 4 : 0)
1161 //doesn't work, why?
1162 | (mask & Button4Mask ? 8 : 0)
1163 | (mask & Button5Mask ? 16 : 0);
1164 k=(buttons ^ lastbuttons); // only changed bit to 1
1165 for(i=0;i<MOUSEBUTTONS;i++,j<<=1)
1166 if(k & j){
1167 if(buttons & j) event.type = ev_keydown;
1168 else event.type = ev_keyup;
1169 if(i==4) event.data1=KEY_MOUSEWHEELUP;
1170 else if(i==5) event.data1=KEY_MOUSEWHEELDOWN;
1171 else event.data1=KEY_MOUSE1+i;
1172 D_PostEvent(&event);
1173 // don't break!!! 19990130 by Kin
1174 }
1175 lastbuttons = buttons;
1176 }
1177
1178 event.type = ev_mouse;
1179 // event.data1 = ((mask & Button1Mask) ? 1 : 0) |
1180 // ((mask & Button2Mask) ? 2 : 0) |
1181 // ((mask & Button3Mask) ? 4 : 0);
1182 event.data2 = (newmousex - lastmousex) << 2;
1183 event.data3 = -((newmousey - lastmousey) << 2);
1184 D_PostEvent(&event);
1185 if ((newmousex < 1) || (newmousey < 1)
1186 || (newmousex > vid.width-2)
1187 || (newmousey > vid.height-2)) {
1188
1189 XWarpPointer(X_display,
1190 None,
1191 X_mainWindow,
1192 0, 0,
1193 0, 0,
1194 vid.width/2, vid.height/2);
1195 lastmousex = vid.width/2;
1196 lastmousey = vid.height/2;
1197 } else {
1198 lastmousex = newmousex;
1199 lastmousey = newmousey;
1200 }
1201 #endif
1202 }
1203
1204 while (XPending(X_display))
1205 I_GetEvent();
1206
1207 //reset wheel like in win32, I don't understand it but works
1208 gamekeydown[KEY_MOUSEWHEELUP] = 0;
1209 gamekeydown[KEY_MOUSEWHEELDOWN] = 0;
1210 }
1211
1212
1213 //
1214 // I_UpdateNoBlit
1215 //
I_UpdateNoBlit(void)1216 void I_UpdateNoBlit(void)
1217 {
1218 /* empty */
1219 }
1220
1221 //
1222 // I_FinishUpdate
1223 //
I_FinishUpdate(void)1224 void I_FinishUpdate(void)
1225 {
1226 if(rendermode==render_soft) {
1227
1228 // cv_vidwait.value not used, X11 handles its own vsync, no controls
1229
1230 if( x_bytepp == vid.bytepp ) {
1231 // no translation
1232 // draw is same bpp as video
1233 // bpp = 8, bytepp = 1, multiply = 1 19990125 by Kin
1234 if( vid.direct_rowbytes == vid.widthbytes )
1235 {
1236 // if direct draw, then no copy needed
1237 if( vid.display != (byte*)image->data ) {
1238 memcpy(image->data, vid.display, vid.direct_size);
1239 }
1240 }
1241 else
1242 VID_BlitLinearScreen ( vid.display, (byte*)image->data, vid.widthbytes,
1243 vid.height, vid.ybytes, vid.direct_rowbytes );
1244 }
1245 // colormap transformation dependent upon X server color depth
1246 else if (x_bytepp == 2) { // 15 bpp, 16 bpp
1247 int x,y;
1248 int xstart = vid.width-1;
1249 unsigned char* ilineptr;
1250 uint16_t* olineptr;
1251 y = vid.height;
1252 while (y--) {
1253 olineptr = (uint16_t *) &(image->data[y*vid.width*x_bytepp]);
1254 ilineptr = (unsigned char*) (vid.display+(y*vid.width));
1255 x = xstart;
1256 do {
1257 olineptr[x] = x_colormap2[ilineptr[x]];
1258 } while (x--);
1259 }
1260 }
1261 else if (x_bytepp == 3) { // 24 bpp
1262 int x,y;
1263 int xstart = vid.width-1;
1264 unsigned char* ilineptr;
1265 unsigned char* olineptr;
1266 y = vid.height;
1267 while (y--) {
1268 #ifdef TILTVIEW
1269 olineptr = (unsigned char *) &image->data[y*vid.width*3];
1270 #else
1271 olineptr = (unsigned char *) &image->data[y*vid.direct_rowbytes];
1272 #endif
1273 ilineptr = (unsigned char*) (vid.display+(y*vid.width));
1274 x = xstart;
1275 do {
1276 memcpy(olineptr+3*x,x_colormap3+3*ilineptr[x],3);
1277 } while (x--);
1278 }
1279 }
1280 else if (x_bytepp == 4) { // 32 bpp
1281 int x,y;
1282 int xstart = vid.width-1;
1283 unsigned char* ilineptr;
1284 uint32_t * olineptr;
1285 y = vid.height;
1286 while (y--) {
1287 #ifdef TILTVIEW
1288 olineptr = (unsigned char *) &image->data[y*vid.width<<2]; // *4
1289 #else
1290 olineptr = (unsigned int *) &(image->data[y*vid.direct_rowbytes]);
1291 #endif
1292 ilineptr = (unsigned char*) (vid.display+(y*vid.width));
1293 x = xstart;
1294 do {
1295 olineptr[x] = x_colormap4[ilineptr[x]];
1296 } while (x--);
1297 }
1298 }
1299
1300 if (doShm)
1301 {
1302
1303 if (!XShmPutImage(X_display,
1304 X_mainWindow,
1305 X_gc,
1306 image,
1307 0, 0,
1308 0, 0,
1309 vid.width, vid.height,
1310 True ))
1311 I_Error("XShmPutImage() failed\n");
1312
1313 // wait for it to finish and processes all input events
1314 shmFinished = false;
1315 do
1316 {
1317 if (XPending(X_display))
1318 I_GetEvent();
1319 else
1320 usleep( 20 );
1321 } while (!shmFinished);
1322
1323 }
1324 else
1325 {
1326
1327 // draw the image
1328 XPutImage( X_display,
1329 X_mainWindow,
1330 X_gc,
1331 image,
1332 0, 0,
1333 0, 0,
1334 vid.width, vid.height );
1335
1336 }
1337 } else {
1338 HWD.pfnFinishUpdate(cv_vidwait.value);
1339 }
1340 }
1341
1342
1343 //
1344 // I_ReadScreen
1345 //
I_ReadScreen(byte * scr)1346 void I_ReadScreen(byte* scr)
1347 {
1348 memcpy (scr, vid.display, vid.screen_size);
1349 }
1350
1351
1352 //
1353 // Palette stuff.
1354 //
1355 static XColor colors[256];
1356
UploadNewPalette(Colormap cmap,RGBA_t * palette)1357 static void UploadNewPalette(Colormap cmap, RGBA_t *palette)
1358 {
1359
1360 register int i;
1361 register int c;
1362 static boolean firstcall = true;
1363
1364 #ifdef __cplusplus
1365 if (X_visualinfo.c_class == PseudoColor && X_visualinfo.depth == 8)
1366 #else
1367 if (X_visualinfo.class == PseudoColor && X_visualinfo.depth == 8)
1368 #endif
1369 {
1370 // initialize the colormap
1371 if (firstcall)
1372 {
1373 firstcall = false;
1374 for (i=0 ; i<256 ; i++)
1375 {
1376 colors[i].pixel = i;
1377 colors[i].flags = DoRed|DoGreen|DoBlue;
1378 }
1379 }
1380
1381 // set the X colormap entries
1382 for (i=0 ; i<256 ; i++,palette++)
1383 {
1384 c = palette->s.red;
1385 colors[i].red = (c<<8) + c;
1386 c = palette->s.green;
1387 colors[i].green = (c<<8) + c;
1388 c = palette->s.blue;
1389 colors[i].blue = (c<<8) + c;
1390 }
1391
1392 // store the colors to the current colormap
1393 XStoreColors(X_display, cmap, colors, 256);
1394
1395 }
1396 }
1397
EmulateNewPalette(RGBA_t * palette)1398 static void EmulateNewPalette(RGBA_t *palette)
1399 {
1400 register int i;
1401
1402 for (i=0 ; i<256 ; i++,palette++)
1403 {
1404 switch(x_bytepp) {
1405 case 2: x_colormap2[i] =
1406 ((palette->s.red>>x_red_mask)<<x_red_offset) |
1407 ((palette->s.green>>x_green_mask)<<x_green_offset) |
1408 ((palette->s.blue>>x_blue_mask)<<x_blue_offset);
1409 break;
1410 case 3: x_colormap3[3*i+x_red_offset] = palette->s.red;
1411 x_colormap3[3*i+x_green_offset] = palette->s.green;
1412 x_colormap3[3*i+x_blue_offset] = palette->s.blue;
1413 break;
1414 case 4: x_colormap4[i] = 0;
1415 ((unsigned char*)(x_colormap4+i))[x_red_offset] =
1416 palette->s.red;
1417 ((unsigned char*)(x_colormap4+i))[x_green_offset] =
1418 palette->s.green;
1419 ((unsigned char*)(x_colormap4+i))[x_blue_offset] =
1420 palette->s.blue;
1421 break;
1422 }
1423 }
1424 }
1425
1426 //
1427 // I_SetPalette
1428 //
I_SetPalette(RGBA_t * palette)1429 void I_SetPalette(RGBA_t* palette)
1430 {
1431 if( rendermode == render_soft )
1432 {
1433 if (x_drawmode == DRAW8PAL)
1434 UploadNewPalette(X_cmap, palette);
1435 else
1436 EmulateNewPalette(palette);
1437 }
1438 }
1439
1440
1441 //
1442 // This function is probably redundant,
1443 // if XShmDetach works properly.
1444 // ddt never detached the XShm memory,
1445 // thus there might have been stale
1446 // handles accumulating.
1447 //
grabsharedmemory(int size)1448 static void grabsharedmemory(int size)
1449 {
1450 int key = ('d'<<24) | ('o'<<16) | ('o'<<8) | 'm';
1451 struct shmid_ds shminfo;
1452 int minsize = 320*200;
1453 int id;
1454 int rc;
1455 int pollution=5;
1456
1457 // try to use what was here before
1458 do
1459 {
1460 id = shmget((key_t) key, minsize, 0777); // just get the id
1461 if (id != -1)
1462 {
1463 rc=shmctl(id, IPC_STAT, &shminfo); // get stats on it
1464 if (!rc)
1465 {
1466 if (shminfo.shm_nattch)
1467 {
1468 GenPrintf(EMSG_info, "User %d appears to be running "
1469 "DOOM. Is that wise?\n", shminfo.shm_cpid);
1470 key++;
1471 }
1472 else
1473 {
1474 if (getuid() == shminfo.shm_perm.cuid)
1475 {
1476 rc = shmctl(id, IPC_RMID, 0);
1477 if (!rc)
1478 GenPrintf(EMSG_info,
1479 "Was able to kill my old shared memory\n");
1480 else
1481 I_Error("Was NOT able to kill my old shared memory");
1482
1483 id = shmget((key_t)key, size, IPC_CREAT|0777);
1484 if (id==-1)
1485 I_Error("Could not get shared memory");
1486
1487 rc=shmctl(id, IPC_STAT, &shminfo);
1488
1489 break;
1490 }
1491 if (size >= shminfo.shm_segsz)
1492 {
1493 GenPrintf(EMSG_info,
1494 "will use %d's stale shared memory\n",
1495 shminfo.shm_cpid);
1496 break;
1497 }
1498 else
1499 {
1500 GenPrintf(EMSG_warn,
1501 "warning: can't use stale "
1502 "shared memory belonging to id %d, "
1503 "key=0x%x\n",
1504 shminfo.shm_cpid, key);
1505 key++;
1506 }
1507 }
1508 }
1509 else
1510 {
1511 I_Error("could not get stats on key=%d", key);
1512 }
1513 }
1514 else
1515 {
1516 id = shmget((key_t)key, size, IPC_CREAT|0777);
1517 if (id==-1)
1518 {
1519 GenPrintf(EMSG_error, "errno=%d\n", errno);
1520 I_Error("Could not get any shared memory");
1521 }
1522 break;
1523 }
1524 } while (--pollution);
1525
1526 if (!pollution)
1527 {
1528 I_Error("Sorry, system too polluted with stale "
1529 "shared memory segments.\n");
1530 }
1531
1532 X_shminfo.shmid = id;
1533
1534 // attach to the shared memory segment
1535 image->data = X_shminfo.shmaddr = shmat(id, 0, 0);
1536 if(verbose)
1537 {
1538 GenPrintf(EMSG_ver, "shared memory id=%d, addr=0x%x\n", id,
1539 (int) (image->data));
1540 }
1541 return;
1542 }
1543
1544
1545 // return number of fullscreen or window modes, for listing
1546 // modetype is of modetype_e
VID_ModeRange(byte modetype)1547 range_t VID_ModeRange( byte modetype )
1548 {
1549 range_t mrange = { 1, 1 }; // first is always 1
1550 if(haveVoodoo)
1551 mrange.last = NUM_VOODOOMODES;
1552 else
1553 mrange.last = (modetype == MODE_fullscreen) ? num_vidmodes : MAXWINMODES;
1554 return mrange;
1555 }
1556
1557
VID_GetMode_Stat(modenum_t modenum)1558 modestat_t VID_GetMode_Stat( modenum_t modenum )
1559 {
1560 modestat_t ms;
1561
1562 if(haveVoodoo)
1563 { // voodoo modes
1564 int mi = modenum.index - 1;
1565 if(mi >= NUM_VOODOOMODES) goto fail;
1566
1567 ms.width = voodooModes[mi][0];
1568 ms.height = voodooModes[mi][1];
1569 ms.type = MODE_voodoo;
1570 ms.mark = "fx";
1571 }
1572 else if( modenum.modetype == MODE_fullscreen )
1573 { // fullscreen modes
1574 int mi = modenum.index - 1;
1575 if(mi >= num_vidmodes) goto fail;
1576
1577 ms.width = vidmodes[vidmap[mi]]->hdisplay;
1578 ms.height = vidmodes[vidmap[mi]]->vdisplay;
1579 ms.type = MODE_fullscreen;
1580 ms.mark = "";
1581 }
1582 else
1583 { // X11 window modes
1584 int mi = modenum.index;
1585 if(mi > MAXWINMODES) goto fail;
1586
1587 ms.width = windowedModes[mi][0];
1588 ms.height = windowedModes[mi][1];
1589 ms.type = MODE_window;
1590 ms.mark = "X11";
1591 }
1592 return ms;
1593
1594 fail:
1595 ms.type = MODE_NOP;
1596 ms.width = ms.height = 0;
1597 ms.mark = NULL;
1598 return ms;
1599 }
1600
1601
1602 // to display selection name of modes
VID_GetModeName(modenum_t modenum)1603 char * VID_GetModeName( modenum_t modenum )
1604 {
1605 modestat_t ms = VID_GetMode_Stat( modenum );
1606 if( ! ms.mark )
1607 goto fail;
1608
1609 // form the string
1610 snprintf( &vidModeName[modenum.index][0], MAX_LEN_VIDMODENAME, "%s %dx%d",
1611 ms.mark, ms.width, ms.height );
1612 vidModeName[modenum.index][MAX_LEN_VIDMODENAME] = 0;
1613 return &vidModeName[modenum.index][0];
1614
1615 fail:
1616 return NULL;
1617 }
1618
1619
1620 // rmodetype is of modetype_e
1621 // Returns MODE_NOP when none found
VID_GetModeForSize(int rw,int rh,byte rmodetype)1622 modenum_t VID_GetModeForSize( int rw, int rh, byte rmodetype )
1623 {
1624 modenum_t modenum = { MODE_NOP, 0 };
1625 int bestdist = INT_MAX;
1626 int best, tdist, i;
1627
1628 if(haveVoodoo)
1629 {
1630 best = 1; // standard mode if no other found
1631 for (i = 0; i < NUM_VOODOOMODES; i++)
1632 {
1633 tdist = abs(voodooModes[i][0] - rw) + abs(voodooModes[i][1] - rh);
1634 // find closest dist
1635 if( bestdist > tdist )
1636 {
1637 bestdist = tdist;
1638 best = i;
1639 if( tdist == 0 ) break; // found exact match
1640 }
1641 }
1642 modenum.index = best + 1; // 1..
1643 modenum.modetype = MODE_voodoo;
1644 }
1645 else if( rmodetype == MODE_fullscreen )
1646 { // scan fullscreen modes
1647
1648 // If vidmode_ext == false, or all w,h are too large
1649 // then will have num_vidmodes == 0
1650 if( num_vidmodes == 0 ) goto done;
1651 best = num_vidmodes-1; // default is smallest mode
1652
1653 for (i = 0; i < num_vidmodes; i++)
1654 {
1655 XF86VidModeModeInfo * vmm = vidmodes[vidmap[i]];
1656 tdist = abs(vmm->hdisplay - rw) + abs(vmm->vdisplay - rh);
1657 // find closest dist
1658 if( bestdist > tdist )
1659 {
1660 bestdist = tdist;
1661 best = i;
1662 if( tdist == 0 ) break; // found exact match
1663 }
1664 }
1665 modenum.index = best + 1; // 1..
1666 modenum.modetype = rmodetype;
1667 }
1668 else
1669 { // windowed modes, 1..
1670 best = MAXWINMODES; // default
1671 for (i = 1; i <= MAXWINMODES; i++)
1672 {
1673 tdist = abs(windowedModes[i][0] - rw) + abs(windowedModes[i][1] - rh);
1674 // find closest dist
1675 if( bestdist > tdist )
1676 {
1677 bestdist = tdist;
1678 best = i;
1679 if( tdist == 0 ) break; // found exact match
1680 }
1681 }
1682 modenum.index = best; // 1..
1683 modenum.modetype = rmodetype;
1684 }
1685 done:
1686 return modenum;
1687 }
1688
1689
destroyWindow(void)1690 static void destroyWindow(void)
1691 {
1692 I_UngrabMouse();
1693
1694 if(rendermode==render_soft)
1695 {
1696 if( vid.buffer )
1697 {
1698 free(vid.buffer);
1699 vid.buffer = vid.direct = NULL; // I want to have an access violation if something goes wrong
1700 vid.display = NULL;
1701 vid.screen1 = NULL;
1702 }
1703
1704 if(doShm) {
1705 if (!XShmDetach(X_display, &X_shminfo))
1706 I_Error("XShmDetach() failed in destroyWindow()");
1707
1708 // Release shared memory.
1709 shmdt(X_shminfo.shmaddr);
1710 shmctl(X_shminfo.shmid, IPC_RMID, 0);
1711
1712 if( image )
1713 {
1714 XDestroyImage(image); // is this correct? there is no shm counterpart
1715 image = NULL;
1716 }
1717 }
1718 else {
1719 if( image )
1720 {
1721 XDestroyImage(image);
1722 image = NULL;
1723 }
1724 }
1725
1726 if( X_mainWindow )
1727 {
1728 XDestroyWindow(X_display, X_mainWindow);
1729 X_mainWindow=0;
1730 }
1731 }
1732 else {
1733 ; // actually do nothing here; HookXwin takes care; not very clean, but it's legacy
1734 }
1735
1736 return;
1737 }
1738
1739 // Called multiple times
createWindow(boolean set_fullscreen,modenum_t modenum)1740 static int createWindow(boolean set_fullscreen, modenum_t modenum)
1741 {
1742 int oktodraw;
1743 unsigned long attribmask;
1744 XSetWindowAttributes attribs;
1745 XGCValues xgcvalues;
1746 XTextProperty windowName, iconName;
1747 int valuemask;
1748 char *window_name = "Legacy";
1749 char *icon_name = window_name;
1750
1751 // change to the mode
1752 if( !set_fullscreen )
1753 {
1754 if( vidmode_ext && vidmodes )
1755 {
1756 XF86VidModeSwitchToMode(X_display, X_screen, vidmodes[0]);
1757 }
1758 else if( !vidmode_ext ) // probably not necessary
1759 {
1760 }
1761 vidmode_active = false;
1762 }
1763 else
1764 {
1765 // Fullscreen
1766 XF86VidModeSwitchToMode(X_display, X_screen, vidmodes[vidmap[modenum.index-1]]);
1767 vidmode_active = true;
1768 // Move the viewport to top left
1769 XF86VidModeSetViewPort(X_display, X_screen, 0, 0);
1770 }
1771
1772 if(rendermode==render_soft) {
1773 // setup attributes for main window
1774 if (vidmode_active) {
1775 // [WDJ] Submitted by pld-linux: Do not force CWColormap, it may be a truecolor mode.
1776 attribmask = CWSaveUnder | CWBackingStore |
1777 CWEventMask | CWOverrideRedirect;
1778
1779 attribs.override_redirect = True;
1780 attribs.backing_store = NotUseful;
1781 attribs.save_under = False;
1782 } else {
1783 // [WDJ] Submitted by pld-linux: Do not force CWColormap, it may be a truecolor mode.
1784 attribmask = CWBorderPixel | CWEventMask;
1785 }
1786
1787 attribs.event_mask = KeyPressMask | KeyReleaseMask
1788 #ifndef POLL_POINTER
1789 | PointerMotionMask | ButtonPressMask | ButtonReleaseMask
1790 #endif
1791 | ExposureMask | StructureNotifyMask;
1792
1793 // [WDJ] Submitted by pld-linux: Do not force CWColormap, it may be a truecolor mode.
1794 // Only in DRAW8PAL does X handle the colormap, not in TrueColor where we do.
1795 if (x_drawmode == DRAW8PAL) {
1796 attribmask |= CWColormap;
1797 attribs.colormap = X_cmap;
1798 }
1799 attribs.border_pixel = 0;
1800
1801 // create the main window
1802 X_mainWindow = XCreateWindow(X_display,
1803 RootWindow(X_display, X_screen),
1804 0, 0, // x, y,
1805 vid.width, vid.height,
1806 0, // borderwidth
1807 X_visualinfo.depth, // depth
1808 InputOutput,
1809 X_visual,
1810 attribmask,
1811 &attribs);
1812
1813 if(!X_mainWindow) goto fail;
1814
1815 // create the GC
1816 valuemask = GCGraphicsExposures;
1817 xgcvalues.graphics_exposures = False;
1818 X_gc = XCreateGC(X_display,
1819 X_mainWindow,
1820 valuemask,
1821 &xgcvalues );
1822 } else {
1823 // Hardware renderer
1824 X_mainWindow = HWD.pfnHookXwin(X_display, vid.width, vid.height, vidmode_active);
1825 if(X_mainWindow == 0) goto fail;
1826 }
1827
1828 // moved here
1829 XDefineCursor(X_display, X_mainWindow,
1830 createnullcursor( X_display, X_mainWindow ) );
1831
1832 // set size hints for window manager, so that resizing isn't possible
1833 X_size.flags = USPosition | PSize | PMinSize | PMaxSize;
1834 X_size.min_width = vid.width;
1835 X_size.min_height = vid.height;
1836 X_size.max_width = vid.width;
1837 X_size.max_height = vid.height;
1838
1839 // window and icon name for the window manager
1840 XStringListToTextProperty(&window_name, 1, &windowName);
1841 XStringListToTextProperty(&icon_name, 1, &iconName);
1842
1843 // window manager hints
1844 X_wm.initial_state = NormalState;
1845 X_wm.input = True;
1846 X_wm.flags = StateHint | InputHint;
1847
1848 // property class, in case we get a configuration file sometime
1849 X_class.res_name = "legacy";
1850 X_class.res_class = "Legacy";
1851
1852 // set the properties
1853 XSetWMProperties(X_display, X_mainWindow, &windowName, &iconName,
1854 0 /*argv*/, 0 /*argc*/, &X_size, &X_wm, &X_class);
1855
1856 // set window manager protocol
1857 X_wm_delwin = XInternAtom(X_display, "WM_DELETE_WINDOW", False);
1858 XSetWMProtocols(X_display, X_mainWindow, &X_wm_delwin, 1);
1859
1860 // map the window
1861 XMapWindow(X_display, X_mainWindow);
1862
1863 if (vidmode_active) {
1864 XMoveWindow(X_display, X_mainWindow, 0, 0);
1865 XRaiseWindow(X_display, X_mainWindow);
1866 XWarpPointer(X_display, None, X_mainWindow, 0, 0, 0, 0, 0, 0);
1867 XFlush(X_display);
1868 // Move the viewport to top left
1869 XF86VidModeSetViewPort(X_display, X_screen, 0, 0);
1870 }
1871 XFlush(X_display);
1872
1873 // wait until it is OK to draw
1874 oktodraw = 0;
1875 while (!oktodraw)
1876 {
1877 XNextEvent(X_display, &X_event);
1878 if (X_event.type == Expose
1879 && !X_event.xexpose.count)
1880 {
1881 oktodraw = 1;
1882 }
1883 }
1884
1885 // set the focus to the window
1886 XSetInputFocus(X_display, X_mainWindow, RevertToPointerRoot, CurrentTime);
1887
1888 // get the pointer coordinates so that the first pointer move won't
1889 // be completely wrong
1890 XQueryPointer(X_display, X_mainWindow, &dummy, &dummy,
1891 &dont_care, &dont_care,
1892 &lastmousex, &lastmousey,
1893 &dont_care_ui);
1894
1895 vid.widthbytes = vid.width * vid.bytepp;
1896 vid.ybytes = vid.widthbytes;
1897 vid.screen_size = vid.ybytes * vid.height;
1898
1899 if(rendermode==render_soft)
1900 {
1901 if (doShm)
1902 {
1903 X_shmeventtype = XShmGetEventBase(X_display) + ShmCompletion;
1904
1905 // create the image
1906 image = XShmCreateImage(X_display,
1907 X_visual,
1908 X_visualinfo.depth,
1909 ZPixmap,
1910 0,
1911 &X_shminfo,
1912 vid.width,
1913 vid.height );
1914
1915 grabsharedmemory(image->bytes_per_line * image->height);
1916
1917 if (!image->data)
1918 {
1919 perror("");
1920 I_Error("shmat() failed in InitGraphics()");
1921 }
1922
1923 // get the X server to attach to it
1924 if (!XShmAttach(X_display, &X_shminfo))
1925 I_Error("XShmAttach() failed in InitGraphics()");
1926 }
1927 else
1928 {
1929 image = XCreateImage(X_display,
1930 X_visual,
1931 X_visualinfo.depth,
1932 ZPixmap,
1933 0, // offset
1934 (char*)malloc(vid.width * vid.height * x_bytepp),
1935 vid.width, vid.height,
1936 8*x_bytepp,
1937 vid.width*x_bytepp );
1938 }
1939
1940 // [WDJ] Draw 8pp and translate to other bpp in FinishUpdate
1941 // unless -bpp or -native
1942 vid.buffer = (unsigned char *) malloc (vid.screen_size * NUMSCREENS);
1943 vid.display = vid.buffer;
1944 vid.screen1 = vid.buffer + vid.screen_size;
1945 #ifdef TILTVIEW
1946 // FIXME: TILTVIEW must not access image, it may be different bpp
1947 // FIXME: external access to direct is not allowed
1948 // Forces Direct to be buffer
1949 vid.direct = vid.buffer;
1950 vid.direct_rowbytes = vid.ybytes;
1951 vid.direct_size = vid.screen_size;
1952 #else
1953 // Direct is video
1954 vid.direct = (byte*)image->data;
1955 vid.direct_rowbytes = vid.width * x_bytepp;
1956 vid.direct_size = vid.direct_rowbytes * vid.height;
1957 if( x_bytepp == vid.bytepp && vid.direct_rowbytes == vid.widthbytes )
1958 {
1959 // can draw direct into image
1960 vid.display = vid.direct;
1961 GenPrintf(EMSG_info, "Draw direct\n");
1962 }
1963 #endif
1964 // Will segfault on the verbose messages if the screen is not setup.
1965 V_Setup_VideoDraw();
1966
1967 if( verbose )
1968 {
1969 GenPrintf(EMSG_ver, "Drawing %i bpp, video at % i bpp\n", vid.bitpp, x_bitpp );
1970 }
1971 vid.fullscreen = set_fullscreen;
1972
1973 // added for 1.27 19990220 by Kin
1974 graphics_state = VGS_active;
1975 } else {
1976 graphics_state = ((X_mainWindow==0)? VGS_off:VGS_active);
1977 }
1978 return 1;
1979
1980 fail:
1981 return 0;
1982 }
1983
1984
VID_SetMode(modenum_t modenum)1985 int VID_SetMode( modenum_t modenum )
1986 {
1987 boolean set_fullscreen = (modenum.modetype == MODE_fullscreen);
1988
1989 vid.draw_ready = 0; // disable print reaching console
1990
1991 if(haveVoodoo) {
1992 int mi = modenum.index - 1;
1993 if(mi >= NUM_VOODOOMODES) goto fail_end;
1994
1995 destroyWindow();
1996 set_fullscreen = true;
1997 vid.width = voodooModes[mi][0];
1998 vid.height = voodooModes[mi][1];
1999 }
2000 else if (set_fullscreen) { // fullscreen
2001 int mi = modenum.index - 1;
2002 // If no vidmode_ext, then num_vidmodes == 0
2003 if(mi >= num_vidmodes) goto fail_end;
2004
2005 destroyWindow();
2006 vid.width = vidmodes[vidmap[mi]]->hdisplay;
2007 vid.height = vidmodes[vidmap[mi]]->vdisplay;
2008 }
2009 else { // X11
2010 int mi = modenum.index;
2011 if(mi >= MAXWINMODES) goto fail_end;
2012
2013 destroyWindow();
2014 vid.width = windowedModes[mi][0];
2015 vid.height = windowedModes[mi][1];
2016 }
2017
2018 vid.recalc = 1;
2019 GenPrintf( EMSG_info, "VID_SetMode(%s,%i) %dx%d\n",
2020 modetype_string[modenum.modetype], modenum.index, vid.width, vid.height);
2021
2022 if(!createWindow( set_fullscreen, modenum ))
2023 return FAIL_create;
2024
2025 I_StartupMouse( false );
2026
2027 vid.modenum = modenum;
2028
2029 return 1;
2030
2031 fail_end:
2032 return FAIL_end;
2033 }
2034
2035 // detect Voodoo card
detect_Voodoo(void)2036 void detect_Voodoo( void )
2037 {
2038 static boolean isVoodooChecked = false;
2039 char *renderer_str, *voodoo_detect;
2040 // I cannot detect the Voodoo earlier, so I try to catch it here
2041 if(!isVoodooChecked) {
2042 if(rendermode == render_opengl) {
2043 renderer_str = HWD.pfnGetRenderer();
2044 if( verbose )
2045 {
2046 GenPrintf(EMSG_ver, "%s\n", renderer_str );
2047 }
2048 // FIXME: if Mesa ever decides to change the this spotword, we're deep in the shit
2049 voodoo_detect = strstr(renderer_str, "Voodoo_Graphics");
2050 if( ! voodoo_detect )
2051 voodoo_detect = strstr(renderer_str, "Voodoo");
2052 if(voodoo_detect != NULL)
2053 {
2054 haveVoodoo = true;
2055 if( verbose )
2056 {
2057 GenPrintf(EMSG_ver, "Voodoo card detected\n" );
2058 }
2059 }
2060 }
2061 isVoodooChecked = true;
2062 }
2063 }
2064
2065
2066 // request_drawmode : vid_drawmode_e
2067 // request_fullscreen : true if want fullscreen modes
2068 // request_bitpp : bits per pixel
2069 // Return true if there are viable modes.
VID_Query_Modelist(byte request_drawmode,byte request_fullscreen,byte request_bitpp)2070 boolean VID_Query_Modelist( byte request_drawmode, byte request_fullscreen, byte request_bitpp )
2071 {
2072 int num;
2073
2074 // Require modelist before rendermode is set.
2075
2076 // Only has native bpp and opengl (using native).
2077 if( request_drawmode < DRM_opengl )
2078 {
2079 if( request_bitpp != native_bitpp )
2080 return false;
2081 }
2082
2083 if(haveVoodoo)
2084 {
2085 num = NUM_VOODOOMODES;
2086 }
2087 else if( request_fullscreen )
2088 {
2089 // once we have the vidmodes, it is not going to change
2090 if( num_vidmodes == 0 )
2091 determine_VidModes();
2092 num = num_vidmodes;
2093 }
2094 else
2095 num = MAXWINMODES;
2096
2097 return (num > 0);
2098 }
2099
2100
2101
2102 // Setup HWR calls according to rendermode.
I_Rendermode_setup(void)2103 int I_Rendermode_setup( void )
2104 {
2105 static byte HWD_current = 0;
2106 void *dlptr;
2107
2108 if( rendermode == render_opengl )
2109 {
2110 if( HWD_current == render_opengl )
2111 return 1;
2112
2113 // only set MESA_GLX_FX if not set by set user
2114 if(!getenv("MESA_GLX_FX"))
2115 {
2116 if(M_CheckParm("-winvoodoo"))
2117 {
2118 // use windowed mode for voodoo cards if requested
2119 putenv("MESA_GLX_FX=window");
2120 putenv("SSTV2_VGA_PASS=1");
2121 putenv("SSTV2_NOSHUTDOWN=1");
2122 }
2123 else
2124 {
2125 // Tell Mesa GLX to use 3Dfx driver in fullscreen mode.
2126 putenv("MESA_GLX_FX=fullscreen");
2127 }
2128
2129 // Disable 3Dfx Glide splash screen
2130 putenv("FX_GLIDE_NO_SPLASH=0");
2131 }
2132
2133 // try to open library in CWD
2134 dlptr = dlopen("./r_opengl.so",RTLD_NOW | RTLD_GLOBAL);
2135
2136 if(!dlptr) {
2137 // try to open in LIBPATH
2138 dlptr = dlopen("r_opengl.so",RTLD_NOW | RTLD_GLOBAL);
2139 }
2140
2141 if(!dlptr)
2142 {
2143 // to get first error messages
2144 dlopen("./r_opengl.so",RTLD_NOW | RTLD_GLOBAL);
2145 GenPrintf(EMSG_error, "Error opening r_opengl.so\n%s\n", dlerror());
2146 #if 0
2147 {
2148 // [WDJ] Troubleshoot why cannot open it
2149 char * cwd2 = getcwd( NULL, 0 ); // malloc
2150 GenPrintf(EMSG_error, "CWD: %s \n", cwd2 );
2151 free( cwd2 );
2152 char * readperm = (access( "r_opengl.so", R_OK ) == 0 )? "OK": "NOT PERMITTED";
2153 char * execperm = (access( "r_opengl.so", X_OK ) == 0 )? "OK": "NOT PERMITTED";
2154 GenPrintf(EMSG_error, "Access r_opengl.so: READ %s, EXECUTE %s\n", readperm, execperm );
2155 }
2156 #endif
2157 // Fail to software rendering
2158 rendermode = render_soft;
2159 return FAIL;
2160 }
2161
2162 // linkage to dll r_opengl.so
2163 HWD.pfnInit = dlsym(dlptr,"Init");
2164 HWD.pfnShutdown = dlsym(dlptr,"Shutdown");
2165 HWD.pfnHookXwin = dlsym(dlptr,"HookXwin");
2166 HWD.pfnSetPalette = dlsym(dlptr,"SetPalette");
2167 HWD.pfnFinishUpdate = dlsym(dlptr,"FinishUpdate");
2168 HWD.pfnDraw2DLine = dlsym(dlptr,"Draw2DLine");
2169 HWD.pfnDrawPolygon = dlsym(dlptr,"DrawPolygon");
2170 //HWD.pfnGetState = dlsym(dlptr,"GetState");
2171 HWD.pfnSetBlend = dlsym(dlptr,"SetBlend");
2172 HWD.pfnClearBuffer = dlsym(dlptr,"ClearBuffer");
2173 HWD.pfnSetTexture = dlsym(dlptr,"SetTexture");
2174 HWD.pfnReadRect = dlsym(dlptr,"ReadRect");
2175 HWD.pfnGClipRect = dlsym(dlptr,"GClipRect");
2176 HWD.pfnClearMipMapCache = dlsym(dlptr,"ClearMipMapCache");
2177 HWD.pfnSetSpecialState = dlsym(dlptr,"SetSpecialState");
2178 HWD.pfnGetRenderer = dlsym(dlptr, "GetRenderer");
2179 //FIXME: check if all this is ok:
2180 HWD.pfnDrawMD2 = dlsym(dlptr, "DrawMD2");
2181 HWD.pfnSetTransform = dlsym(dlptr, "SetTransform");
2182 HWD.pfnGetTextureUsed = dlsym(dlptr, "GetTextureUsed");
2183 HWD.pfnGetRenderVersion = dlsym(dlptr, "GetRenderVersion");
2184
2185 // check gl renderer lib
2186 if (HWD.pfnGetRenderVersion() != DOOMLEGACY_COMPONENT_VERSION)
2187 {
2188 I_Error ("The version of the renderer doesn't match the version of the executable\nBe sure you have installed Doom Legacy properly.\n");
2189 }
2190
2191 HWD_current = render_opengl;
2192 }
2193 return 1;
2194 }
2195
2196
2197 // Called once. Init with basic error message screen.
I_StartupGraphics(void)2198 void I_StartupGraphics(void)
2199 {
2200 modenum_t initialmode = {MODE_window,0}; // the initial mode
2201 // pre-init by V_Init_VideoControl
2202 char *displayname;
2203
2204 vid.draw_ready = 0; // disable print reaching console
2205 graphics_state = VGS_startup;
2206
2207 // FIXME: catch other signals as well?
2208 signal(SIGINT, (void (*)(int)) I_Quit);
2209 signal(SIGTERM, (void (*)(int)) I_Quit); // shutdown gracefully if terminated
2210
2211 XSetErrorHandler( X_error_handler );
2212
2213 // subject to -display switch
2214 displayname = initDisplay(); // Set X_display
2215
2216 findVisual(); // Set X_screen, X_visualinfo, X_visual, x_drawmode
2217
2218 determineBPP(); // Sets x_bitpp and x_bytepp from X_visualinfo.depth
2219 native_drawmode = DRM_native;
2220 native_bitpp = x_bitpp;
2221 native_bytepp = x_bytepp;
2222
2223 check_vidmode_extension(); // Set vidmode_ext
2224 checkForShm(); // Set doShm
2225
2226 if( V_CanDraw( x_bitpp ))
2227 {
2228 vid.bitpp = x_bitpp;
2229 vid.bytepp = x_bytepp;
2230 GenPrintf(EMSG_info, "Video %s: %i bpp (%i bytes)\n", displayname, vid.bitpp, vid.bytepp);
2231 }
2232 else if( verbose )
2233 {
2234 // Use 8 bit and do the palette translation.
2235 vid.bitpp = 8;
2236 vid.bytepp = 1;
2237 GenPrintf(EMSG_ver, "Video %s: %i bpp rejected\n", displayname, x_bitpp );
2238 }
2239 determineColorMask(); // Set color offset and masks
2240 createColorMap(); // Create X_cmap and x_colormap2/3/4
2241
2242 // window
2243 initialmode = VID_GetModeForSize( vid.width, vid.height, MODE_window );
2244 if( ! createWindow( false, initialmode) )
2245 goto abort_error;
2246
2247 // startupscreen does not need a grabbed mouse
2248 I_UngrabMouse();
2249
2250 if( verbose )
2251 GenPrintf(EMSG_ver, "StartupGraphics completed\n" );
2252
2253 vid.modenum = initialmode;
2254 vid.recalc = true;
2255 graphics_state = VGS_active;
2256 return;
2257
2258 abort_error:
2259 // cannot return without a display screen
2260 I_Error("StartupGraphics Abort\n");
2261 }
2262
2263
2264 // Called to start rendering graphic screen according to the request switches.
2265 // Fullscreen modes are possible.
2266 // param: req_drawmode, req_bitpp, req_alt_bitpp, req_width, req_height.
2267 // Returns FAIL_select, FAIL_end, FAIL_create, of status_return_e, 1 on success;
I_RequestFullGraphics(byte select_fullscreen)2268 int I_RequestFullGraphics( byte select_fullscreen )
2269 {
2270 modenum_t initialmode;
2271 byte select_fullscreen_mode;
2272 int ret_value;
2273
2274 vid.draw_ready = 0; // disable print reaching console
2275 graphics_state = VGS_startup;
2276 destroyWindow();
2277
2278 // setup vid 19990110 by Kin
2279
2280 if( req_drawmode == DRM_opengl )
2281 {
2282 ret_value = I_Rendermode_setup(); // some functions needed immediately
2283 if( ret_value < 0 )
2284 return ret_value;
2285
2286 // requires HWD.pfnGetRenderer
2287 detect_Voodoo();
2288 }
2289
2290 // Set hardware vidmodes and vidmap, from X_display, X_screen
2291
2292 determine_VidModes();
2293
2294 findVisual(); // Set X_screen, X_visualinfo, X_visual, x_drawmode
2295
2296 determineBPP(); // Sets x_bitpp and x_bytepp from X_visualinfo.depth
2297
2298 checkForShm(); // Set doShm
2299
2300 switch(req_drawmode)
2301 {
2302 case DRM_explicit_bpp:
2303 if( req_bitpp == 8 )
2304 goto draw_pal8;
2305
2306 if( x_bitpp != req_bitpp )
2307 {
2308 GenPrintf(EMSG_error, "Not in %i bpp mode\n", req_bitpp );
2309 goto no_modes;
2310 }
2311 vid.bitpp = x_bitpp;
2312 vid.bytepp = x_bytepp;
2313 goto accept;
2314
2315 case DRM_native:
2316 if( V_CanDraw( native_bitpp ))
2317 {
2318 if( verbose )
2319 GenPrintf(EMSG_info, "Video %i bpp (%i bytes)\n", native_bitpp, native_bytepp);
2320 goto draw_native;
2321 }
2322 else
2323 {
2324 GenPrintf( EMSG_info,"Native %i bpp rejected\n", native_bitpp );
2325 // Use 8 bit and do the palette translation.
2326 goto draw_pal8;
2327 }
2328 break;
2329
2330 case DRM_opengl:
2331 default:
2332 goto draw_native;
2333 }
2334
2335 draw_pal8:
2336 // Use 8 bit and do the palette translation.
2337 vid.bitpp = 8;
2338 vid.bytepp = 1;
2339 goto accept;
2340
2341 draw_native:
2342 vid.bitpp = native_bitpp;
2343 vid.bytepp = native_bytepp;
2344 goto accept;
2345
2346 accept:
2347 determineColorMask(); // Set color offset and masks
2348 createColorMap(); // Create X_cmap and x_colormap2/3/4
2349
2350 if( select_fullscreen
2351 && ! haveVoodoo
2352 && num_vidmodes == 0) // do we have any fullscreen modes at all?
2353 {
2354 // switch to windowed
2355 select_fullscreen = 0;
2356 GenPrintf(EMSG_info,"No modes below 1600x1200 available\nSwitching to windowed mode ...\n");
2357 // goto no_modes;
2358 }
2359
2360 vid.width = req_width;
2361 vid.height = req_height;
2362
2363 select_fullscreen_mode = vid_mode_table[select_fullscreen];
2364 initialmode = VID_GetModeForSize( req_width, req_height, select_fullscreen_mode );
2365 if( ! createWindow( select_fullscreen, initialmode ) )
2366 return FAIL_create;
2367
2368 // startupscreen does not need a grabbed mouse
2369 I_UngrabMouse();
2370
2371 if( verbose )
2372 GenPrintf(EMSG_ver, "RequestFullGraphics completed\n" );
2373
2374 vid.modenum = initialmode;
2375 vid.recalc = true;
2376 graphics_state = VGS_fullactive;
2377 return 1;
2378
2379 no_modes:
2380 return FAIL_select;
2381 }
2382
2383
I_ShutdownGraphics(void)2384 void I_ShutdownGraphics(void)
2385 {
2386 if( graphics_state <= VGS_shutdown )
2387 return;
2388
2389 graphics_state = VGS_shutdown; // to catch some repeats due to errors
2390
2391 // was graphics initialized anyway?
2392 if (!X_display)
2393 return;
2394
2395 destroyWindow();
2396
2397 // return to normal mode
2398 if( vidmode_ext )
2399 {
2400 if( vidmodes )
2401 {
2402 XF86VidModeSwitchToMode(X_display, X_screen, vidmodes[0]);
2403 }
2404 }
2405
2406 if(rendermode != render_soft) {
2407 HWD.pfnShutdown();
2408 }
2409
2410 XCloseDisplay(X_display);
2411 graphics_state = VGS_off;
2412 }
2413