1 diff -ru a/unix/unix_glw.c b/unix/unix_glw.c
2 --- a/unix/unix_glw.c 2011-04-29 14:42:24.000000000 +0200
3 +++ b/unix/unix_glw.c 2011-10-03 22:11:02.000000000 +0200
6 - Copyright (C) 1997-2001 Id Software, Inc.
8 - This program is free software; you can redistribute it and/or
9 - modify it under the terms of the GNU General Public License
10 - as published by the Free Software Foundation; either version 2
11 - of the License, or (at your option) any later version.
13 - This program is distributed in the hope that it will be useful,
14 - but WITHOUT ANY WARRANTY; without even the implied warranty of
15 - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 - See the GNU General Public License for more details.
19 - You should have received a copy of the GNU General Public License
20 - along with this program; if not, write to the Free Software
21 - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 -** This file contains ALL Linux specific stuff having to do with the
28 -** OpenGL refresh. When a port is being made the following functions
29 -** must be implemented by the port:
34 -** GLimp_SwitchFullscreen
39 -#include <sys/ioctl.h>
40 -#include <sys/stat.h>
47 -#include "../ref_gl/r_local.h"
48 -#include "../client/keys.h"
52 -#include "unix_glw.h"
54 -#define DISPLAY_MASK ( VisibilityChangeMask | StructureNotifyMask | ExposureMask | PropertyChangeMask )
55 -#define INIT_MASK ( KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | FocusChangeMask | DISPLAY_MASK )
57 -x11display_t x11display;
59 -glwstate_t glw_state;
61 -static qboolean _xf86_vidmodes_supported = qfalse;
62 -static int default_dotclock, default_viewport[2];
63 -static XF86VidModeModeLine default_modeline;
64 -static XF86VidModeModeInfo **_xf86_vidmodes;
65 -static int _xf86_vidmodes_num;
66 -static qboolean _xf86_vidmodes_active = qfalse;
67 -static qboolean _xf86_xinerama_supported = qfalse;
69 -static void _xf86_VidmodesInit( void )
71 - int MajorVersion = 0, MinorVersion = 0;
73 - // Get video mode list
74 - if( XF86VidModeQueryVersion( x11display.dpy, &MajorVersion, &MinorVersion ) )
76 - Com_Printf( "..XFree86-VidMode Extension Version %d.%d\n", MajorVersion, MinorVersion );
77 - XF86VidModeGetViewPort( x11display.dpy, x11display.scr, &default_viewport[0], &default_viewport[1] );
78 - XF86VidModeGetModeLine( x11display.dpy, x11display.scr, &default_dotclock, &default_modeline );
79 - XF86VidModeGetAllModeLines( x11display.dpy, x11display.scr, &_xf86_vidmodes_num, &_xf86_vidmodes );
80 - _xf86_vidmodes_supported = qtrue;
84 - Com_Printf( "..XFree86-VidMode Extension not available\n" );
85 - _xf86_vidmodes_supported = qfalse;
89 -static void _xf86_VidmodesFree( void )
91 - if( _xf86_vidmodes_supported ) XFree( _xf86_vidmodes );
93 - _xf86_vidmodes_supported = qfalse;
96 -static void _xf86_XineramaInit( void )
98 - int MajorVersion = 0, MinorVersion = 0;
100 - if( ( XineramaQueryVersion( x11display.dpy, &MajorVersion, &MinorVersion ) ) && ( XineramaIsActive( x11display.dpy ) ) )
102 - Com_Printf( "..XFree86-Xinerama Extension Version %d.%d\n", MajorVersion, MinorVersion );
103 - _xf86_xinerama_supported = qtrue;
107 - Com_Printf( "..XFree86-Xinerama Extension not available\n" );
108 - _xf86_xinerama_supported = qfalse;
112 -static void _xf86_XineramaFree( void )
114 - _xf86_xinerama_supported = qfalse;
117 -static qboolean _xf86_XineramaFindBest( int *x, int *y, int *width, int *height, qboolean silent )
119 - int i, screens, head;
120 - int best_dist, dist;
121 - XineramaScreenInfo *xinerama;
123 - assert( _xf86_xinerama_supported );
125 - if( vid_multiscreen_head->integer == 0 )
128 - xinerama = XineramaQueryScreens( x11display.dpy, &screens );
133 - if( vid_multiscreen_head->integer > 0 )
135 - for( i = 0; i < screens; i++ )
137 - if( xinerama[i].screen_number == vid_multiscreen_head->integer - 1 )
143 - if( head == -1 && !silent )
144 - Com_Printf( "Xinerama: Head %i not found, using best fit\n", vid_multiscreen_head->integer );
145 - if( *width > xinerama[head].width || *height > xinerama[head].height )
149 - Com_Printf( "Xinerama: Window doesn't fit into head %i, using best fit\n", vid_multiscreen_head->integer );
153 - if( head == -1 ) // find best fit
155 - best_dist = 999999999;
156 - for( i = 0; i < screens; i++ )
158 - if( *width <= xinerama[i].width && *height <= xinerama[i].height )
160 - if( xinerama[i].width - *width > xinerama[i].height - *height )
162 - dist = xinerama[i].height - *height;
166 - dist = xinerama[i].width - *width;
170 - dist = -dist; // Only positive number please
172 - if( dist < best_dist )
182 - Com_Printf( "Xinerama: No fitting head found" );
187 - *x = xinerama[head].x_org;
188 - *y = xinerama[head].y_org;
189 - *width = xinerama[head].width;
190 - *height = xinerama[head].height;
193 - Com_Printf( "Xinerama: Using screen %d: %dx%d+%d+%d\n", xinerama[head].screen_number, xinerama[head].width, xinerama[head].height, xinerama[head].x_org, xinerama[head].y_org );
198 -static void _xf86_VidmodesSwitch( int mode )
200 - if( _xf86_vidmodes_supported )
202 - XF86VidModeSwitchToMode( x11display.dpy, x11display.scr, _xf86_vidmodes[mode] );
203 - XF86VidModeSetViewPort( x11display.dpy, x11display.scr, 0, 0 );
206 - _xf86_vidmodes_active = qtrue;
209 -static void _xf86_VidmodesSwitchBack( void )
211 - if( _xf86_vidmodes_supported && _xf86_vidmodes_active )
213 - XF86VidModeModeInfo modeinfo;
215 - modeinfo.dotclock = default_dotclock;
216 - modeinfo.hdisplay = default_modeline.hdisplay;
217 - modeinfo.hsyncstart = default_modeline.hsyncstart;
218 - modeinfo.hsyncend = default_modeline.hsyncend;
219 - modeinfo.htotal = default_modeline.htotal;
220 - modeinfo.vdisplay = default_modeline.vdisplay;
221 - modeinfo.vsyncstart = default_modeline.vsyncstart;
222 - modeinfo.vsyncend = default_modeline.vsyncend;
223 - modeinfo.vtotal = default_modeline.vtotal;
224 - modeinfo.flags = default_modeline.flags;
225 - modeinfo.privsize = default_modeline.privsize;
226 - modeinfo.private = default_modeline.private;
228 - XF86VidModeSwitchToMode( x11display.dpy, x11display.scr, &modeinfo );
229 - XF86VidModeSetViewPort( x11display.dpy, x11display.scr, default_viewport[0], default_viewport[1] );
232 - _xf86_vidmodes_active = qfalse;
235 -static void _xf86_VidmodesFindBest( int *mode, int *pwidth, int *pheight, qboolean silent )
237 - int i, best_fit, best_dist, dist, x, y;
240 - best_dist = 999999999;
242 - if( _xf86_vidmodes_supported )
244 - for( i = 0; i < _xf86_vidmodes_num; i++ )
246 - if( _xf86_vidmodes[i]->hdisplay < *pwidth || _xf86_vidmodes[i]->vdisplay < *pheight )
249 - x = _xf86_vidmodes[i]->hdisplay - *pwidth;
250 - y = _xf86_vidmodes[i]->vdisplay - *pheight;
252 - if( x > y ) dist = y;
255 - if( dist < 0 ) dist = -dist; // Only positive number please
257 - if( dist < best_dist )
264 - Com_Printf( "%ix%i -> %ix%i: %i\n", *pwidth, *pheight, _xf86_vidmodes[i]->hdisplay, _xf86_vidmodes[i]->vdisplay, dist );
267 - if( best_fit >= 0 )
270 - Com_Printf( "%ix%i selected\n", _xf86_vidmodes[best_fit]->hdisplay, _xf86_vidmodes[best_fit]->vdisplay );
272 - *pwidth = _xf86_vidmodes[best_fit]->hdisplay;
273 - *pheight = _xf86_vidmodes[best_fit]->vdisplay;
280 -static void _x11_SetNoResize( Window w, int width, int height )
284 - if( x11display.dpy )
286 - hints = XAllocSizeHints();
290 - hints->min_width = hints->max_width = width;
291 - hints->min_height = hints->max_height = height;
293 - hints->flags = PMaxSize | PMinSize;
295 - XSetWMNormalHints( x11display.dpy, w, hints );
301 -/*****************************************************************************/
305 - Sys_GetClipboardData
307 - Orginally from EzQuake
308 - There should be a smarter place to put this
311 -char *Sys_GetClipboardData( qboolean primary )
316 - unsigned long nitems, bytes_after, bytes_left;
317 - unsigned char *data;
321 - if( !x11display.dpy )
326 - atom = XInternAtom( x11display.dpy, "PRIMARY", True );
330 - atom = XInternAtom( x11display.dpy, "CLIPBOARD", True );
335 - win = XGetSelectionOwner( x11display.dpy, atom );
339 - XConvertSelection( x11display.dpy, atom, XA_STRING, atom, win, CurrentTime );
340 - XFlush( x11display.dpy );
342 - XGetWindowProperty( x11display.dpy, win, atom, 0, 0, False, AnyPropertyType, &type, &format, &nitems, &bytes_left,
344 - if( bytes_left <= 0 )
347 - ret = XGetWindowProperty( x11display.dpy, win, atom, 0, bytes_left, False, AnyPropertyType, &type,
348 - &format, &nitems, &bytes_after, &data );
349 - if( ret == Success )
351 - buffer = Q_malloc( bytes_left + 1 );
352 - Q_strncpyz( buffer, (char *)data, bytes_left + 1 );
366 -* Sys_SetClipboardData
368 -qboolean Sys_SetClipboardData( char *data )
375 - Sys_FreeClipboardData
378 -void Sys_FreeClipboardData( char *data )
384 -* _NET_WM_CHECK_SUPPORTED
386 -static qboolean _NET_WM_CHECK_SUPPORTED( Atom NET_ATOM )
388 - qboolean issupported = qfalse;
389 - unsigned char *atomdata;
391 - int status, real_format;
393 - unsigned long items_read, items_left, i;
395 - Atom _NET_SUPPORTED;
397 - _NET_SUPPORTED = XInternAtom( x11display.dpy, "_NET_SUPPORTED", 0 );
399 - status = XGetWindowProperty( x11display.dpy, x11display.root, _NET_SUPPORTED,
400 - 0L, 8192L, False, XA_ATOM, &real_type, &real_format,
401 - &items_read, &items_left, &atomdata );
403 - if( status != Success )
406 - atoms = (Atom *)atomdata;
407 - for( i = 0; result && i < items_read; i++ )
409 - if( atoms[i] == NET_ATOM )
411 - issupported = qtrue;
417 - return issupported;
421 -* _NET_WM_STATE_FULLSCREEN_SUPPORTED
423 -static qboolean _NET_WM_STATE_FULLSCREEN_SUPPORTED( void )
425 - Atom _NET_WM_STATE_FULLSCREEN = XInternAtom( x11display.dpy, "_NET_WM_STATE_FULLSCREEN", 0 );
426 - return _NET_WM_CHECK_SUPPORTED( _NET_WM_STATE_FULLSCREEN );
431 -* _NETWM_CHECK_FULLSCREEN
433 -qboolean _NETWM_CHECK_FULLSCREEN( void )
435 - qboolean isfullscreen = qfalse;
436 - unsigned char *atomdata;
438 - int status, real_format;
440 - unsigned long items_read, items_left, i;
442 - Atom _NET_WM_STATE;
443 - Atom _NET_WM_STATE_FULLSCREEN;
445 - if( !x11display.features.wmStateFullscreen )
448 - _NET_WM_STATE = XInternAtom( x11display.dpy, "_NET_WM_STATE", 0 );
449 - _NET_WM_STATE_FULLSCREEN = XInternAtom( x11display.dpy, "_NET_WM_STATE_FULLSCREEN", 0 );
451 - status = XGetWindowProperty( x11display.dpy, x11display.win, _NET_WM_STATE,
452 - 0L, 8192L, False, XA_ATOM, &real_type, &real_format,
453 - &items_read, &items_left, &atomdata );
455 - if( status != Success )
458 - atoms = (Atom *)atomdata;
459 - for( i = 0; result && i < items_read; i++ )
461 - if( atoms[i] == _NET_WM_STATE_FULLSCREEN )
463 - isfullscreen = qtrue;
470 - Cvar_SetValue( "vid_fullscreen", 1 );
471 - vid_fullscreen->modified = qfalse;
475 - Cvar_SetValue( "vid_fullscreen", 0 );
476 - vid_fullscreen->modified = qfalse;
480 - return isfullscreen;
484 -* _NETWM_SET_FULLSCREEN
486 -* Tell Window-Manager to toggle fullscreen
488 -void _NETWM_SET_FULLSCREEN( qboolean fullscreen )
492 - Atom wm_fullscreen;
494 - if( !x11display.features.wmStateFullscreen )
497 - wm_state = XInternAtom( x11display.dpy, "_NET_WM_STATE", False );
498 - wm_fullscreen = XInternAtom( x11display.dpy, "_NET_WM_STATE_FULLSCREEN", False );
500 - memset(&xev, 0, sizeof(xev));
501 - xev.type = ClientMessage;
502 - xev.xclient.window = x11display.win;
503 - xev.xclient.message_type = wm_state;
504 - xev.xclient.format = 32;
505 - xev.xclient.data.l[0] = fullscreen ? 1 : 0;
506 - xev.xclient.data.l[1] = wm_fullscreen;
507 - xev.xclient.data.l[2] = 0;
509 - XSendEvent( x11display.dpy, DefaultRootWindow( x11display.dpy ), False,
510 - SubstructureNotifyMask, &xev );
513 -/*****************************************************************************/
515 -static void GLimp_SetXPMIcon( const int *xpm_icon )
518 - size_t i, cardinalSize;
519 - long *cardinalData;
523 - // allocate memory for icon data: width + height + width * height pixels
524 - // note: sizeof(long) shall be used according to XChangeProperty() man page
525 - width = xpm_icon[0];
526 - height = xpm_icon[1];
527 - cardinalSize = width * height + 2;
528 - cardinalData = Q_malloc( cardinalSize * sizeof( *cardinalData ) );
529 - for( i = 0; i < cardinalSize; i++ )
530 - cardinalData[i] = xpm_icon[i];
532 - NET_WM_ICON = XInternAtom( x11display.dpy, "_NET_WM_ICON", False );
533 - CARDINAL = XInternAtom( x11display.dpy, "CARDINAL", False );
535 - XChangeProperty( x11display.dpy, x11display.win, NET_WM_ICON, CARDINAL, 32,
536 - PropModeReplace, (unsigned char *)cardinalData, cardinalSize );
538 - Q_free( cardinalData );
541 -int *parse_xpm_icon ( int num_xpm_elements, char *xpm_data[] );
543 -static void GLimp_SetApplicationIcon( void )
545 - #include "warsow128x128.xpm"
547 - const int *xpm_icon;
549 - xpm_icon = parse_xpm_icon( sizeof( warsow128x128_xpm ) / sizeof( warsow128x128_xpm[0] ), warsow128x128_xpm );
552 - GLimp_SetXPMIcon( xpm_icon );
553 - free( ( void * )xpm_icon );
557 -/*****************************************************************************/
560 -** GLimp_SetMode_Real
561 -* Hack to get rid of the prints when toggling fullscreen
563 -int GLimp_SetMode_Real( int mode, qboolean fullscreen, qboolean silent )
565 - int width, height, screen_x, screen_y, screen_width, screen_height, screen_mode;
567 - XSetWindowAttributes wa;
568 - unsigned long mask;
569 - qboolean wideScreen;
571 - if( !VID_GetModeInfo( &width, &height, &wideScreen, mode ) )
574 - Com_Printf( " invalid mode\n" );
575 - return rserr_invalid_mode;
579 - screen_x = screen_y = 0;
580 - screen_width = width;
581 - screen_height = height;
583 - x11display.old_win = x11display.win;
587 - if( !_xf86_xinerama_supported ||
588 - !_xf86_XineramaFindBest( &screen_x, &screen_y, &screen_width, &screen_height, silent ) )
590 - _xf86_VidmodesFindBest( &screen_mode, &screen_width, &screen_height, silent );
591 - if( screen_mode < 0 )
594 - Com_Printf( " no mode found\n" );
595 - return rserr_invalid_mode;
599 - if( screen_width < width || screen_height < height )
601 - if( width > height )
603 - ratio = width / height;
604 - height = height * ratio;
605 - width = screen_width;
609 - ratio = height / width;
610 - width = width * ratio;
611 - height = screen_height;
616 - Com_Printf( "...setting fullscreen mode %d:\n", mode );
618 - /* Create fulscreen window */
619 - wa.background_pixel = 0;
620 - wa.border_pixel = 0;
621 - wa.event_mask = INIT_MASK;
622 - wa.backing_store = NotUseful;
623 - wa.save_under = False;
625 - if( x11display.features.wmStateFullscreen )
627 - wa.override_redirect = False;
628 - mask = CWBackPixel | CWBorderPixel | CWEventMask | CWSaveUnder | CWBackingStore;
632 - wa.override_redirect = True;
633 - mask = CWBackPixel | CWBorderPixel | CWEventMask | CWSaveUnder | CWBackingStore | CWOverrideRedirect;
636 - x11display.win = XCreateWindow( x11display.dpy, x11display.root, screen_x, screen_y, screen_width, screen_height,
637 - 0, CopyFromParent, InputOutput, CopyFromParent, mask, &wa );
639 - XResizeWindow( x11display.dpy, x11display.gl_win, width, height );
640 - XReparentWindow( x11display.dpy, x11display.gl_win, x11display.win, ( screen_width/2 )-( width/2 ),
641 - ( screen_height/2 )-( height/2 ) );
643 - x11display.modeset = qtrue;
645 - XMapWindow( x11display.dpy, x11display.gl_win );
646 - XMapWindow( x11display.dpy, x11display.win );
648 - if ( !x11display.features.wmStateFullscreen )
649 - _x11_SetNoResize( x11display.win, width, height );
651 - _NETWM_SET_FULLSCREEN( qtrue );
653 - if( screen_mode != -1 )
654 - _xf86_VidmodesSwitch( screen_mode );
659 - Com_Printf( "...setting mode %d:\n", mode );
661 - /* Create managed window */
662 - wa.background_pixel = 0;
663 - wa.border_pixel = 0;
664 - wa.event_mask = INIT_MASK;
665 - mask = CWBackPixel | CWBorderPixel | CWEventMask;
667 - x11display.win = XCreateWindow( x11display.dpy, x11display.root, 0, 0, screen_width, screen_height,
668 - 0, CopyFromParent, InputOutput, CopyFromParent, mask, &wa );
669 - x11display.wmDeleteWindow = XInternAtom( x11display.dpy, "WM_DELETE_WINDOW", False );
670 - XSetWMProtocols( x11display.dpy, x11display.win, &x11display.wmDeleteWindow, 1 );
672 - XResizeWindow( x11display.dpy, x11display.gl_win, width, height );
673 - XReparentWindow( x11display.dpy, x11display.gl_win, x11display.win, 0, 0 );
675 - x11display.modeset = qtrue;
677 - XMapWindow( x11display.dpy, x11display.gl_win );
678 - XMapWindow( x11display.dpy, x11display.win );
680 - if( !x11display.features.wmStateFullscreen )
681 - _x11_SetNoResize( x11display.win, width, height );
683 - _xf86_VidmodesSwitchBack();
686 - XSetStandardProperties( x11display.dpy, x11display.win, APPLICATION, None, None, NULL, 0, NULL );
688 - GLimp_SetApplicationIcon();
690 - XSetIconName( x11display.dpy, x11display.win, APPLICATION );
691 - XStoreName( x11display.dpy, x11display.win, APPLICATION );
693 - // save the parent window size for mouse use. this is not the gl context window
694 - x11display.win_width = width;
695 - x11display.win_height = height;
697 - if( x11display.old_win )
699 - XDestroyWindow( x11display.dpy, x11display.old_win );
700 - x11display.old_win = 0;
703 - XFlush( x11display.dpy );
705 - glState.width = width;
706 - glState.height = height;
707 - glState.fullScreen = fullscreen;
708 - glState.wideScreen = wideScreen;
710 - // let the sound and input subsystems know about the new window
711 - VID_NewWindow( width, height );
719 -int GLimp_SetMode( int mode, qboolean fullscreen )
721 - return GLimp_SetMode_Real( mode, fullscreen, qfalse );
725 -** GLimp_GetCurrentMode
727 -int GLimp_GetCurrentMode( void )
729 - if( x11display.dpy )
733 - width = DisplayWidth( x11display.dpy, x11display.scr );
734 - height = DisplayHeight( x11display.dpy, x11display.scr );
735 - return VID_GetModeNum( width, height );
744 -void GLimp_Shutdown( void )
746 - if( x11display.dpy )
748 - _xf86_VidmodesSwitchBack();
749 - _xf86_VidmodesFree();
750 - _xf86_XineramaFree();
752 - if( x11display.cmap ) XFreeColormap( x11display.dpy, x11display.cmap );
753 - if( x11display.ctx ) qglXDestroyContext( x11display.dpy, x11display.ctx );
754 - if( x11display.gl_win ) XDestroyWindow( x11display.dpy, x11display.gl_win );
755 - if( x11display.win ) XDestroyWindow( x11display.dpy, x11display.win );
757 - XCloseDisplay( x11display.dpy );
760 - memset(&x11display.features, 0, sizeof(x11display.features));
761 - x11display.modeset = qfalse;
762 - x11display.visinfo = NULL;
763 - x11display.cmap = 0;
764 - x11display.ctx = NULL;
765 - x11display.gl_win = 0;
766 - x11display.win = 0;
767 - x11display.dpy = NULL;
770 -static qboolean gotstencil = qfalse; // evil hack!
771 -static qboolean ChooseVisual( int colorbits, int stencilbits )
774 - int depthbits = colorbits;
776 - if( colorbits == 24 ) colorsize = 8;
777 - else colorsize = 4;
780 - int attributes[] = {
783 - GLX_RED_SIZE, colorsize,
784 - GLX_GREEN_SIZE, colorsize,
785 - GLX_BLUE_SIZE, colorsize,
786 - GLX_DEPTH_SIZE, depthbits,
787 - GLX_STENCIL_SIZE, stencilbits,
791 - x11display.visinfo = qglXChooseVisual( x11display.dpy, x11display.scr, attributes );
792 - if( !x11display.visinfo )
794 - Com_Printf( "..Failed to get colorbits %i, depthbits %i, stencilbits %i\n", colorbits, depthbits, stencilbits );
799 - Com_Printf( "..Got colorbits %i, depthbits %i, stencilbits %i\n", colorbits, depthbits, stencilbits );
800 - if( stencilbits > 0 ) gotstencil = qtrue;
809 -int GLimp_Init( void *hinstance, void *wndproc, void *parenthWnd )
811 - int colorbits, stencilbits;
812 - XSetWindowAttributes attr;
813 - unsigned long mask;
818 - // on unix we can change to fullscreen on fly
819 - vid_fullscreen->flags &= ~( CVAR_LATCH_VIDEO );
821 - if( x11display.dpy )
824 - Com_Printf( "Display initialization\n" );
826 - x11display.dpy = XOpenDisplay( NULL );
827 - if( !x11display.dpy )
829 - Com_Printf( "..Error couldn't open the X display\n" );
833 - x11display.scr = DefaultScreen( x11display.dpy );
835 - x11display.root = (Window )parenthWnd;
837 - x11display.root = RootWindow( x11display.dpy, x11display.scr );
839 - x11display.wmState = XInternAtom( x11display.dpy, "WM_STATE", False );
840 - x11display.features.wmStateFullscreen = _NET_WM_STATE_FULLSCREEN_SUPPORTED();
842 - _xf86_VidmodesInit();
843 - _xf86_XineramaInit();
845 - if( r_colorbits->integer == 16 || r_colorbits->integer == 24 ) colorbits = r_colorbits->integer;
846 - else colorbits = 0;
848 - if( r_stencilbits->integer == 8 || r_stencilbits->integer == 16 ) stencilbits = r_stencilbits->integer;
849 - else stencilbits = 0;
851 - gotstencil = qfalse;
852 - if( colorbits > 0 )
854 - ChooseVisual( colorbits, stencilbits );
855 - if( !x11display.visinfo && stencilbits > 8 ) ChooseVisual( colorbits, 8 );
856 - if( !x11display.visinfo && stencilbits > 0 ) ChooseVisual( colorbits, 0 );
857 - if( !x11display.visinfo && colorbits > 16 ) ChooseVisual( 16, 0 );
861 - ChooseVisual( 24, stencilbits );
862 - if( !x11display.visinfo ) ChooseVisual( 16, stencilbits );
863 - if( !x11display.visinfo && stencilbits > 8 ) ChooseVisual( 24, 8 );
864 - if( !x11display.visinfo && stencilbits > 8 ) ChooseVisual( 16, 8 );
865 - if( !x11display.visinfo && stencilbits > 0 ) ChooseVisual( 24, 0 );
866 - if( !x11display.visinfo && stencilbits > 0 ) ChooseVisual( 16, 0 );
869 - if( !x11display.visinfo )
871 - GLimp_Shutdown(); // hope this doesn't do anything evil when we don't have window etc.
872 - Com_Printf( "..Error couldn't set GLX visual\n" );
876 - glState.stencilEnabled = gotstencil;
878 - x11display.ctx = qglXCreateContext( x11display.dpy, x11display.visinfo, NULL, True );
879 - x11display.cmap = XCreateColormap( x11display.dpy, x11display.root, x11display.visinfo->visual, AllocNone );
881 - attr.colormap = x11display.cmap;
882 - attr.border_pixel = 0;
883 - attr.event_mask = DISPLAY_MASK;
884 - attr.override_redirect = False;
885 - mask = CWBorderPixel | CWColormap | ExposureMask;
887 - x11display.gl_win = XCreateWindow( x11display.dpy, x11display.root, 0, 0, 1, 1, 0,
888 - x11display.visinfo->depth, InputOutput, x11display.visinfo->visual, mask, &attr );
889 - qglXMakeCurrent( x11display.dpy, x11display.gl_win, x11display.ctx );
891 - XSync( x11display.dpy, False );
899 -void GLimp_BeginFrame( void )
906 -** Responsible for doing a swapbuffers and possibly for other stuff
907 -** as yet to be determined. Probably better not to make this a GLimp
908 -** function and instead do a call to GLimp_SwapBuffers.
910 -void GLimp_EndFrame( void )
912 - qglXSwapBuffers( x11display.dpy, x11display.gl_win );
914 - if( vid_fullscreen->modified || ( vid_fullscreen->integer && vid_multiscreen_head->modified ) )
916 - GLimp_SetMode_Real( r_mode->integer, vid_fullscreen->integer, qtrue );
917 - vid_fullscreen->modified = qfalse;
918 - vid_multiscreen_head->modified = qfalse;
923 -** GLimp_GetGammaRamp
925 -qboolean GLimp_GetGammaRamp( size_t stride, unsigned short *ramp )
927 - if( XF86VidModeGetGammaRamp( x11display.dpy, x11display.scr, stride, ramp, ramp + stride, ramp + ( stride << 1 ) ) != 0 )
933 -** GLimp_SetGammaRamp
935 -void GLimp_SetGammaRamp( size_t stride, unsigned short *ramp )
937 - XF86VidModeSetGammaRamp( x11display.dpy, x11display.scr, stride, ramp, ramp + stride, ramp + ( stride << 1 ) );
941 -** GLimp_AppActivate
943 -void GLimp_AppActivate( qboolean active, qboolean destroy )
947 +Copyright (C) 1997-2001 Id Software, Inc.
949 +This program is free software; you can redistribute it and/or
950 +modify it under the terms of the GNU General Public License
951 +as published by the Free Software Foundation; either version 2
952 +of the License, or (at your option) any later version.
954 +This program is distributed in the hope that it will be useful,
955 +but WITHOUT ANY WARRANTY; without even the implied warranty of
956 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
958 +See the GNU General Public License for more details.
960 +You should have received a copy of the GNU General Public License
961 +along with this program; if not, write to the Free Software
962 +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
968 +** This file contains ALL Linux specific stuff having to do with the
969 +** OpenGL refresh. When a port is being made the following functions
970 +** must be implemented by the port:
975 +** GLimp_SwitchFullscreen
979 +#include <termios.h>
980 +#include <sys/ioctl.h>
981 +#include <sys/stat.h>
988 +#include "../ref_gl/r_local.h"
989 +#include "../client/keys.h"
993 +#include "unix_glw.h"
995 +#define DISPLAY_MASK ( VisibilityChangeMask | StructureNotifyMask | ExposureMask | PropertyChangeMask )
996 +#define INIT_MASK ( KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | FocusChangeMask | DISPLAY_MASK )
999 +x11display_t x11display;
1001 +glwstate_t glw_state;
1003 +static qboolean _xf86_vidmodes_supported = qfalse;
1004 +static int default_dotclock, default_viewport[2];
1005 +static XF86VidModeModeLine default_modeline;
1006 +static XF86VidModeModeInfo **_xf86_vidmodes;
1007 +static int _xf86_vidmodes_num;
1008 +static qboolean _xf86_vidmodes_active = qfalse;
1009 +static qboolean _xf86_xinerama_supported = qfalse;
1011 +static void _xf86_VidmodesInit( void )
1013 + int MajorVersion = 0, MinorVersion = 0;
1015 + // Get video mode list
1016 + if( XF86VidModeQueryVersion( x11display.dpy, &MajorVersion, &MinorVersion ) )
1018 + Com_Printf( "..XFree86-VidMode Extension Version %d.%d\n", MajorVersion, MinorVersion );
1019 + XF86VidModeGetViewPort( x11display.dpy, x11display.scr, &default_viewport[0], &default_viewport[1] );
1020 + XF86VidModeGetModeLine( x11display.dpy, x11display.scr, &default_dotclock, &default_modeline );
1021 + XF86VidModeGetAllModeLines( x11display.dpy, x11display.scr, &_xf86_vidmodes_num, &_xf86_vidmodes );
1022 + _xf86_vidmodes_supported = qtrue;
1026 + Com_Printf( "..XFree86-VidMode Extension not available\n" );
1027 + _xf86_vidmodes_supported = qfalse;
1031 +static void _xf86_VidmodesFree( void )
1033 + if( _xf86_vidmodes_supported ) XFree( _xf86_vidmodes );
1035 + _xf86_vidmodes_supported = qfalse;
1038 +static void _xf86_XineramaInit( void )
1040 + int MajorVersion = 0, MinorVersion = 0;
1042 + if( ( XineramaQueryVersion( x11display.dpy, &MajorVersion, &MinorVersion ) ) && ( XineramaIsActive( x11display.dpy ) ) )
1044 + Com_Printf( "..XFree86-Xinerama Extension Version %d.%d\n", MajorVersion, MinorVersion );
1045 + _xf86_xinerama_supported = qtrue;
1049 + Com_Printf( "..XFree86-Xinerama Extension not available\n" );
1050 + _xf86_xinerama_supported = qfalse;
1054 +static void _xf86_XineramaFree( void )
1056 + _xf86_xinerama_supported = qfalse;
1059 +static qboolean _xf86_XineramaFindBest( int *x, int *y, int *width, int *height, qboolean silent )
1061 + int i, screens, head;
1062 + int best_dist, dist;
1063 + XineramaScreenInfo *xinerama;
1065 + assert( _xf86_xinerama_supported );
1067 + if( vid_multiscreen_head->integer == 0 )
1070 + xinerama = XineramaQueryScreens( x11display.dpy, &screens );
1071 + if( screens <= 1 )
1075 + if( vid_multiscreen_head->integer > 0 )
1077 + for( i = 0; i < screens; i++ )
1079 + if( xinerama[i].screen_number == vid_multiscreen_head->integer - 1 )
1085 + if( head == -1 && !silent )
1086 + Com_Printf( "Xinerama: Head %i not found, using best fit\n", vid_multiscreen_head->integer );
1087 + if( *width > xinerama[head].width || *height > xinerama[head].height )
1091 + Com_Printf( "Xinerama: Window doesn't fit into head %i, using best fit\n", vid_multiscreen_head->integer );
1095 + if( head == -1 ) // find best fit
1097 + best_dist = 999999999;
1098 + for( i = 0; i < screens; i++ )
1100 + if( *width <= xinerama[i].width && *height <= xinerama[i].height )
1102 + if( xinerama[i].width - *width > xinerama[i].height - *height )
1104 + dist = xinerama[i].height - *height;
1108 + dist = xinerama[i].width - *width;
1112 + dist = -dist; // Only positive number please
1114 + if( dist < best_dist )
1124 + Com_Printf( "Xinerama: No fitting head found" );
1129 + *x = xinerama[head].x_org;
1130 + *y = xinerama[head].y_org;
1131 + *width = xinerama[head].width;
1132 + *height = xinerama[head].height;
1135 + Com_Printf( "Xinerama: Using screen %d: %dx%d+%d+%d\n", xinerama[head].screen_number, xinerama[head].width, xinerama[head].height, xinerama[head].x_org, xinerama[head].y_org );
1140 +static void _xf86_VidmodesSwitch( int mode )
1142 + if( _xf86_vidmodes_supported )
1144 + XF86VidModeSwitchToMode( x11display.dpy, x11display.scr, _xf86_vidmodes[mode] );
1145 + XF86VidModeSetViewPort( x11display.dpy, x11display.scr, 0, 0 );
1148 + _xf86_vidmodes_active = qtrue;
1151 +static void _xf86_VidmodesSwitchBack( void )
1153 + if( _xf86_vidmodes_supported && _xf86_vidmodes_active )
1155 + XF86VidModeModeInfo modeinfo;
1157 + modeinfo.dotclock = default_dotclock;
1158 + modeinfo.hdisplay = default_modeline.hdisplay;
1159 + modeinfo.hsyncstart = default_modeline.hsyncstart;
1160 + modeinfo.hsyncend = default_modeline.hsyncend;
1161 + modeinfo.htotal = default_modeline.htotal;
1162 + modeinfo.vdisplay = default_modeline.vdisplay;
1163 + modeinfo.vsyncstart = default_modeline.vsyncstart;
1164 + modeinfo.vsyncend = default_modeline.vsyncend;
1165 + modeinfo.vtotal = default_modeline.vtotal;
1166 + modeinfo.flags = default_modeline.flags;
1167 + modeinfo.privsize = default_modeline.privsize;
1168 + modeinfo.private = default_modeline.private;
1170 + XF86VidModeSwitchToMode( x11display.dpy, x11display.scr, &modeinfo );
1171 + XF86VidModeSetViewPort( x11display.dpy, x11display.scr, default_viewport[0], default_viewport[1] );
1174 + _xf86_vidmodes_active = qfalse;
1177 +static void _xf86_VidmodesFindBest( int *mode, int *pwidth, int *pheight, qboolean silent )
1179 + int i, best_fit, best_dist, dist, x, y;
1182 + best_dist = 999999999;
1184 + if( _xf86_vidmodes_supported )
1186 + for( i = 0; i < _xf86_vidmodes_num; i++ )
1188 + if( _xf86_vidmodes[i]->hdisplay < *pwidth || _xf86_vidmodes[i]->vdisplay < *pheight )
1191 + x = _xf86_vidmodes[i]->hdisplay - *pwidth;
1192 + y = _xf86_vidmodes[i]->vdisplay - *pheight;
1194 + if( x > y ) dist = y;
1197 + if( dist < 0 ) dist = -dist; // Only positive number please
1199 + if( dist < best_dist )
1206 + Com_Printf( "%ix%i -> %ix%i: %i\n", *pwidth, *pheight, _xf86_vidmodes[i]->hdisplay, _xf86_vidmodes[i]->vdisplay, dist );
1209 + if( best_fit >= 0 )
1212 + Com_Printf( "%ix%i selected\n", _xf86_vidmodes[best_fit]->hdisplay, _xf86_vidmodes[best_fit]->vdisplay );
1214 + *pwidth = _xf86_vidmodes[best_fit]->hdisplay;
1215 + *pheight = _xf86_vidmodes[best_fit]->vdisplay;
1222 +static void _x11_SetNoResize( Window w, int width, int height )
1224 + XSizeHints *hints;
1226 + if( x11display.dpy )
1228 + hints = XAllocSizeHints();
1232 + hints->min_width = hints->max_width = width;
1233 + hints->min_height = hints->max_height = height;
1235 + hints->flags = PMaxSize | PMinSize;
1237 + XSetWMNormalHints( x11display.dpy, w, hints );
1243 +/*****************************************************************************/
1246 +* Sys_GetClipboardData
1248 +* Orginally from EzQuake
1249 +* There should be a smarter place to put this
1251 +char *Sys_GetClipboardData( qboolean primary )
1256 + unsigned long nitems, bytes_after, bytes_left;
1257 + unsigned char *data;
1261 + if( !x11display.dpy )
1266 + atom = XInternAtom( x11display.dpy, "PRIMARY", True );
1270 + atom = XInternAtom( x11display.dpy, "CLIPBOARD", True );
1272 + if( atom == None )
1275 + win = XGetSelectionOwner( x11display.dpy, atom );
1279 + XConvertSelection( x11display.dpy, atom, XA_STRING, atom, win, CurrentTime );
1280 + XFlush( x11display.dpy );
1282 + XGetWindowProperty( x11display.dpy, win, atom, 0, 0, False, AnyPropertyType, &type, &format, &nitems, &bytes_left,
1284 + if( bytes_left <= 0 )
1287 + ret = XGetWindowProperty( x11display.dpy, win, atom, 0, bytes_left, False, AnyPropertyType, &type,
1288 + &format, &nitems, &bytes_after, &data );
1289 + if( ret == Success )
1291 + buffer = Q_malloc( bytes_left + 1 );
1292 + Q_strncpyz( buffer, (char *)data, bytes_left + 1 );
1306 +* Sys_SetClipboardData
1308 +qboolean Sys_SetClipboardData( char *data )
1314 +* Sys_FreeClipboardData
1316 +void Sys_FreeClipboardData( char *data )
1322 +* _NET_WM_CHECK_SUPPORTED
1324 +static qboolean _NET_WM_CHECK_SUPPORTED( Atom NET_ATOM )
1326 + qboolean issupported = qfalse;
1327 + unsigned char *atomdata;
1329 + int status, real_format;
1331 + unsigned long items_read, items_left, i;
1333 + Atom _NET_SUPPORTED;
1335 + _NET_SUPPORTED = XInternAtom( x11display.dpy, "_NET_SUPPORTED", 0 );
1337 + status = XGetWindowProperty( x11display.dpy, x11display.root, _NET_SUPPORTED,
1338 + 0L, 8192L, False, XA_ATOM, &real_type, &real_format,
1339 + &items_read, &items_left, &atomdata );
1341 + if( status != Success )
1344 + atoms = (Atom *)atomdata;
1345 + for( i = 0; result && i < items_read; i++ )
1347 + if( atoms[i] == NET_ATOM )
1349 + issupported = qtrue;
1354 + XFree( atomdata );
1355 + return issupported;
1359 +* _NET_WM_STATE_FULLSCREEN_SUPPORTED
1361 +static qboolean _NET_WM_STATE_FULLSCREEN_SUPPORTED( void )
1363 + Atom _NET_WM_STATE_FULLSCREEN = XInternAtom( x11display.dpy, "_NET_WM_STATE_FULLSCREEN", 0 );
1364 + return _NET_WM_CHECK_SUPPORTED( _NET_WM_STATE_FULLSCREEN );
1369 +* _NETWM_CHECK_FULLSCREEN
1371 +qboolean _NETWM_CHECK_FULLSCREEN( void )
1373 + qboolean isfullscreen = qfalse;
1374 + unsigned char *atomdata;
1376 + int status, real_format;
1378 + unsigned long items_read, items_left, i;
1380 + Atom _NET_WM_STATE;
1381 + Atom _NET_WM_STATE_FULLSCREEN;
1383 + if( !x11display.features.wmStateFullscreen )
1386 + _NET_WM_STATE = XInternAtom( x11display.dpy, "_NET_WM_STATE", 0 );
1387 + _NET_WM_STATE_FULLSCREEN = XInternAtom( x11display.dpy, "_NET_WM_STATE_FULLSCREEN", 0 );
1389 + status = XGetWindowProperty( x11display.dpy, x11display.win, _NET_WM_STATE,
1390 + 0L, 8192L, False, XA_ATOM, &real_type, &real_format,
1391 + &items_read, &items_left, &atomdata );
1393 + if( status != Success )
1396 + atoms = (Atom *)atomdata;
1397 + for( i = 0; result && i < items_read; i++ )
1399 + if( atoms[i] == _NET_WM_STATE_FULLSCREEN )
1401 + isfullscreen = qtrue;
1406 + if( isfullscreen )
1408 + Cvar_SetValue( "vid_fullscreen", 1 );
1409 + vid_fullscreen->modified = qfalse;
1413 + Cvar_SetValue( "vid_fullscreen", 0 );
1414 + vid_fullscreen->modified = qfalse;
1417 + XFree( atomdata );
1418 + return isfullscreen;
1422 +* _NETWM_SET_FULLSCREEN
1424 +* Tell Window-Manager to toggle fullscreen
1426 +void _NETWM_SET_FULLSCREEN( qboolean fullscreen )
1430 + Atom wm_fullscreen;
1432 + if( !x11display.features.wmStateFullscreen )
1435 + wm_state = XInternAtom( x11display.dpy, "_NET_WM_STATE", False );
1436 + wm_fullscreen = XInternAtom( x11display.dpy, "_NET_WM_STATE_FULLSCREEN", False );
1438 + memset(&xev, 0, sizeof(xev));
1439 + xev.type = ClientMessage;
1440 + xev.xany.type = ClientMessage;
1441 + xev.xclient.window = x11display.win;
1442 + xev.xclient.message_type = wm_state;
1443 + xev.xclient.format = 32;
1444 + xev.xclient.data.l[0] = fullscreen ? 1 : 0;
1445 + xev.xclient.data.l[1] = wm_fullscreen;
1446 + xev.xclient.data.l[2] = 0l;
1448 + XSendEvent( x11display.dpy, DefaultRootWindow( x11display.dpy ), False,
1449 + SubstructureNotifyMask | SubstructureRedirectMask, &xev );
1453 +* _NETWM_CHECK_PING
1455 +* Checks if the _NET_WM_PING Atom is already present in WM_PROTOCOLS
1457 +qboolean _NETWM_CHECK_PING( void )
1460 + qboolean present = qfalse;
1464 + status = XGetWMProtocols( x11display.dpy, x11display.win, &atoms, &num_atoms );
1469 + for( i = 0; i < num_atoms; i++ )
1471 + if( atoms[i] == x11display.ping )
1484 +* Sets informative hints defined in the ICCCM2/EWMH spec
1486 +void _NETWM_SET_HINTS( void )
1489 + XTextProperty titleprop, iconprop, clientmachineprop;
1490 + char *title = "Warsow"; //FIXME: Shouldn't be hardcoded
1491 + char *icon_name = "warsow128x128.xpm"; //FIXME: Shouldn't be hardcoded
1492 + pid_t warsowpid; //FIXME: Does Warsow already know it's pid? Can it be retrieved from there?
1493 + char hostname[256]; //FIXME: Is it possible to get the hostname of the client from qcommon/net.c or somewhere else?
1494 + char* hostnamepointer = &hostname[0];
1501 + Atom NET_WM_ICON_NAME;
1502 + Atom NET_WM_WINDOW_TYPE;
1503 + Atom NET_WM_WINDOW_TYPE_NORMAL;
1505 + Atom WM_PROTOCOLS;
1506 + Atom WM_CLIENT_MACHINE;
1508 + x11display.ping = XInternAtom( x11display.dpy, "_NET_WM_PING", False );
1510 + CARDINAL = XInternAtom( x11display.dpy, "CARDINAL", False );
1511 + UTF8_STRING = XInternAtom( x11display.dpy, "_UTF8_STRING", False );
1513 + NET_WM_PID = XInternAtom( x11display.dpy, "_NET_WM_PID", False );
1514 + NET_WM_NAME = XInternAtom( x11display.dpy, "_NET_WM_NAME", False );
1515 + NET_WM_ICON_NAME = XInternAtom( x11display.dpy, "_NET_WM_ICON_NAME", False );
1516 + NET_WM_WINDOW_TYPE = XInternAtom( x11display.dpy, "_NET_WM_WINDOW_TYPE", False );
1517 + NET_WM_WINDOW_TYPE_NORMAL = XInternAtom( x11display.dpy, "_NET_WM_WINDOW_TYPE_NORMAL", False );
1519 + WM_PROTOCOLS = XInternAtom( x11display.dpy, "WM_PROTOCOLS", False );
1520 + WM_CLIENT_MACHINE = XInternAtom( x11display.dpy, "WM_CLIENT_MACHINE", False );
1522 + warsowpid = getpid();
1524 + XChangeProperty( x11display.dpy, x11display.win, NET_WM_PID, CARDINAL, 32,
1526 + (unsigned char *)&warsowpid, 1 );
1528 + status = XStringListToTextProperty( &title, 1, &titleprop );
1531 + XSetTextProperty( x11display.dpy, x11display.win, &titleprop, NET_WM_NAME );
1533 + status = XStringListToTextProperty( &icon_name, 1, &iconprop );
1536 + XSetTextProperty( x11display.dpy, x11display.win, &iconprop, NET_WM_ICON_NAME );
1538 + XChangeProperty( x11display.dpy, x11display.win, NET_WM_WINDOW_TYPE, XA_ATOM, 32,
1540 + (unsigned char *)&NET_WM_WINDOW_TYPE_NORMAL, 1 );
1542 + if( gethostname( hostname, 256 ) == SOCKET_ERROR )
1545 + status = XStringListToTextProperty( &hostnamepointer, 1, &clientmachineprop );
1548 + XSetWMClientMachine( x11display.dpy, x11display.win, &clientmachineprop );
1552 + if( !_NETWM_CHECK_PING() ) {
1553 + XChangeProperty( x11display.dpy, x11display.win, WM_PROTOCOLS, XA_ATOM, 32,
1555 + (unsigned char *)&x11display.ping, 1 );
1559 +/*****************************************************************************/
1561 +static void GLimp_SetXPMIcon( const int *xpm_icon )
1563 + int width, height;
1564 + size_t i, cardinalSize;
1565 + long *cardinalData;
1569 + // allocate memory for icon data: width + height + width * height pixels
1570 + // note: sizeof(long) shall be used according to XChangeProperty() man page
1571 + width = xpm_icon[0];
1572 + height = xpm_icon[1];
1573 + cardinalSize = width * height + 2;
1574 + cardinalData = Q_malloc( cardinalSize * sizeof( *cardinalData ) );
1575 + for( i = 0; i < cardinalSize; i++ )
1576 + cardinalData[i] = xpm_icon[i];
1578 + NET_WM_ICON = XInternAtom( x11display.dpy, "_NET_WM_ICON", False );
1579 + CARDINAL = XInternAtom( x11display.dpy, "CARDINAL", False );
1581 + XChangeProperty( x11display.dpy, x11display.win, NET_WM_ICON, CARDINAL, 32,
1582 + PropModeReplace, (unsigned char *)cardinalData, cardinalSize );
1584 + Q_free( cardinalData );
1587 +int *parse_xpm_icon ( int num_xpm_elements, char *xpm_data[] );
1589 +static void GLimp_SetApplicationIcon( void )
1591 +#include "warsow128x128.xpm"
1593 + const int *xpm_icon;
1595 + xpm_icon = parse_xpm_icon( sizeof( warsow128x128_xpm ) / sizeof( warsow128x128_xpm[0] ), warsow128x128_xpm );
1598 + GLimp_SetXPMIcon( xpm_icon );
1599 + free( ( void * )xpm_icon );
1603 +/*****************************************************************************/
1606 +** GLimp_SetMode_Real
1607 +* Hack to get rid of the prints when toggling fullscreen
1609 +int GLimp_SetMode_Real( int mode, qboolean fullscreen, qboolean silent )
1611 + int width, height, screen_x, screen_y, screen_width, screen_height, screen_mode;
1613 + XSetWindowAttributes wa;
1614 + unsigned long mask;
1615 + qboolean wideScreen;
1617 + if( !VID_GetModeInfo( &width, &height, &wideScreen, mode ) )
1620 + Com_Printf( " invalid mode\n" );
1621 + return rserr_invalid_mode;
1625 + screen_x = screen_y = 0;
1626 + screen_width = width;
1627 + screen_height = height;
1629 + x11display.old_win = x11display.win;
1633 + if( !_xf86_xinerama_supported ||
1634 + !_xf86_XineramaFindBest( &screen_x, &screen_y, &screen_width, &screen_height, silent ) )
1636 + _xf86_VidmodesFindBest( &screen_mode, &screen_width, &screen_height, silent );
1637 + if( screen_mode < 0 )
1640 + Com_Printf( " no mode found\n" );
1641 + return rserr_invalid_mode;
1645 + if( screen_width < width || screen_height < height )
1647 + if( width > height )
1649 + ratio = width / height;
1650 + height = height * ratio;
1651 + width = screen_width;
1655 + ratio = height / width;
1656 + width = width * ratio;
1657 + height = screen_height;
1662 + Com_Printf( "...setting fullscreen mode %d:\n", mode );
1664 + /* Create fulscreen window */
1665 + wa.background_pixel = 0;
1666 + wa.border_pixel = 0;
1667 + wa.event_mask = INIT_MASK;
1668 + wa.backing_store = NotUseful;
1669 + wa.save_under = False;
1671 + if( x11display.features.wmStateFullscreen )
1673 + wa.override_redirect = False;
1674 + mask = CWBackPixel | CWBorderPixel | CWEventMask | CWSaveUnder | CWBackingStore;
1678 + wa.override_redirect = True;
1679 + mask = CWBackPixel | CWBorderPixel | CWEventMask | CWSaveUnder | CWBackingStore | CWOverrideRedirect;
1682 + if( ( !x11display.win ) || !x11display.features.wmStateFullscreen ) {
1683 + x11display.win = XCreateWindow( x11display.dpy, x11display.root, screen_x, screen_y, screen_width, screen_height,
1684 + 0, CopyFromParent, InputOutput, CopyFromParent, mask, &wa );
1685 + x11display.wmDeleteWindow = XInternAtom( x11display.dpy, "WM_DELETE_WINDOW", False );
1686 + XSetWMProtocols( x11display.dpy, x11display.win, &x11display.wmDeleteWindow, 1 );
1687 + _NETWM_SET_HINTS();
1690 + XResizeWindow( x11display.dpy, x11display.gl_win, width, height );
1691 + XReparentWindow( x11display.dpy, x11display.gl_win, x11display.win, ( screen_width/2 )-( width/2 ),
1692 + ( screen_height/2 )-( height/2 ) );
1694 + x11display.modeset = qtrue;
1696 + XMapWindow( x11display.dpy, x11display.gl_win );
1697 + XMapWindow( x11display.dpy, x11display.win );
1699 + if ( !x11display.features.wmStateFullscreen )
1700 + _x11_SetNoResize( x11display.win, width, height );
1702 + _NETWM_SET_FULLSCREEN( qtrue );
1704 + if( screen_mode != -1 )
1706 + _xf86_VidmodesSwitch( screen_mode );
1712 + Com_Printf( "...setting mode %d:\n", mode );
1714 + /* Create managed window */
1715 + wa.background_pixel = 0;
1716 + wa.border_pixel = 0;
1717 + wa.event_mask = INIT_MASK;
1718 + mask = CWBackPixel | CWBorderPixel | CWEventMask;
1720 + if( ( !x11display.win ) || !x11display.features.wmStateFullscreen ) {
1721 + x11display.win = XCreateWindow( x11display.dpy, x11display.root, 0, 0, screen_width, screen_height,
1722 + 0, CopyFromParent, InputOutput, CopyFromParent, mask, &wa );
1723 + x11display.wmDeleteWindow = XInternAtom( x11display.dpy, "WM_DELETE_WINDOW", False );
1724 + XSetWMProtocols( x11display.dpy, x11display.win, &x11display.wmDeleteWindow, 1 );
1725 + _NETWM_SET_HINTS();
1728 + XResizeWindow( x11display.dpy, x11display.gl_win, width, height );
1729 + XReparentWindow( x11display.dpy, x11display.gl_win, x11display.win, 0, 0 );
1731 + x11display.modeset = qtrue;
1733 + XMapWindow( x11display.dpy, x11display.gl_win );
1734 + XMapWindow( x11display.dpy, x11display.win );
1736 + if( !x11display.features.wmStateFullscreen )
1737 + _x11_SetNoResize( x11display.win, width, height );
1739 + _NETWM_SET_FULLSCREEN( qfalse );
1741 + _xf86_VidmodesSwitchBack();
1744 + XSetStandardProperties( x11display.dpy, x11display.win, APPLICATION, None, None, NULL, 0, NULL );
1746 + GLimp_SetApplicationIcon();
1748 + XSetIconName( x11display.dpy, x11display.win, APPLICATION );
1749 + XStoreName( x11display.dpy, x11display.win, APPLICATION );
1751 + // save the parent window size for mouse use. this is not the gl context window
1752 + x11display.win_width = width;
1753 + x11display.win_height = height;
1755 + if( x11display.old_win && !x11display.features.wmStateFullscreen )
1757 + XDestroyWindow( x11display.dpy, x11display.old_win );
1758 + x11display.old_win = 0;
1761 + XFlush( x11display.dpy );
1763 + glState.width = width;
1764 + glState.height = height;
1765 + glState.fullScreen = fullscreen;
1766 + glState.wideScreen = wideScreen;
1768 + // let the sound and input subsystems know about the new window
1769 + VID_NewWindow( width, height );
1777 +int GLimp_SetMode( int mode, qboolean fullscreen )
1779 + return GLimp_SetMode_Real( mode, fullscreen, qfalse );
1783 +** GLimp_GetCurrentMode
1785 +int GLimp_GetCurrentMode( void )
1787 + if( x11display.dpy )
1789 + int width, height;
1791 + width = DisplayWidth( x11display.dpy, x11display.scr );
1792 + height = DisplayHeight( x11display.dpy, x11display.scr );
1793 + return VID_GetModeNum( width, height );
1802 +void GLimp_Shutdown( void )
1804 + if( x11display.dpy )
1806 + _xf86_VidmodesSwitchBack();
1807 + _xf86_VidmodesFree();
1808 + _xf86_XineramaFree();
1810 + if( x11display.cmap ) XFreeColormap( x11display.dpy, x11display.cmap );
1811 + if( x11display.ctx ) qglXDestroyContext( x11display.dpy, x11display.ctx );
1812 + if( x11display.gl_win ) XDestroyWindow( x11display.dpy, x11display.gl_win );
1813 + if( x11display.win ) XDestroyWindow( x11display.dpy, x11display.win );
1815 + XCloseDisplay( x11display.dpy );
1818 + memset(&x11display.features, 0, sizeof(x11display.features));
1819 + x11display.modeset = qfalse;
1820 + x11display.visinfo = NULL;
1821 + x11display.cmap = 0;
1822 + x11display.ctx = NULL;
1823 + x11display.gl_win = 0;
1824 + x11display.win = 0;
1825 + x11display.dpy = NULL;
1828 +static qboolean gotstencil = qfalse; // evil hack!
1829 +static qboolean ChooseVisual( int colorbits, int stencilbits )
1832 + int depthbits = colorbits;
1834 + if( colorbits == 24 ) colorsize = 8;
1835 + else colorsize = 4;
1838 + int attributes[] = {
1841 + GLX_RED_SIZE, colorsize,
1842 + GLX_GREEN_SIZE, colorsize,
1843 + GLX_BLUE_SIZE, colorsize,
1844 + GLX_DEPTH_SIZE, depthbits,
1845 + GLX_STENCIL_SIZE, stencilbits,
1849 + x11display.visinfo = qglXChooseVisual( x11display.dpy, x11display.scr, attributes );
1850 + if( !x11display.visinfo )
1852 + Com_Printf( "..Failed to get colorbits %i, depthbits %i, stencilbits %i\n", colorbits, depthbits, stencilbits );
1857 + Com_Printf( "..Got colorbits %i, depthbits %i, stencilbits %i\n", colorbits, depthbits, stencilbits );
1858 + if( stencilbits > 0 ) gotstencil = qtrue;
1864 +static int _my_x11_error( Display *dpy, XErrorEvent *ev )
1866 + printf("_my_x11_error:\n\ttype: %d\n\terror-code: %d\n\tminor-code: %d\n\trequest-code: %d\n",
1867 + ev->type, ev->error_code, ev->minor_code, ev->request_code );
1877 +int GLimp_Init( void *hinstance, void *wndproc, void *parenthWnd )
1879 + int colorbits, stencilbits;
1880 + XSetWindowAttributes attr;
1881 + unsigned long mask;
1886 + // on unix we can change to fullscreen on fly
1887 + vid_fullscreen->flags &= ~( CVAR_LATCH_VIDEO );
1889 + if( x11display.dpy )
1892 + Com_Printf( "Display initialization\n" );
1894 + x11display.dpy = XOpenDisplay( NULL );
1895 + if( !x11display.dpy )
1897 + Com_Printf( "..Error couldn't open the X display\n" );
1901 + x11display.scr = DefaultScreen( x11display.dpy );
1903 + x11display.root = (Window )parenthWnd;
1905 + x11display.root = RootWindow( x11display.dpy, x11display.scr );
1907 + x11display.wmState = XInternAtom( x11display.dpy, "WM_STATE", False );
1908 + x11display.features.wmStateFullscreen = _NET_WM_STATE_FULLSCREEN_SUPPORTED();
1910 + _xf86_VidmodesInit();
1912 + if( r_colorbits->integer == 16 || r_colorbits->integer == 24 ) colorbits = r_colorbits->integer;
1913 + else colorbits = 0;
1915 + if( r_stencilbits->integer == 8 || r_stencilbits->integer == 16 ) stencilbits = r_stencilbits->integer;
1916 + else stencilbits = 0;
1918 + gotstencil = qfalse;
1919 + if( colorbits > 0 )
1921 + ChooseVisual( colorbits, stencilbits );
1922 + if( !x11display.visinfo && stencilbits > 8 ) ChooseVisual( colorbits, 8 );
1923 + if( !x11display.visinfo && stencilbits > 0 ) ChooseVisual( colorbits, 0 );
1924 + if( !x11display.visinfo && colorbits > 16 ) ChooseVisual( 16, 0 );
1928 + ChooseVisual( 24, stencilbits );
1929 + if( !x11display.visinfo ) ChooseVisual( 16, stencilbits );
1930 + if( !x11display.visinfo && stencilbits > 8 ) ChooseVisual( 24, 8 );
1931 + if( !x11display.visinfo && stencilbits > 8 ) ChooseVisual( 16, 8 );
1932 + if( !x11display.visinfo && stencilbits > 0 ) ChooseVisual( 24, 0 );
1933 + if( !x11display.visinfo && stencilbits > 0 ) ChooseVisual( 16, 0 );
1936 + if( !x11display.visinfo )
1938 + GLimp_Shutdown(); // hope this doesn't do anything evil when we don't have window etc.
1939 + Com_Printf( "..Error couldn't set GLX visual\n" );
1943 + glState.stencilEnabled = gotstencil;
1945 + x11display.ctx = qglXCreateContext( x11display.dpy, x11display.visinfo, NULL, True );
1946 + x11display.cmap = XCreateColormap( x11display.dpy, x11display.root, x11display.visinfo->visual, AllocNone );
1948 + attr.colormap = x11display.cmap;
1949 + attr.border_pixel = 0;
1950 + attr.event_mask = DISPLAY_MASK;
1951 + attr.override_redirect = False;
1952 + mask = CWBorderPixel | CWColormap | ExposureMask;
1954 + x11display.gl_win = XCreateWindow( x11display.dpy, x11display.root, 0, 0, 1, 1, 0,
1955 + x11display.visinfo->depth, InputOutput, x11display.visinfo->visual, mask, &attr );
1956 + qglXMakeCurrent( x11display.dpy, x11display.gl_win, x11display.ctx );
1958 + XSync( x11display.dpy, False );
1960 + XSetErrorHandler( _my_x11_error );
1966 +** GLimp_BeginFrame
1968 +void GLimp_BeginFrame( void )
1975 +** Responsible for doing a swapbuffers and possibly for other stuff
1976 +** as yet to be determined. Probably better not to make this a GLimp
1977 +** function and instead do a call to GLimp_SwapBuffers.
1979 +void GLimp_EndFrame( void )
1981 + qglXSwapBuffers( x11display.dpy, x11display.gl_win );
1983 + if( vid_fullscreen->modified || ( vid_fullscreen->integer && vid_multiscreen_head->modified ) )
1985 + GLimp_SetMode_Real( r_mode->integer, vid_fullscreen->integer, qtrue );
1986 + vid_fullscreen->modified = qfalse;
1987 + vid_multiscreen_head->modified = qfalse;
1992 +** GLimp_GetGammaRamp
1994 +qboolean GLimp_GetGammaRamp( size_t stride, unsigned short *ramp )
1996 + if( XF86VidModeGetGammaRamp( x11display.dpy, x11display.scr, stride, ramp, ramp + stride, ramp + ( stride << 1 ) ) != 0 )
2002 +** GLimp_SetGammaRamp
2004 +void GLimp_SetGammaRamp( size_t stride, unsigned short *ramp )
2006 + XF86VidModeSetGammaRamp( x11display.dpy, x11display.scr, stride, ramp, ramp + stride, ramp + ( stride << 1 ) );
2010 +** GLimp_AppActivate
2012 +void GLimp_AppActivate( qboolean active, qboolean destroy )
2016 diff -ru a/unix/unix_input.c b/unix/unix_input.c
2017 --- a/unix/unix_input.c 2011-04-29 14:42:24.000000000 +0200
2018 +++ b/unix/unix_input.c 2011-10-03 22:13:53.000000000 +0200
2019 @@ -748,6 +748,13 @@
2021 if( event.xclient.data.l[0] == x11display.wmDeleteWindow )
2022 Cbuf_ExecuteText( EXEC_NOW, "quit" );
2024 + if( event.xclient.data.l[0] == x11display.ping )
2026 + event.xclient.window = x11display.root;
2027 + XSendEvent( x11display.dpy, x11display.root, False,
2028 + (SubstructureNotifyMask|SubstructureRedirectMask), &event );
2033 diff -ru a/unix/x11.h b/unix/x11.h
2034 --- a/unix/x11.h 2011-04-29 14:42:24.000000000 +0200
2035 +++ b/unix/x11.h 2011-10-03 22:11:30.000000000 +0200
2038 XVisualInfo *visinfo;
2039 Atom wmDeleteWindow;
2043 struct featureset_s {