updated on Tue Jan 17 16:10:12 UTC 2012
[aur-mirror.git] / warsow-openbox / warsowopenboxfs.patch
bloba4fdc1fb83647e3d8e07f97a9bf0d62929fa63dc
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
4 @@ -1,941 +1,1070 @@
5 -/*
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.
23 - */
24 -/*
25 -** GLW_IMP.C
26 -**
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:
30 -**
31 -** GLimp_EndFrame
32 -** GLimp_Init
33 -** GLimp_Shutdown
34 -** GLimp_SwitchFullscreen
35 -**
36 -*/
38 -#include <termios.h>
39 -#include <sys/ioctl.h>
40 -#include <sys/stat.h>
41 -#include <stdarg.h>
42 -#include <stdio.h>
43 -#include <unistd.h>
44 -#include <signal.h>
45 -#include <dlfcn.h>
47 -#include "../ref_gl/r_local.h"
48 -#include "../client/keys.h"
50 -#include "x11.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 ) )
75 - {
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;
81 - }
82 - else
83 - {
84 - Com_Printf( "..XFree86-VidMode Extension not available\n" );
85 - _xf86_vidmodes_supported = qfalse;
86 - }
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;
105 - else
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 )
126 - return qfalse;
128 - xinerama = XineramaQueryScreens( x11display.dpy, &screens );
129 - if( screens <= 1 )
130 - return qfalse;
132 - head = -1;
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 )
139 - head = i;
140 - break;
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 )
147 - head = -1;
148 - if( !silent )
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;
164 - else
166 - dist = xinerama[i].width - *width;
169 - if( dist < 0 )
170 - dist = -dist; // Only positive number please
172 - if( dist < best_dist )
174 - best_dist = dist;
175 - head = i;
179 - if( head < -1 )
181 - if( !silent )
182 - Com_Printf( "Xinerama: No fitting head found" );
183 - return qfalse;
187 - *x = xinerama[head].x_org;
188 - *y = xinerama[head].y_org;
189 - *width = xinerama[head].width;
190 - *height = xinerama[head].height;
192 - if( !silent )
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 );
195 - return qtrue;
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;
239 - best_fit = -1;
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 )
247 - continue;
249 - x = _xf86_vidmodes[i]->hdisplay - *pwidth;
250 - y = _xf86_vidmodes[i]->vdisplay - *pheight;
252 - if( x > y ) dist = y;
253 - else dist = x;
255 - if( dist < 0 ) dist = -dist; // Only positive number please
257 - if( dist < best_dist )
259 - best_dist = dist;
260 - best_fit = i;
263 - if( !silent )
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 )
269 - if( !silent )
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;
277 - *mode = best_fit;
280 -static void _x11_SetNoResize( Window w, int width, int height )
282 - XSizeHints *hints;
284 - if( x11display.dpy )
286 - hints = XAllocSizeHints();
288 - if( hints )
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 );
296 - XFree( hints );
301 -/*****************************************************************************/
304 - =================
305 - Sys_GetClipboardData
307 - Orginally from EzQuake
308 - There should be a smarter place to put this
309 - =================
310 - */
311 -char *Sys_GetClipboardData( qboolean primary )
313 - Window win;
314 - Atom type;
315 - int format, ret;
316 - unsigned long nitems, bytes_after, bytes_left;
317 - unsigned char *data;
318 - char *buffer;
319 - Atom atom;
321 - if( !x11display.dpy )
322 - return NULL;
324 - if( primary )
326 - atom = XInternAtom( x11display.dpy, "PRIMARY", True );
328 - else
330 - atom = XInternAtom( x11display.dpy, "CLIPBOARD", True );
332 - if( atom == None )
333 - return NULL;
335 - win = XGetSelectionOwner( x11display.dpy, atom );
336 - if( win == None )
337 - return NULL;
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,
343 - &data );
344 - if( bytes_left <= 0 )
345 - return NULL;
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 );
354 - else
356 - buffer = NULL;
359 - XFree( data );
361 - return buffer;
366 -* Sys_SetClipboardData
368 -qboolean Sys_SetClipboardData( char *data )
370 - return qfalse;
374 - =================
375 - Sys_FreeClipboardData
376 - =================
377 - */
378 -void Sys_FreeClipboardData( char *data )
380 - Q_free( data );
384 -* _NET_WM_CHECK_SUPPORTED
386 -static qboolean _NET_WM_CHECK_SUPPORTED( Atom NET_ATOM )
388 - qboolean issupported = qfalse;
389 - unsigned char *atomdata;
390 - Atom *atoms;
391 - int status, real_format;
392 - Atom real_type;
393 - unsigned long items_read, items_left, i;
394 - int result = 1;
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 )
404 - return qfalse;
406 - atoms = (Atom *)atomdata;
407 - for( i = 0; result && i < items_read; i++ )
409 - if( atoms[i] == NET_ATOM )
411 - issupported = qtrue;
412 - break;
416 - XFree( atomdata );
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;
437 - Atom *atoms;
438 - int status, real_format;
439 - Atom real_type;
440 - unsigned long items_read, items_left, i;
441 - int result = 1;
442 - Atom _NET_WM_STATE;
443 - Atom _NET_WM_STATE_FULLSCREEN;
445 - if( !x11display.features.wmStateFullscreen )
446 - return qfalse;
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 )
456 - return qfalse;
458 - atoms = (Atom *)atomdata;
459 - for( i = 0; result && i < items_read; i++ )
461 - if( atoms[i] == _NET_WM_STATE_FULLSCREEN )
463 - isfullscreen = qtrue;
464 - break;
468 - if( isfullscreen )
470 - Cvar_SetValue( "vid_fullscreen", 1 );
471 - vid_fullscreen->modified = qfalse;
473 - else
475 - Cvar_SetValue( "vid_fullscreen", 0 );
476 - vid_fullscreen->modified = qfalse;
479 - XFree( atomdata );
480 - return isfullscreen;
484 -* _NETWM_SET_FULLSCREEN
486 -* Tell Window-Manager to toggle fullscreen
488 -void _NETWM_SET_FULLSCREEN( qboolean fullscreen )
490 - XEvent xev;
491 - Atom wm_state;
492 - Atom wm_fullscreen;
494 - if( !x11display.features.wmStateFullscreen )
495 - return;
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 )
517 - int width, height;
518 - size_t i, cardinalSize;
519 - long *cardinalData;
520 - Atom NET_WM_ICON;
521 - Atom CARDINAL;
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 );
550 - if( xpm_icon )
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;
566 - float ratio;
567 - XSetWindowAttributes wa;
568 - unsigned long mask;
569 - qboolean wideScreen;
571 - if( !VID_GetModeInfo( &width, &height, &wideScreen, mode ) )
573 - if( !silent )
574 - Com_Printf( " invalid mode\n" );
575 - return rserr_invalid_mode;
578 - screen_mode = -1;
579 - screen_x = screen_y = 0;
580 - screen_width = width;
581 - screen_height = height;
583 - x11display.old_win = x11display.win;
585 - if( fullscreen )
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 )
593 - if( !silent )
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;
607 - else
609 - ratio = height / width;
610 - width = width * ratio;
611 - height = screen_height;
615 - if( !silent )
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;
630 - else
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 );
650 - else
651 - _NETWM_SET_FULLSCREEN( qtrue );
653 - if( screen_mode != -1 )
654 - _xf86_VidmodesSwitch( screen_mode );
656 - else
658 - if( !silent )
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 );
713 - return rserr_ok;
717 -** GLimp_SetMode
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 )
731 - int width, height;
733 - width = DisplayWidth( x11display.dpy, x11display.scr );
734 - height = DisplayHeight( x11display.dpy, x11display.scr );
735 - return VID_GetModeNum( width, height );
738 - return -1;
742 -** GLimp_Shutdown
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 )
773 - int colorsize;
774 - int depthbits = colorbits;
776 - if( colorbits == 24 ) colorsize = 8;
777 - else colorsize = 4;
780 - int attributes[] = {
781 - GLX_RGBA,
782 - GLX_DOUBLEBUFFER,
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,
788 - None
789 - };
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 );
795 - return qfalse;
797 - else
799 - Com_Printf( "..Got colorbits %i, depthbits %i, stencilbits %i\n", colorbits, depthbits, stencilbits );
800 - if( stencilbits > 0 ) gotstencil = qtrue;
801 - return qtrue;
807 -** GLimp_Init
809 -int GLimp_Init( void *hinstance, void *wndproc, void *parenthWnd )
811 - int colorbits, stencilbits;
812 - XSetWindowAttributes attr;
813 - unsigned long mask;
815 - hinstance = NULL;
816 - wndproc = NULL;
818 - // on unix we can change to fullscreen on fly
819 - vid_fullscreen->flags &= ~( CVAR_LATCH_VIDEO );
821 - if( x11display.dpy )
822 - GLimp_Shutdown();
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" );
830 - return 0;
833 - x11display.scr = DefaultScreen( x11display.dpy );
834 - if( parenthWnd )
835 - x11display.root = (Window )parenthWnd;
836 - else
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 );
859 - else
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" );
873 - return 0;
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 );
893 - return 1;
897 -** GLimp_BeginFrame
899 -void GLimp_BeginFrame( void )
904 -** GLimp_EndFrame
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 )
928 - return qtrue;
929 - return qfalse;
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.
966 +** GLW_IMP.C
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:
972 +** GLimp_EndFrame
973 +** GLimp_Init
974 +** GLimp_Shutdown
975 +** GLimp_SwitchFullscreen
979 +#include <termios.h>
980 +#include <sys/ioctl.h>
981 +#include <sys/stat.h>
982 +#include <stdarg.h>
983 +#include <stdio.h>
984 +#include <unistd.h>
985 +#include <signal.h>
986 +#include <dlfcn.h>
988 +#include "../ref_gl/r_local.h"
989 +#include "../client/keys.h"
991 +#include "x11.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;
1024 + else
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;
1047 + else
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 )
1068 + return qfalse;
1070 + xinerama = XineramaQueryScreens( x11display.dpy, &screens );
1071 + if( screens <= 1 )
1072 + return qfalse;
1074 + head = -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 )
1081 + head = i;
1082 + break;
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 )
1089 + head = -1;
1090 + if( !silent )
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;
1106 + else
1108 + dist = xinerama[i].width - *width;
1111 + if( dist < 0 )
1112 + dist = -dist; // Only positive number please
1114 + if( dist < best_dist )
1116 + best_dist = dist;
1117 + head = i;
1121 + if( head < -1 )
1123 + if( !silent )
1124 + Com_Printf( "Xinerama: No fitting head found" );
1125 + return qfalse;
1129 + *x = xinerama[head].x_org;
1130 + *y = xinerama[head].y_org;
1131 + *width = xinerama[head].width;
1132 + *height = xinerama[head].height;
1134 + if( !silent )
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 );
1137 + return qtrue;
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;
1181 + best_fit = -1;
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 )
1189 + continue;
1191 + x = _xf86_vidmodes[i]->hdisplay - *pwidth;
1192 + y = _xf86_vidmodes[i]->vdisplay - *pheight;
1194 + if( x > y ) dist = y;
1195 + else dist = x;
1197 + if( dist < 0 ) dist = -dist; // Only positive number please
1199 + if( dist < best_dist )
1201 + best_dist = dist;
1202 + best_fit = i;
1205 + if( !silent )
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 )
1211 + if( !silent )
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;
1219 + *mode = best_fit;
1222 +static void _x11_SetNoResize( Window w, int width, int height )
1224 + XSizeHints *hints;
1226 + if( x11display.dpy )
1228 + hints = XAllocSizeHints();
1230 + if( hints )
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 );
1238 + XFree( 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 )
1253 + Window win;
1254 + Atom type;
1255 + int format, ret;
1256 + unsigned long nitems, bytes_after, bytes_left;
1257 + unsigned char *data;
1258 + char *buffer;
1259 + Atom atom;
1261 + if( !x11display.dpy )
1262 + return NULL;
1264 + if( primary )
1266 + atom = XInternAtom( x11display.dpy, "PRIMARY", True );
1268 + else
1270 + atom = XInternAtom( x11display.dpy, "CLIPBOARD", True );
1272 + if( atom == None )
1273 + return NULL;
1275 + win = XGetSelectionOwner( x11display.dpy, atom );
1276 + if( win == None )
1277 + return NULL;
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,
1283 + &data );
1284 + if( bytes_left <= 0 )
1285 + return NULL;
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 );
1294 + else
1296 + buffer = NULL;
1299 + XFree( data );
1301 + return buffer;
1306 +* Sys_SetClipboardData
1308 +qboolean Sys_SetClipboardData( char *data )
1310 + return qfalse;
1314 +* Sys_FreeClipboardData
1316 +void Sys_FreeClipboardData( char *data )
1318 + Q_free( data );
1322 +* _NET_WM_CHECK_SUPPORTED
1324 +static qboolean _NET_WM_CHECK_SUPPORTED( Atom NET_ATOM )
1326 + qboolean issupported = qfalse;
1327 + unsigned char *atomdata;
1328 + Atom *atoms;
1329 + int status, real_format;
1330 + Atom real_type;
1331 + unsigned long items_read, items_left, i;
1332 + int result = 1;
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 )
1342 + return qfalse;
1344 + atoms = (Atom *)atomdata;
1345 + for( i = 0; result && i < items_read; i++ )
1347 + if( atoms[i] == NET_ATOM )
1349 + issupported = qtrue;
1350 + break;
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;
1375 + Atom *atoms;
1376 + int status, real_format;
1377 + Atom real_type;
1378 + unsigned long items_read, items_left, i;
1379 + int result = 1;
1380 + Atom _NET_WM_STATE;
1381 + Atom _NET_WM_STATE_FULLSCREEN;
1383 + if( !x11display.features.wmStateFullscreen )
1384 + return qfalse;
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 )
1394 + return qfalse;
1396 + atoms = (Atom *)atomdata;
1397 + for( i = 0; result && i < items_read; i++ )
1399 + if( atoms[i] == _NET_WM_STATE_FULLSCREEN )
1401 + isfullscreen = qtrue;
1402 + break;
1406 + if( isfullscreen )
1408 + Cvar_SetValue( "vid_fullscreen", 1 );
1409 + vid_fullscreen->modified = qfalse;
1411 + else
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 )
1428 + XEvent xev;
1429 + Atom wm_state;
1430 + Atom wm_fullscreen;
1432 + if( !x11display.features.wmStateFullscreen )
1433 + return;
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 )
1459 + Status status;
1460 + qboolean present = qfalse;
1461 + Atom *atoms;
1462 + int num_atoms, i;
1464 + status = XGetWMProtocols( x11display.dpy, x11display.win, &atoms, &num_atoms );
1466 + if( status == 0 )
1467 + return qfalse;
1469 + for( i = 0; i < num_atoms; i++ )
1471 + if( atoms[i] == x11display.ping )
1473 + present = qtrue;
1474 + break;
1477 + XFree( atoms );
1478 + return present;
1482 +* _NETWM_SET_HINTS
1484 +* Sets informative hints defined in the ICCCM2/EWMH spec
1486 +void _NETWM_SET_HINTS( void )
1488 + Status status;
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];
1496 + Atom CARDINAL;
1497 + Atom UTF8_STRING;
1499 + Atom NET_WM_PID;
1500 + Atom NET_WM_NAME;
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,
1525 + PropModeReplace,
1526 + (unsigned char *)&warsowpid, 1 );
1528 + status = XStringListToTextProperty( &title, 1, &titleprop );
1530 + if( status )
1531 + XSetTextProperty( x11display.dpy, x11display.win, &titleprop, NET_WM_NAME );
1533 + status = XStringListToTextProperty( &icon_name, 1, &iconprop );
1535 + if( status )
1536 + XSetTextProperty( x11display.dpy, x11display.win, &iconprop, NET_WM_ICON_NAME );
1538 + XChangeProperty( x11display.dpy, x11display.win, NET_WM_WINDOW_TYPE, XA_ATOM, 32,
1539 + PropModeReplace,
1540 + (unsigned char *)&NET_WM_WINDOW_TYPE_NORMAL, 1 );
1542 + if( gethostname( hostname, 256 ) == SOCKET_ERROR )
1543 + return;
1545 + status = XStringListToTextProperty( &hostnamepointer, 1, &clientmachineprop );
1547 + if( status )
1548 + XSetWMClientMachine( x11display.dpy, x11display.win, &clientmachineprop );
1549 + else
1550 + return;
1552 + if( !_NETWM_CHECK_PING() ) {
1553 + XChangeProperty( x11display.dpy, x11display.win, WM_PROTOCOLS, XA_ATOM, 32,
1554 + PropModeAppend,
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;
1566 + Atom NET_WM_ICON;
1567 + Atom CARDINAL;
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 );
1596 + if( xpm_icon )
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;
1612 + float ratio;
1613 + XSetWindowAttributes wa;
1614 + unsigned long mask;
1615 + qboolean wideScreen;
1617 + if( !VID_GetModeInfo( &width, &height, &wideScreen, mode ) )
1619 + if( !silent )
1620 + Com_Printf( " invalid mode\n" );
1621 + return rserr_invalid_mode;
1624 + screen_mode = -1;
1625 + screen_x = screen_y = 0;
1626 + screen_width = width;
1627 + screen_height = height;
1629 + x11display.old_win = x11display.win;
1631 + if( fullscreen )
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 )
1639 + if( !silent )
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;
1653 + else
1655 + ratio = height / width;
1656 + width = width * ratio;
1657 + height = screen_height;
1661 + if( !silent )
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;
1676 + else
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 );
1701 + else
1702 + _NETWM_SET_FULLSCREEN( qtrue );
1704 + if( screen_mode != -1 )
1706 + _xf86_VidmodesSwitch( screen_mode );
1709 + else
1711 + if( !silent )
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 );
1738 + else
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 );
1771 + return rserr_ok;
1775 +** GLimp_SetMode
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 );
1796 + return -1;
1800 +** GLimp_Shutdown
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 )
1831 + int colorsize;
1832 + int depthbits = colorbits;
1834 + if( colorbits == 24 ) colorsize = 8;
1835 + else colorsize = 4;
1838 + int attributes[] = {
1839 + GLX_RGBA,
1840 + GLX_DOUBLEBUFFER,
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,
1846 + None
1847 + };
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 );
1853 + return qfalse;
1855 + else
1857 + Com_Printf( "..Got colorbits %i, depthbits %i, stencilbits %i\n", colorbits, depthbits, stencilbits );
1858 + if( stencilbits > 0 ) gotstencil = qtrue;
1859 + return 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 );
1869 +// assert( 0 );
1871 + return 0;
1875 +** GLimp_Init
1877 +int GLimp_Init( void *hinstance, void *wndproc, void *parenthWnd )
1879 + int colorbits, stencilbits;
1880 + XSetWindowAttributes attr;
1881 + unsigned long mask;
1883 + hinstance = NULL;
1884 + wndproc = NULL;
1886 + // on unix we can change to fullscreen on fly
1887 + vid_fullscreen->flags &= ~( CVAR_LATCH_VIDEO );
1889 + if( x11display.dpy )
1890 + GLimp_Shutdown();
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" );
1898 + return 0;
1901 + x11display.scr = DefaultScreen( x11display.dpy );
1902 + if( parenthWnd )
1903 + x11display.root = (Window )parenthWnd;
1904 + else
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 );
1926 + else
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" );
1940 + return 0;
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 );
1962 + return 1;
1966 +** GLimp_BeginFrame
1968 +void GLimp_BeginFrame( void )
1973 +** GLimp_EndFrame
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 )
1997 + return qtrue;
1998 + return qfalse;
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 @@
2020 case ClientMessage:
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 );
2030 break;
2032 case MapNotify:
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
2036 @@ -18,6 +18,7 @@
2037 GLXContext ctx;
2038 XVisualInfo *visinfo;
2039 Atom wmDeleteWindow;
2040 + Atom ping;
2042 Atom wmState;
2043 struct featureset_s {