1 /*
2 vid_x11.c
3
4 General X11 video driver
5
6 Copyright (C) 1996-1997 Id Software, Inc.
7 Copyright (C) 1999-2000 contributors of the QuakeForge project
8 Copyright (C) 2000 Marcus Sundberg [mackan@stacken.kth.se]
9 Copyright (C) 1999,2000 contributors of the QuakeForge project
10 Please see the file "AUTHORS" for a list of contributors
11
12 This program is free software; you can redistribute it and/or
13 modify it under the terms of the GNU General Public License
14 as published by the Free Software Foundation; either version 2
15 of the License, or (at your option) any later version.
16
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20
21 See the GNU General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to:
25
26 Free Software Foundation, Inc.
27 59 Temple Place - Suite 330
28 Boston, MA 02111-1307, USA
29
30 */
31 #define _BSD
32
33 #ifdef HAVE_CONFIG_H
34 # include "config.h"
35 #endif
36
37 #ifdef HAVE_STRING_H
38 # include <string.h>
39 #endif
40 #ifdef HAVE_STRINGS_H
41 # include <strings.h>
42 #endif
43 #ifdef HAVE_UNISTD_H
44 # include <unistd.h>
45 #endif
46
47 #include <ctype.h>
48 #include <dlfcn.h>
49 #include <errno.h>
50 #include <limits.h>
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <sys/ipc.h>
54 #include <sys/shm.h>
55 #include <sys/time.h>
56 #include <sys/types.h>
57 #include <X11/Xatom.h>
58 #include <X11/Xlib.h>
59 #include <X11/Xutil.h>
60 #include <X11/keysym.h>
61 #include <X11/extensions/XShm.h>
62
63 #ifdef HAVE_VIDMODE
64 # include <X11/extensions/xf86vmode.h>
65 #endif
66
67 #include "QF/cmd.h"
68 #include "QF/console.h"
69 #include "QF/cvar.h"
70 #include "QF/qargs.h"
71 #include "QF/qendian.h"
72 #include "QF/screen.h"
73 #include "QF/sys.h"
74 #include "QF/va.h"
75
76 #include "compat.h"
77 #include "context_x11.h"
78 #include "d_iface.h"
79 #include "dga_check.h"
80 #include "vid_internal.h"
81
82 int XShmGetEventBase (Display *x); // for broken X11 headers
83
84 static GC x_gc;
85
86 static qboolean doShm;
87 static XShmSegmentInfo x_shminfo[2];
88
89 static int current_framebuffer;
90 static XImage *x_framebuffer[2] = { 0, 0 };
91
92 int VID_options_items = 1;
93
94 static byte current_palette[768];
95
96 typedef unsigned char PIXEL8;
97 typedef unsigned short PIXEL16;
98 typedef unsigned int PIXEL24;
99
100 static PIXEL16 st2d_8to16table[256];
101 static PIXEL24 st2d_8to24table[256];
102 static int shiftmask_fl = 0;
103 static long r_shift, g_shift, b_shift;
104 static unsigned long r_mask, g_mask, b_mask;
105
106 #define GLX_RGBA 4 // true if RGBA mode
107 #define GLX_DOUBLEBUFFER 5 // double buffering supported
108 #define GLX_RED_SIZE 8 // number of red component bits
109 #define GLX_GREEN_SIZE 9 // number of green component bits
110 #define GLX_BLUE_SIZE 10 // number of blue component bits
111 #define GLX_DEPTH_SIZE 12 // number of depth bits
112
113 // GLXContext is a pointer to opaque data
114 typedef struct __GLXcontextRec *GLXContext;
115 typedef XID GLXDrawable;
116
117 // Define GLAPIENTRY to a useful value
118 #ifndef GLAPIENTRY
119 # ifdef _WIN32
120 # include <windows.h>
121 # define GLAPIENTRY WINAPI
122 # undef LoadImage
123 # else
124 # ifdef APIENTRY
125 # define GLAPIENTRY APIENTRY
126 # else
127 # define GLAPIENTRY
128 # endif
129 # endif
130 #endif
131 static GLXContext ctx = NULL;
132 static void *libgl_handle;
133 static void (*qfglXSwapBuffers) (Display *dpy, GLXDrawable drawable);
134 static XVisualInfo* (*qfglXChooseVisual) (Display *dpy, int screen,
135 int *attribList);
136 static GLXContext (*qfglXCreateContext) (Display *dpy, XVisualInfo *vis,
137 GLXContext shareList, Bool direct);
138 static Bool (*qfglXMakeCurrent) (Display *dpy, GLXDrawable drawable,
139 GLXContext ctx);
140 static void (GLAPIENTRY *qfglFinish) (void);
141 static void *(*glGetProcAddress) (const char *symbol) = NULL;
142 static int use_gl_procaddress = 0;
143 static cvar_t *gl_driver;
144
145 static void (*choose_visual) (void);
146 static void (*create_context) (void);
147
148 static void *
QFGL_GetProcAddress(void * handle,const char * name)149 QFGL_GetProcAddress (void *handle, const char *name)
150 {
151 void *glfunc = NULL;
152
153 if (use_gl_procaddress && glGetProcAddress)
154 glfunc = glGetProcAddress (name);
155 if (!glfunc)
156 glfunc = dlsym (handle, name);
157 return glfunc;
158 }
159
160 static void *
QFGL_ProcAddress(const char * name,qboolean crit)161 QFGL_ProcAddress (const char *name, qboolean crit)
162 {
163 void *glfunc = NULL;
164
165 Sys_MaskPrintf (SYS_VID, "DEBUG: Finding symbol %s ... ", name);
166
167 glfunc = QFGL_GetProcAddress (libgl_handle, name);
168 if (glfunc) {
169 Sys_MaskPrintf (SYS_VID, "found [%p]\n", glfunc);
170 return glfunc;
171 }
172 Sys_MaskPrintf (SYS_VID, "not found\n");
173
174 if (crit) {
175 if (strncmp ("fxMesa", name, 6) == 0) {
176 Sys_Printf ("This target requires a special version of Mesa with "
177 "support for Glide and SVGAlib.\n");
178 Sys_Printf ("If you are in X, try using a GLX or SGL target.\n");
179 }
180 Sys_Error ("Couldn't load critical OpenGL function %s, exiting...",
181 name);
182 }
183 return NULL;
184 }
185
186 static void
glx_choose_visual(void)187 glx_choose_visual (void)
188 {
189 int attrib[] = {
190 GLX_RGBA,
191 GLX_RED_SIZE, 1,
192 GLX_GREEN_SIZE, 1,
193 GLX_BLUE_SIZE, 1,
194 GLX_DOUBLEBUFFER,
195 GLX_DEPTH_SIZE, 1,
196 None
197 };
198
199 x_visinfo = qfglXChooseVisual (x_disp, x_screen, attrib);
200 if (!x_visinfo) {
201 Sys_Error ("Error couldn't get an RGB, Double-buffered, Depth visual");
202 }
203 x_vis = x_visinfo->visual;
204 }
205
206 static void
glx_create_context(void)207 glx_create_context (void)
208 {
209 XSync (x_disp, 0);
210 ctx = qfglXCreateContext (x_disp, x_visinfo, NULL, True);
211 qfglXMakeCurrent (x_disp, x_win, ctx);
212 viddef.init_gl ();
213 }
214
215 static void
glx_end_rendering(void)216 glx_end_rendering (void)
217 {
218 qfglFinish ();
219 qfglXSwapBuffers (x_disp, x_win);
220 }
221
222 static void
glx_load_gl(void)223 glx_load_gl (void)
224 {
225 int flags = RTLD_NOW;
226
227 choose_visual = glx_choose_visual;
228 create_context = glx_create_context;
229
230 viddef.get_proc_address = QFGL_ProcAddress;
231 viddef.end_rendering = glx_end_rendering;
232
233 #ifdef RTLD_GLOBAL
234 flags |= RTLD_GLOBAL;
235 #endif
236 if (!(libgl_handle = dlopen (gl_driver->string, flags))) {
237 Sys_Error ("Couldn't load OpenGL library %s: %s", gl_driver->string,
238 dlerror ());
239 }
240 glGetProcAddress = dlsym (libgl_handle, "glXGetProcAddress");
241 if (!glGetProcAddress)
242 glGetProcAddress = dlsym (libgl_handle, "glXGetProcAddressARB");
243
244 qfglXSwapBuffers = QFGL_ProcAddress ("glXSwapBuffers", true);
245 qfglXChooseVisual = QFGL_ProcAddress ("glXChooseVisual", true);
246 qfglXCreateContext = QFGL_ProcAddress ("glXCreateContext", true);
247 qfglXMakeCurrent = QFGL_ProcAddress ("glXMakeCurrent", true);
248
249 use_gl_procaddress = 1;
250
251 qfglFinish = QFGL_ProcAddress ("glFinish", true);
252 }
253
254 static void
shiftmask_init(void)255 shiftmask_init (void)
256 {
257 unsigned long long x;
258
259 r_mask = x_vis->red_mask;
260 g_mask = x_vis->green_mask;
261 b_mask = x_vis->blue_mask;
262
263 for (r_shift = -8, x = 1; x < r_mask; x <<= 1)
264 r_shift++;
265 for (g_shift = -8, x = 1; x < g_mask; x <<= 1)
266 g_shift++;
267 for (b_shift = -8, x = 1; x < b_mask; x <<= 1)
268 b_shift++;
269 shiftmask_fl = 1;
270 }
271
272 static PIXEL16
xlib_rgb16(int r,int g,int b)273 xlib_rgb16 (int r, int g, int b)
274 {
275 PIXEL16 p = 0;
276
277 if (!shiftmask_fl)
278 shiftmask_init ();
279
280 if (r_shift > 0) {
281 p = (r << (r_shift)) & r_mask;
282 } else {
283 if (r_shift < 0) {
284 p = (r >> (-r_shift)) & r_mask;
285 } else {
286 p |= (r & r_mask);
287 }
288 }
289
290 if (g_shift > 0) {
291 p |= (g << (g_shift)) & g_mask;
292 } else {
293 if (g_shift < 0) {
294 p |= (g >> (-g_shift)) & g_mask;
295 } else {
296 p |= (g & g_mask);
297 }
298 }
299
300 if (b_shift > 0) {
301 p |= (b << (b_shift)) & b_mask;
302 } else {
303 if (b_shift < 0) {
304 p |= (b >> (-b_shift)) & b_mask;
305 } else {
306 p |= (b & b_mask);
307 }
308 }
309
310 return p;
311 }
312
313 static PIXEL24
xlib_rgb24(int r,int g,int b)314 xlib_rgb24 (int r, int g, int b)
315 {
316 PIXEL24 p = 0;
317
318 if (!shiftmask_fl)
319 shiftmask_init ();
320
321 if (r_shift > 0) {
322 p = (r << (r_shift)) & r_mask;
323 } else {
324 if (r_shift < 0) {
325 p = (r >> (-r_shift)) & r_mask;
326 } else {
327 p |= (r & r_mask);
328 }
329 }
330
331 if (g_shift > 0) {
332 p |= (g << (g_shift)) & g_mask;
333 } else {
334 if (g_shift < 0) {
335 p |= (g >> (-g_shift)) & g_mask;
336 } else {
337 p |= (g & g_mask);
338 }
339 }
340
341 if (b_shift > 0) {
342 p |= (b << (b_shift)) & b_mask;
343 } else {
344 if (b_shift < 0) {
345 p |= (b >> (-b_shift)) & b_mask;
346 } else {
347 p |= (b & b_mask);
348 }
349 }
350
351 return p;
352 }
353
354 static void
st2_fixup(XImage * framebuf,int x,int y,int width,int height)355 st2_fixup (XImage *framebuf, int x, int y, int width, int height)
356 {
357 int xi, yi;
358 unsigned char *src;
359 PIXEL16 *dest;
360
361 if (x < 0 || y < 0)
362 return;
363
364 for (yi = y; yi < (y + height); yi++) {
365 src = &((byte *)viddef.buffer)[yi * viddef.width];
366 dest = (PIXEL16 *) &framebuf->data[yi * framebuf->bytes_per_line];
367 for (xi = x; xi < x + width; xi++) {
368 dest[xi] = st2d_8to16table[src[xi]];
369 }
370 }
371 }
372
373 static void
st3_fixup(XImage * framebuf,int x,int y,int width,int height)374 st3_fixup (XImage * framebuf, int x, int y, int width, int height)
375 {
376 int yi;
377 unsigned char *src;
378 PIXEL24 *dest;
379 register int count, n;
380
381 if (x < 0 || y < 0)
382 return;
383
384 for (yi = y; yi < (y + height); yi++) {
385 src = &((byte *)viddef.buffer)[yi * viddef.width + x];
386 dest = (PIXEL24 *) &framebuf->data[yi * framebuf->bytes_per_line + x];
387
388 // Duff's Device
389 count = width;
390 n = (count + 7) / 8;
391
392 switch (count % 8) {
393 case 0:
394 do {
395 *dest++ = st2d_8to24table[*src++];
396 case 7:
397 *dest++ = st2d_8to24table[*src++];
398 case 6:
399 *dest++ = st2d_8to24table[*src++];
400 case 5:
401 *dest++ = st2d_8to24table[*src++];
402 case 4:
403 *dest++ = st2d_8to24table[*src++];
404 case 3:
405 *dest++ = st2d_8to24table[*src++];
406 case 2:
407 *dest++ = st2d_8to24table[*src++];
408 case 1:
409 *dest++ = st2d_8to24table[*src++];
410 } while (--n > 0);
411 }
412 }
413 }
414
415 void
D_BeginDirectRect(int x,int y,byte * pbitmap,int width,int height)416 D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height)
417 {
418 // direct drawing of the "accessing disk" icon isn't supported
419 }
420
421 void
D_EndDirectRect(int x,int y,int width,int height)422 D_EndDirectRect (int x, int y, int width, int height)
423 {
424 // direct drawing of the "accessing disk" icon isn't supported
425 }
426
427 static void
ResetFrameBuffer(void)428 ResetFrameBuffer (void)
429 {
430 int mem, pwidth;
431 char *buf;
432
433 if (x_framebuffer[0]) {
434 XDestroyImage (x_framebuffer[0]);
435 }
436
437 pwidth = x_visinfo->depth / 8;
438
439 if (pwidth == 3)
440 pwidth = 4;
441 mem = ((viddef.width * pwidth + 7) & ~7) * viddef.height;
442 buf = malloc (mem);
443 SYS_CHECKMEM (buf);
444
445 // allocate new screen buffer
446 x_framebuffer[0] = XCreateImage (x_disp, x_vis, x_visinfo->depth,
447 ZPixmap, 0, buf, viddef.width,
448 viddef.height, 32, 0);
449
450 if (!x_framebuffer[0]) {
451 Sys_Error ("VID: XCreateImage failed");
452 }
453 }
454
455 static void
ResetSharedFrameBuffers(void)456 ResetSharedFrameBuffers (void)
457 {
458 int size;
459 int key;
460 int minsize = getpagesize ();
461 int frm;
462
463 for (frm = 0; frm < 2; frm++) {
464
465 // free up old frame buffer memory
466 if (x_framebuffer[frm]) {
467 XShmDetach (x_disp, &x_shminfo[frm]);
468 free (x_framebuffer[frm]);
469 shmdt (x_shminfo[frm].shmaddr);
470 }
471 // create the image
472 x_framebuffer[frm] = XShmCreateImage (x_disp, x_vis, x_visinfo->depth,
473 ZPixmap, 0, &x_shminfo[frm],
474 viddef.width, viddef.height);
475
476 // grab shared memory
477 size = x_framebuffer[frm]->bytes_per_line * x_framebuffer[frm]->height;
478
479 if (size < minsize)
480 Sys_Error ("VID: Window must use at least %d bytes", minsize);
481
482 key = random ();
483 x_shminfo[frm].shmid = shmget ((key_t) key, size, IPC_CREAT | 0777);
484 if (x_shminfo[frm].shmid == -1)
485 Sys_Error ("VID: Could not get any shared memory (%s)",
486 strerror (errno));
487
488 // attach to the shared memory segment
489 x_shminfo[frm].shmaddr = (void *) shmat (x_shminfo[frm].shmid, 0, 0);
490
491 Sys_MaskPrintf (SYS_VID, "VID: shared memory id=%d, addr=0x%lx\n",
492 x_shminfo[frm].shmid, (long) x_shminfo[frm].shmaddr);
493
494 x_framebuffer[frm]->data = x_shminfo[frm].shmaddr;
495
496 // get the X server to attach to it
497 if (!XShmAttach (x_disp, &x_shminfo[frm]))
498 Sys_Error ("VID: XShmAttach() failed");
499 XSync (x_disp, 0);
500 shmctl (x_shminfo[frm].shmid, IPC_RMID, 0);
501
502 }
503 }
504
505 static void
x11_init_buffers(void)506 x11_init_buffers (void)
507 {
508 if (doShm)
509 ResetSharedFrameBuffers ();
510 else
511 ResetFrameBuffer ();
512
513 current_framebuffer = 0;
514
515 viddef.direct = 0;
516 viddef.rowbytes = viddef.width;
517 if (x_visinfo->depth != 8) {
518 if (viddef.buffer)
519 free (viddef.buffer);
520 viddef.buffer = calloc (viddef.width, viddef.height);
521 if (!viddef.buffer)
522 Sys_Error ("Not enough memory for video mode");
523 } else {
524 viddef.buffer = x_framebuffer[current_framebuffer]->data;
525 }
526 viddef.conbuffer = viddef.buffer;
527
528 viddef.conrowbytes = viddef.rowbytes;
529 }
530
531 static void
x11_choose_visual(void)532 x11_choose_visual (void)
533 {
534 int pnum, i;
535 XVisualInfo template;
536 int num_visuals;
537 int template_mask;
538
539 template_mask = 0;
540
541 // specify a visual id
542 if ((pnum = COM_CheckParm ("-visualid"))) {
543 if (pnum >= com_argc - 1)
544 Sys_Error ("VID: -visualid <id#>");
545 template.visualid = atoi (com_argv[pnum + 1]);
546 template_mask = VisualIDMask;
547 } else { // If not specified, use default
548 // visual
549 template.visualid =
550 XVisualIDFromVisual (XDefaultVisual (x_disp, x_screen));
551 template_mask = VisualIDMask;
552 }
553
554 // pick a visual -- warn if more than one was available
555 x_visinfo = XGetVisualInfo (x_disp, template_mask, &template,
556 &num_visuals);
557
558 if (x_visinfo->depth == 8 && x_visinfo->class == PseudoColor)
559 x_cmap = XCreateColormap (x_disp, x_win, x_vis, AllocAll);
560 x_vis = x_visinfo->visual;
561
562 if (num_visuals > 1) {
563 Sys_MaskPrintf (SYS_VID,
564 "Found more than one visual id at depth %d:\n",
565 template.depth);
566 for (i = 0; i < num_visuals; i++)
567 Sys_MaskPrintf (SYS_VID, " -visualid %d\n",
568 (int) x_visinfo[i].visualid);
569 } else {
570 if (num_visuals == 0) {
571 if (template_mask == VisualIDMask) {
572 Sys_Error ("VID: Bad visual ID %ld", template.visualid);
573 } else {
574 Sys_Error ("VID: No visuals at depth %d", template.depth);
575 }
576 }
577 }
578
579 Sys_MaskPrintf (SYS_VID, "Using visualid %d:\n",
580 (int) x_visinfo->visualid);
581 Sys_MaskPrintf (SYS_VID, " class %d\n", x_visinfo->class);
582 Sys_MaskPrintf (SYS_VID, " screen %d\n", x_visinfo->screen);
583 Sys_MaskPrintf (SYS_VID, " depth %d\n", x_visinfo->depth);
584 Sys_MaskPrintf (SYS_VID, " red_mask 0x%x\n",
585 (int) x_visinfo->red_mask);
586 Sys_MaskPrintf (SYS_VID, " green_mask 0x%x\n",
587 (int) x_visinfo->green_mask);
588 Sys_MaskPrintf (SYS_VID, " blue_mask 0x%x\n",
589 (int) x_visinfo->blue_mask);
590 Sys_MaskPrintf (SYS_VID, " colormap_size %d\n",
591 x_visinfo->colormap_size);
592 Sys_MaskPrintf (SYS_VID, " bits_per_rgb %d\n",
593 x_visinfo->bits_per_rgb);
594 }
595
596 static void
x11_create_context(void)597 x11_create_context (void)
598 {
599 // create the GC
600 {
601 XGCValues xgcvalues;
602 int valuemask = GCGraphicsExposures;
603
604 xgcvalues.graphics_exposures = False;
605 x_gc = XCreateGC (x_disp, x_win, valuemask, &xgcvalues);
606 }
607
608 // even if MITSHM is available, make sure it's a local connection
609 if (XShmQueryExtension (x_disp)) {
610 char *displayname;
611 char *d;
612
613 doShm = true;
614
615 if ((displayname = XDisplayName (NULL))) {
616 if ((d = strchr (displayname, ':')))
617 *d = '\0';
618
619 if (!(!strcasecmp (displayname, "unix") || !*displayname))
620 doShm = false;
621 }
622 }
623
624 if (doShm) {
625 x_shmeventtype = XShmGetEventBase (x_disp) + ShmCompletion;
626 }
627
628 viddef.do_screen_buffer = x11_init_buffers;
629 VID_InitBuffers ();
630
631 // XSynchronize (x_disp, False);
632 // X11_AddEvent (x_shmeventtype, event_shm);
633 }
634
635 static void
VID_SetPalette(const byte * palette)636 VID_SetPalette (const byte *palette)
637 {
638 int i;
639 XColor colors[256];
640
641 for (i = 0; i < 256; i++) {
642 st2d_8to16table[i] = xlib_rgb16 (palette[i * 3], palette[i * 3 + 1],
643 palette[i * 3 + 2]);
644 st2d_8to24table[i] = xlib_rgb24 (palette[i * 3], palette[i * 3 + 1],
645 palette[i * 3 + 2]);
646 }
647
648 if (x_visinfo->class == PseudoColor && x_visinfo->depth == 8) {
649 if (palette != current_palette) {
650 memcpy (current_palette, palette, 768);
651 }
652 for (i = 0; i < 256; i++) {
653 colors[i].pixel = i;
654 colors[i].flags = DoRed | DoGreen | DoBlue;
655 colors[i].red = palette[(i * 3)] << 8;
656 colors[i].green = palette[(i * 3) + 1] << 8;
657 colors[i].blue = palette[(i * 3) + 2] << 8;
658 }
659 XStoreColors (x_disp, x_cmap, colors, 256);
660 }
661 }
662
663 /*
664 Set up color translation tables and the window. Takes a 256-color 8-bit
665 palette. Palette data will go away after the call, so copy it if you'll
666 need it later.
667 */
668 void
VID_Init(byte * palette,byte * colormap)669 VID_Init (byte *palette, byte *colormap)
670 {
671 choose_visual = x11_choose_visual;
672 create_context = x11_create_context;
673
674 R_LoadModule (glx_load_gl, VID_SetPalette);
675
676 viddef.numpages = 2;
677 viddef.colormap8 = colormap;
678 viddef.fullbright = 256 - viddef.colormap8[256 * VID_GRADES];
679
680 srandom (getpid ());
681
682 VID_GetWindowSize (320, 200);
683 X11_OpenDisplay ();
684 choose_visual ();
685 X11_SetVidMode (viddef.width, viddef.height);
686 X11_CreateWindow (viddef.width, viddef.height);
687 X11_CreateNullCursor (); // hide mouse pointer
688 create_context ();
689
690 VID_InitGamma (palette);
691 viddef.set_palette (viddef.palette);
692
693 Sys_MaskPrintf (SYS_VID, "Video mode %dx%d initialized.\n",
694 viddef.width, viddef.height);
695
696 viddef.initialized = true;
697 viddef.recalc_refdef = 1; // force a surface cache flush
698 }
699
700 void
VID_Init_Cvars()701 VID_Init_Cvars ()
702 {
703 X11_Init_Cvars ();
704 gl_driver = Cvar_Get ("gl_driver", GL_DRIVER, CVAR_ROM, NULL,
705 "The OpenGL library to use. (path optional)");
706 }
707
708 /*
709 VID_Shutdown
710
711 Restore video mode
712 */
713 void
VID_Shutdown(void)714 VID_Shutdown (void)
715 {
716 Sys_MaskPrintf (SYS_VID, "VID_Shutdown\n");
717 X11_CloseDisplay ();
718 }
719
720 static int config_notify = 0;
721 static int config_notify_width;
722 static int config_notify_height;
723
724 /*
725 VID_Update
726
727 Flush the given rectangles from the view buffer to the screen.
728 */
729 void
VID_Update(vrect_t * rects)730 VID_Update (vrect_t *rects)
731 {
732 /* If the window changes dimension, skip this frame. */
733 if (config_notify) {
734 fprintf (stderr, "config notify\n");
735 config_notify = 0;
736 viddef.width = config_notify_width & ~7;
737 viddef.height = config_notify_height;
738
739 VID_InitBuffers ();
740
741 viddef.recalc_refdef = 1; /* force a surface cache flush */
742 Con_CheckResize ();
743 return;
744 }
745
746 while (rects) {
747 switch (x_visinfo->depth) {
748 case 16:
749 st2_fixup (x_framebuffer[current_framebuffer],
750 rects->x, rects->y, rects->width, rects->height);
751 break;
752 case 24:
753 st3_fixup (x_framebuffer[current_framebuffer],
754 rects->x, rects->y, rects->width, rects->height);
755 break;
756 }
757 if (doShm) {
758 if (!XShmPutImage (x_disp, x_win, x_gc,
759 x_framebuffer[current_framebuffer],
760 rects->x, rects->y, rects->x, rects->y,
761 rects->width, rects->height, True)) {
762 Sys_Error ("VID_Update: XShmPutImage failed");
763 }
764 oktodraw = false;
765 while (!oktodraw)
766 X11_ProcessEvent ();
767 rects = rects->next;
768
769 current_framebuffer = !current_framebuffer;
770 } else {
771 if (XPutImage (x_disp, x_win, x_gc, x_framebuffer[0],
772 rects->x, rects->y, rects->x, rects->y,
773 rects->width, rects->height)) {
774 Sys_Error ("VID_Update: XPutImage failed");
775 }
776 rects = rects->next;
777 }
778 }
779 XSync (x_disp, False);
780 r_data->scr_fullupdate = 0;
781 }
782
783 void
VID_LockBuffer(void)784 VID_LockBuffer (void)
785 {
786 }
787
788 void
VID_UnlockBuffer(void)789 VID_UnlockBuffer (void)
790 {
791 }
792
793 void
VID_SetCaption(const char * text)794 VID_SetCaption (const char *text)
795 {
796 if (text && *text) {
797 char *temp = strdup (text);
798
799 X11_SetCaption (va ("%s: %s", PACKAGE_STRING, temp));
800 free (temp);
801 } else {
802 X11_SetCaption (va ("%s", PACKAGE_STRING));
803 }
804 }
805
806 qboolean
VID_SetGamma(double gamma)807 VID_SetGamma (double gamma)
808 {
809 return X11_SetGamma (gamma);
810 }
811