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