diff options
| author | Magnus Auvinen <magnus.auvinen@gmail.com> | 2007-08-22 07:52:33 +0000 |
|---|---|---|
| committer | Magnus Auvinen <magnus.auvinen@gmail.com> | 2007-08-22 07:52:33 +0000 |
| commit | 8b3c16e6152a527f9aec1a88a9eed74119de7000 (patch) | |
| tree | f0bde5cea15e696e42cade06a3b12ff6b13acc57 /src/engine/external/glfw/lib/x11/x11_window.c | |
| parent | 9899666a7ce6679a3b9667ab09f615f4d0769c16 (diff) | |
| download | zcatch-8b3c16e6152a527f9aec1a88a9eed74119de7000.tar.gz zcatch-8b3c16e6152a527f9aec1a88a9eed74119de7000.zip | |
major engine cleanup. dependency on baselib removed. engine is now C code (not ansi tho). some other cruft removed aswell
Diffstat (limited to 'src/engine/external/glfw/lib/x11/x11_window.c')
| -rw-r--r-- | src/engine/external/glfw/lib/x11/x11_window.c | 1746 |
1 files changed, 1746 insertions, 0 deletions
diff --git a/src/engine/external/glfw/lib/x11/x11_window.c b/src/engine/external/glfw/lib/x11/x11_window.c new file mode 100644 index 00000000..d9d97be4 --- /dev/null +++ b/src/engine/external/glfw/lib/x11/x11_window.c @@ -0,0 +1,1746 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: x11_window.c +// Platform: X11 (Unix) +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + + +/* Defines some GLX FSAA tokens if not yet defined */ +#ifndef GLX_SAMPLE_BUFFERS +# define GLX_SAMPLE_BUFFERS 100000 +#endif +#ifndef GLX_SAMPLES +# define GLX_SAMPLES 100001 +#endif + + +/* KDE decoration values */ +enum { + KDE_noDecoration = 0, + KDE_normalDecoration = 1, + KDE_tinyDecoration = 2, + KDE_noFocus = 256, + KDE_standaloneMenuBar = 512, + KDE_desktopIcon = 1024 , + KDE_staysOnTop = 2048 +}; + + +//************************************************************************ +//**** GLFW internal functions **** +//************************************************************************ + +//======================================================================== +// _glfwWaitForMapNotify() +//======================================================================== + +Bool _glfwWaitForMapNotify( Display *d, XEvent *e, char *arg ) +{ + return (e->type == MapNotify) && (e->xmap.window == (Window)arg); +} + + +//======================================================================== +// _glfwWaitForUnmapNotify() +//======================================================================== + +Bool _glfwWaitForUnmapNotify( Display *d, XEvent *e, char *arg ) +{ + return (e->type == UnmapNotify) && (e->xmap.window == (Window)arg); +} + + +//======================================================================== +// _glfwDisableDecorations() - Turn off window decorations +// Based on xawdecode: src/wmhooks.c +//======================================================================== + +#define MWM_HINTS_DECORATIONS (1L << 1) + +static void _glfwDisableDecorations( void ) +{ + int RemovedDecorations; + Atom HintAtom; + XSetWindowAttributes attributes; + + RemovedDecorations = 0; + + // First try to set MWM hints + HintAtom = XInternAtom( _glfwLibrary.Dpy, "_MOTIF_WM_HINTS", True ); + if ( HintAtom != None ) + { + struct { + unsigned long flags; + unsigned long functions; + unsigned long decorations; + long input_mode; + unsigned long status; + } MWMHints = { MWM_HINTS_DECORATIONS, 0, 0, 0, 0 }; + + XChangeProperty( _glfwLibrary.Dpy, _glfwWin.Win, HintAtom, HintAtom, + 32, PropModeReplace, (unsigned char *)&MWMHints, + sizeof(MWMHints)/4 ); + RemovedDecorations = 1; + } + + // Now try to set KWM hints + HintAtom = XInternAtom( _glfwLibrary.Dpy, "KWM_WIN_DECORATION", True ); + if ( HintAtom != None ) + { + long KWMHints = KDE_tinyDecoration; + + XChangeProperty( _glfwLibrary.Dpy, _glfwWin.Win, HintAtom, HintAtom, + 32, PropModeReplace, (unsigned char *)&KWMHints, + sizeof(KWMHints)/4 ); + RemovedDecorations = 1; + } + + // Now try to set GNOME hints + HintAtom = XInternAtom(_glfwLibrary.Dpy, "_WIN_HINTS", True ); + if ( HintAtom != None ) + { + long GNOMEHints = 0; + + XChangeProperty( _glfwLibrary.Dpy, _glfwWin.Win, HintAtom, HintAtom, + 32, PropModeReplace, (unsigned char *)&GNOMEHints, + sizeof(GNOMEHints)/4 ); + RemovedDecorations = 1; + } + + // Now try to set KDE NET_WM hints + HintAtom = XInternAtom( _glfwLibrary.Dpy, "_NET_WM_WINDOW_TYPE", True ); + if ( HintAtom != None ) + { + Atom NET_WMHints[2]; + + NET_WMHints[0] = XInternAtom( _glfwLibrary.Dpy, "_KDE_NET_WM_WINDOW_TYPE_OVERRIDE", True ); + /* define a fallback... */ + NET_WMHints[1] = XInternAtom( _glfwLibrary.Dpy, "_NET_WM_WINDOW_TYPE_NORMAL", True ); + + XChangeProperty( _glfwLibrary.Dpy, _glfwWin.Win, HintAtom, XA_ATOM, + 32, PropModeReplace, (unsigned char *)&NET_WMHints, + 2 ); + RemovedDecorations = 1; + } + + // Set ICCCM fullscreen WM hint + HintAtom = XInternAtom( _glfwLibrary.Dpy, "_NET_WM_STATE", True ); + if ( HintAtom != None ) + { + Atom NET_WMHints[1]; + + NET_WMHints[0] = XInternAtom( _glfwLibrary.Dpy, "_NET_WM_STATE_FULLSCREEN", True ); + + XChangeProperty( _glfwLibrary.Dpy, _glfwWin.Win, HintAtom, XA_ATOM, + 32, PropModeReplace, (unsigned char *)&NET_WMHints, 1 ); + } + + + // Did we sucessfully remove the window decorations? + if( RemovedDecorations ) + { + // Finally set the transient hints + XSetTransientForHint( _glfwLibrary.Dpy, _glfwWin.Win, RootWindow(_glfwLibrary.Dpy, _glfwWin.Scrn) ); + XUnmapWindow( _glfwLibrary.Dpy, _glfwWin.Win ); + XMapWindow( _glfwLibrary.Dpy, _glfwWin.Win ); + } + else + { + // The Butcher way of removing window decorations + attributes.override_redirect = True; + XChangeWindowAttributes( _glfwLibrary.Dpy, _glfwWin.Win, + CWOverrideRedirect, &attributes ); + _glfwWin.OverrideRedirect = GL_TRUE; + } +} + + +//======================================================================== +// _glfwEnableDecorations() - Turn on window decorations +//======================================================================== + +static void _glfwEnableDecorations( void ) +{ + int ActivatedDecorations; + Atom HintAtom; + + // If this is an override redirect window, skip it... + if( _glfwWin.OverrideRedirect ) + { + return; + } + + ActivatedDecorations = 0; + + // First try to unset MWM hints + HintAtom = XInternAtom( _glfwLibrary.Dpy, "_MOTIF_WM_HINTS", True ); + if ( HintAtom != None ) + { + XDeleteProperty( _glfwLibrary.Dpy, _glfwWin.Win, HintAtom ); + ActivatedDecorations = 1; + } + + // Now try to unset KWM hints + HintAtom = XInternAtom( _glfwLibrary.Dpy, "KWM_WIN_DECORATION", True ); + if ( HintAtom != None ) + { + XDeleteProperty( _glfwLibrary.Dpy, _glfwWin.Win, HintAtom ); + ActivatedDecorations = 1; + } + + // Now try to unset GNOME hints + HintAtom = XInternAtom( _glfwLibrary.Dpy, "_WIN_HINTS", True ); + if ( HintAtom != None ) + { + XDeleteProperty( _glfwLibrary.Dpy, _glfwWin.Win, HintAtom ); + ActivatedDecorations = 1; + } + + // Now try to unset NET_WM hints + HintAtom = XInternAtom( _glfwLibrary.Dpy, "_NET_WM_WINDOW_TYPE", True ); + if ( HintAtom != None ) + { + Atom NET_WMHints = XInternAtom( _glfwLibrary.Dpy, "_NET_WM_WINDOW_TYPE_NORMAL", True); + if( NET_WMHints != None ) + { + XChangeProperty( _glfwLibrary.Dpy, _glfwWin.Win, + HintAtom, XA_ATOM, 32, PropModeReplace, + (unsigned char *)&NET_WMHints, 1 ); + ActivatedDecorations = 1; + } + } + + // Finally unset the transient hints if necessary + if( ActivatedDecorations ) + { + // NOTE: Does this work? + XSetTransientForHint( _glfwLibrary.Dpy, _glfwWin.Win, None); + XUnmapWindow( _glfwLibrary.Dpy, _glfwWin.Win ); + XMapWindow( _glfwLibrary.Dpy, _glfwWin.Win ); + } +} + + +//======================================================================== +// _glfwChooseVisual() - We do our own function here, since +// glXChooseVisual does not behave as we want it to (not according to the +// GLFW specs) +//======================================================================== + +XVisualInfo * _glfwChooseVisual( Display *Dpy, int Screen, int r, int g, + int b, int a, int d, int s, int ar, int ag, int ab, int aa, int aux, + int fsaa, int stereo) +{ + XVisualInfo *VI, *VI_list, VI_tmp; + int nitems_return, i; + int vi_gl, vi_rgba, vi_double, vi_stereo; + int vi_r, vi_g, vi_b, vi_a, vi_d, vi_s, vi_ar, vi_ag, vi_ab, vi_aa; + int vi_aux; + int color, accum, vi_accum; + int missing, color_diff, extra_diff; + int best_vis, best_missing, best_color_diff, best_extra_diff; + int samples, samplebuffers, vi_samples, vi_samplebuffers; + + // Get list of visuals for this screen & display + VI_tmp.screen = Screen; + VI_list = XGetVisualInfo( Dpy, VisualScreenMask, &VI_tmp, + &nitems_return ); + if( VI_list == NULL ) + { + return NULL; + } + + // Pick some prefered color depth if the user did not request a + // specific depth (note: if the user did not request a specific color + // depth, this will not be a driving demand, it's only here to avoid + // selection randomness) + color = (r > 0 || g > 0 || b > 0); + if( !color ) + { + r = g = b = 8; + } + + // Make sure that stereo is 1 or 0 + stereo = stereo ? 1 : 0; + + // Convenience pre-calculation + accum = (ar > 0 || ag > 0 || ab > 0 || aa > 0); + + samples = fsaa; + samplebuffers = (fsaa > 0) ? 1 : 0; + + + + // Loop through list of visuals to find best match + best_vis = -1; + best_missing = 0x7fffffff; + best_color_diff = 0x7fffffff; + best_extra_diff = 0x7fffffff; + for( i = 0; i < nitems_return; i ++ ) + { + // We want GL, RGBA & DOUBLEBUFFER, and NOT STEREO / STEREO + glXGetConfig( Dpy, &VI_list[i], GLX_USE_GL, &vi_gl ); + glXGetConfig( Dpy, &VI_list[i], GLX_RGBA, &vi_rgba ); + glXGetConfig( Dpy, &VI_list[i], GLX_DOUBLEBUFFER, &vi_double ); + glXGetConfig( Dpy, &VI_list[i], GLX_STEREO, &vi_stereo ); + vi_stereo = vi_stereo ? 1 : 0; + if( vi_gl && vi_rgba && vi_double && (vi_stereo == stereo) ) + { + // Get visual color parameters + glXGetConfig( Dpy, &VI_list[i], GLX_RED_SIZE, &vi_r ); + glXGetConfig( Dpy, &VI_list[i], GLX_GREEN_SIZE, &vi_g ); + glXGetConfig( Dpy, &VI_list[i], GLX_BLUE_SIZE, &vi_b ); + + // Get visual "extra" parameters + glXGetConfig( Dpy, &VI_list[i], GLX_ALPHA_SIZE, &vi_a ); + glXGetConfig( Dpy, &VI_list[i], GLX_DEPTH_SIZE, &vi_d ); + glXGetConfig( Dpy, &VI_list[i], GLX_STENCIL_SIZE, &vi_s ); + glXGetConfig( Dpy, &VI_list[i], GLX_ACCUM_RED_SIZE, &vi_ar ); + glXGetConfig( Dpy, &VI_list[i], GLX_ACCUM_GREEN_SIZE, &vi_ag ); + glXGetConfig( Dpy, &VI_list[i], GLX_ACCUM_BLUE_SIZE, &vi_ab ); + glXGetConfig( Dpy, &VI_list[i], GLX_ACCUM_ALPHA_SIZE, &vi_aa ); + glXGetConfig( Dpy, &VI_list[i], GLX_AUX_BUFFERS, &vi_aux ); + glXGetConfig( Dpy, &VI_list[i], GLX_SAMPLE_BUFFERS, &vi_samplebuffers ); + glXGetConfig( Dpy, &VI_list[i], GLX_SAMPLES, &vi_samples ); + + vi_accum = (vi_ar > 0 || vi_ag > 0 || vi_ab > 0 || vi_aa > 0); + + // Check how many buffers are missing + missing = 0; + if( a > 0 && vi_a == 0 ) missing ++; + if( d > 0 && vi_d == 0 ) missing ++; + if( s > 0 && vi_s == 0 ) missing ++; + if( accum && !vi_accum ) missing ++; + if( aux > 0 && vi_aux == 0 ) missing ++; + if( samplebuffers > 0 && vi_samplebuffers == 0 ) missing ++; + + + // Calculate color diff + color_diff = (r - vi_r) * (r - vi_r) + + (g - vi_g) * (g - vi_g) + + (b - vi_b) * (b - vi_b); + + // Calculate "extra" diff + extra_diff = 0; + if( a > 0 ) + { + extra_diff += (a - vi_a) * (a - vi_a); + } + if( d > 0 ) + { + extra_diff += (d - vi_d) * (d - vi_d); + } + if( s > 0 ) + { + extra_diff += (s - vi_s) * (s - vi_s); + } + if( accum ) + { + extra_diff += (ar - vi_ar) * (ar - vi_ar) + + (ag - vi_ag) * (ag - vi_ag) + + (ab - vi_ab) * (ab - vi_ab) + + (aa - vi_aa) * (aa - vi_aa); + } + if( aux > 0 ) + { + extra_diff += (aux - vi_aux) * (aux - vi_aux); + } + if( samples > 0 ) + { + extra_diff += (samples - vi_samples) * (samples - vi_samples); + + } + // Check if this is a better match. We implement some + // complicated rules, by prioritizing in this order: + // 1) Visuals with the least number of missing buffers always + // have priority + // 2a) If (r,g,b)!=(0,0,0), color depth has priority over + // other buffers + // 2b) If (r,g,b)==(0,0,0), other buffers have priority over + // color depth + if( missing < best_missing ) + { + best_vis = i; + } + else if( missing == best_missing ) + { + if( color ) + { + if( (color_diff < best_color_diff) || + (color_diff == best_color_diff && + extra_diff < best_extra_diff) ) + { + best_vis = i; + } + } + else + { + if( (extra_diff < best_extra_diff) || + (extra_diff == best_extra_diff && + color_diff < best_color_diff) ) + { + best_vis = i; + } + } + } + if( best_vis == i ) + { + best_missing = missing; + best_color_diff = color_diff; + best_extra_diff = extra_diff; + } + } + } + + // Copy best visual to a visual to return + if( best_vis >= 0 ) + { + VI = XGetVisualInfo( Dpy, VisualIDMask, &VI_list[ best_vis ], + &nitems_return ); + } + else + { + VI = NULL; + } + + // Free visuals list + XFree( VI_list ); + + return VI; +} + + +//======================================================================== +// _glfwTranslateKey() - Translates an X Window key to internal coding +//======================================================================== + +static int _glfwTranslateKey( int keycode ) +{ + KeySym key, key_lc, key_uc; + + // Try secondary keysym, for numeric keypad keys + // Note: This way we always force "NumLock = ON", which at least + // enables GLFW users to detect numeric keypad keys + key = XKeycodeToKeysym( _glfwLibrary.Dpy, keycode, 1 ); + switch( key ) + { + // Numeric keypad + case XK_KP_0: return GLFW_KEY_KP_0; + case XK_KP_1: return GLFW_KEY_KP_1; + case XK_KP_2: return GLFW_KEY_KP_2; + case XK_KP_3: return GLFW_KEY_KP_3; + case XK_KP_4: return GLFW_KEY_KP_4; + case XK_KP_5: return GLFW_KEY_KP_5; + case XK_KP_6: return GLFW_KEY_KP_6; + case XK_KP_7: return GLFW_KEY_KP_7; + case XK_KP_8: return GLFW_KEY_KP_8; + case XK_KP_9: return GLFW_KEY_KP_9; + case XK_KP_Separator: + case XK_KP_Decimal: return GLFW_KEY_KP_DECIMAL; + case XK_KP_Equal: return GLFW_KEY_KP_EQUAL; + case XK_KP_Enter: return GLFW_KEY_KP_ENTER; + default: break; + } + + // Now try pimary keysym + key = XKeycodeToKeysym( _glfwLibrary.Dpy, keycode, 0 ); + switch( key ) + { + // Special keys (non character keys) + case XK_Escape: return GLFW_KEY_ESC; + case XK_Tab: return GLFW_KEY_TAB; + case XK_Shift_L: return GLFW_KEY_LSHIFT; + case XK_Shift_R: return GLFW_KEY_RSHIFT; + case XK_Control_L: return GLFW_KEY_LCTRL; + case XK_Control_R: return GLFW_KEY_RCTRL; + case XK_Meta_L: + case XK_Alt_L: return GLFW_KEY_LALT; + case XK_Mode_switch: // Mapped to Alt_R on many keyboards + case XK_Meta_R: + case XK_Alt_R: return GLFW_KEY_RALT; + case XK_KP_Delete: + case XK_Delete: return GLFW_KEY_DEL; + case XK_BackSpace: return GLFW_KEY_BACKSPACE; + case XK_Return: return GLFW_KEY_ENTER; + case XK_KP_Home: + case XK_Home: return GLFW_KEY_HOME; + case XK_KP_End: + case XK_End: return GLFW_KEY_END; + case XK_KP_Page_Up: + case XK_Page_Up: return GLFW_KEY_PAGEUP; + case XK_KP_Page_Down: + case XK_Page_Down: return GLFW_KEY_PAGEDOWN; + case XK_KP_Insert: + case XK_Insert: return GLFW_KEY_INSERT; + case XK_KP_Left: + case XK_Left: return GLFW_KEY_LEFT; + case XK_KP_Right: + case XK_Right: return GLFW_KEY_RIGHT; + case XK_KP_Down: + case XK_Down: return GLFW_KEY_DOWN; + case XK_KP_Up: + case XK_Up: return GLFW_KEY_UP; + case XK_F1: return GLFW_KEY_F1; + case XK_F2: return GLFW_KEY_F2; + case XK_F3: return GLFW_KEY_F3; + case XK_F4: return GLFW_KEY_F4; + case XK_F5: return GLFW_KEY_F5; + case XK_F6: return GLFW_KEY_F6; + case XK_F7: return GLFW_KEY_F7; + case XK_F8: return GLFW_KEY_F8; + case XK_F9: return GLFW_KEY_F9; + case XK_F10: return GLFW_KEY_F10; + case XK_F11: return GLFW_KEY_F11; + case XK_F12: return GLFW_KEY_F12; + case XK_F13: return GLFW_KEY_F13; + case XK_F14: return GLFW_KEY_F14; + case XK_F15: return GLFW_KEY_F15; + case XK_F16: return GLFW_KEY_F16; + case XK_F17: return GLFW_KEY_F17; + case XK_F18: return GLFW_KEY_F18; + case XK_F19: return GLFW_KEY_F19; + case XK_F20: return GLFW_KEY_F20; + case XK_F21: return GLFW_KEY_F21; + case XK_F22: return GLFW_KEY_F22; + case XK_F23: return GLFW_KEY_F23; + case XK_F24: return GLFW_KEY_F24; + case XK_F25: return GLFW_KEY_F25; + + // Numeric keypad (should have been detected in secondary keysym!) + case XK_KP_Divide: return GLFW_KEY_KP_DIVIDE; + case XK_KP_Multiply: return GLFW_KEY_KP_MULTIPLY; + case XK_KP_Subtract: return GLFW_KEY_KP_SUBTRACT; + case XK_KP_Add: return GLFW_KEY_KP_ADD; + case XK_KP_Equal: return GLFW_KEY_KP_EQUAL; + case XK_KP_Enter: return GLFW_KEY_KP_ENTER; + + // The rest (should be printable keys) + default: + // Make uppercase + XConvertCase( key, &key_lc, &key_uc ); + key = key_uc; + + // Valid ISO 8859-1 character? + if( (key >= 32 && key <= 126) || + (key >= 160 && key <= 255) ) + { + return (int) key; + } + return GLFW_KEY_UNKNOWN; + } +} + + +//======================================================================== +// _glfwTranslateChar() - Translates an X Window event to Unicode +//======================================================================== + +static int _glfwTranslateChar( XKeyEvent *event ) +{ + KeySym keysym; + + // Get X11 keysym + XLookupString( event, NULL, 0, &keysym, NULL ); + + // Convert to Unicode (see x11_keysym2unicode.c) + return (int) _glfwKeySym2Unicode( keysym ); +} + + + +//======================================================================== +// Get next X event (called by glfwPollEvents) +//======================================================================== + +static int _glfwGetNextEvent( void ) +{ + XEvent event, next_event; + + // Pull next event from event queue + XNextEvent( _glfwLibrary.Dpy, &event ); + + // Handle certain window messages + switch( event.type ) + { + // Is a key being pressed? + case KeyPress: + { + // Translate and report key press + _glfwInputKey( _glfwTranslateKey( event.xkey.keycode ), GLFW_PRESS ); + + // Translate and report character input + if( _glfwWin.CharCallback ) + { + _glfwInputChar( _glfwTranslateChar( &event.xkey ), GLFW_PRESS ); + } + break; + } + + // Is a key being released? + case KeyRelease: + { + // Do not report key releases for key repeats. For key repeats + // we will get KeyRelease/KeyPress pairs with identical time + // stamps. User selected key repeat filtering is handled in + // _glfwInputKey()/_glfwInputChar(). + if( XEventsQueued( _glfwLibrary.Dpy, QueuedAfterReading ) ) + { + XPeekEvent( _glfwLibrary.Dpy, &next_event ); + if( next_event.type == KeyPress && + next_event.xkey.window == event.xkey.window && + next_event.xkey.keycode == event.xkey.keycode && + next_event.xkey.time == event.xkey.time ) + { + // Do not report anything for this event + break; + } + } + + // Translate and report key release + _glfwInputKey( _glfwTranslateKey( event.xkey.keycode ), GLFW_RELEASE ); + + // Translate and report character input + if( _glfwWin.CharCallback ) + { + _glfwInputChar( _glfwTranslateChar( &event.xkey ), GLFW_RELEASE ); + } + break; + } + + // Were any of the mouse-buttons pressed? + case ButtonPress: + { + if( event.xbutton.button == Button1 ) + { + _glfwInputMouseClick( GLFW_MOUSE_BUTTON_LEFT, GLFW_PRESS ); + } + else if( event.xbutton.button == Button2 ) + { + _glfwInputMouseClick( GLFW_MOUSE_BUTTON_MIDDLE, GLFW_PRESS ); + } + else if( event.xbutton.button == Button3 ) + { + _glfwInputMouseClick( GLFW_MOUSE_BUTTON_RIGHT, GLFW_PRESS ); + } + + // XFree86 3.3.2 and later translates mouse wheel up/down into + // mouse button 4 & 5 presses + else if( event.xbutton.button == Button4 ) + { + _glfwInput.WheelPos++; // To verify: is this up or down? + if( _glfwWin.MouseWheelCallback ) + { + _glfwWin.MouseWheelCallback( _glfwInput.WheelPos ); + } + } + else if( event.xbutton.button == Button5 ) + { + _glfwInput.WheelPos--; + if( _glfwWin.MouseWheelCallback ) + { + _glfwWin.MouseWheelCallback( _glfwInput.WheelPos ); + } + } + break; + } + + // Were any of the mouse-buttons released? + case ButtonRelease: + { + if( event.xbutton.button == Button1 ) + { + _glfwInputMouseClick( GLFW_MOUSE_BUTTON_LEFT, + GLFW_RELEASE ); + } + else if( event.xbutton.button == Button2 ) + { + _glfwInputMouseClick( GLFW_MOUSE_BUTTON_MIDDLE, + GLFW_RELEASE ); + } + else if( event.xbutton.button == Button3 ) + { + _glfwInputMouseClick( GLFW_MOUSE_BUTTON_RIGHT, + GLFW_RELEASE ); + } + break; + } + + // Was the mouse moved? + case MotionNotify: + { + if( event.xmotion.x != _glfwInput.CursorPosX || + event.xmotion.y != _glfwInput.CursorPosY ) + { + if( _glfwWin.MouseLock ) + { + _glfwInput.MousePosX += event.xmotion.x - + _glfwInput.CursorPosX; + _glfwInput.MousePosY += event.xmotion.y - + _glfwInput.CursorPosY; + } + else + { + _glfwInput.MousePosX = event.xmotion.x; + _glfwInput.MousePosY = event.xmotion.y; + } + _glfwInput.CursorPosX = event.xmotion.x; + _glfwInput.CursorPosY = event.xmotion.y; + _glfwInput.MouseMoved = GL_TRUE; + + // Call user callback function + if( _glfwWin.MousePosCallback ) + { + _glfwWin.MousePosCallback( _glfwInput.MousePosX, + _glfwInput.MousePosY ); + } + } + break; + } + + // Was the window resized? + case ConfigureNotify: + { + if( event.xconfigure.width != _glfwWin.Width || + event.xconfigure.height != _glfwWin.Height ) + { + _glfwWin.Width = event.xconfigure.width; + _glfwWin.Height = event.xconfigure.height; + if( _glfwWin.WindowSizeCallback ) + { + _glfwWin.WindowSizeCallback( _glfwWin.Width, + _glfwWin.Height ); + } + } + break; + } + + // Was the window closed by the window manager? + case ClientMessage: + { + if( (Atom) event.xclient.data.l[ 0 ] == _glfwWin.WMDeleteWindow ) + { + return GL_TRUE; + } + + if( (Atom) event.xclient.data.l[ 0 ] == _glfwWin.WMPing ) + { + XSendEvent( _glfwLibrary.Dpy, + RootWindow( _glfwLibrary.Dpy, _glfwWin.VI->screen ), + False, SubstructureNotifyMask | SubstructureRedirectMask, &event ); + } + break; + } + + // Was the window mapped (un-iconified)? + case MapNotify: + _glfwWin.MapNotifyCount++; + break; + + // Was the window unmapped (iconified)? + case UnmapNotify: + _glfwWin.MapNotifyCount--; + break; + + // Was the window activated? + case FocusIn: + _glfwWin.FocusInCount++; + break; + + // Was the window de-activated? + case FocusOut: + _glfwWin.FocusInCount--; + break; + + // Was the window contents damaged? + case Expose: + { + // Call user callback function + if( _glfwWin.WindowRefreshCallback ) + { + _glfwWin.WindowRefreshCallback(); + } + break; + } + + // Was the window destroyed? + case DestroyNotify: + return GL_TRUE; + + default: + { +#if defined( _GLFW_HAS_XRANDR ) + switch( event.type - _glfwLibrary.XRandR.EventBase ) + { + case RRScreenChangeNotify: + { + // Show XRandR that we really care + XRRUpdateConfiguration( &event ); + break; + } + } +#endif + break; + } + } + + // The window was not destroyed + return GL_FALSE; +} + + +//======================================================================== +// _glfwCreateNULLCursor() - Create a blank cursor (for locked mouse mode) +//======================================================================== + +Cursor _glfwCreateNULLCursor( Display *display, Window root ) +{ + Pixmap cursormask; + XGCValues xgc; + GC gc; + XColor col; + Cursor cursor; + + cursormask = XCreatePixmap( display, root, 1, 1, 1 ); + xgc.function = GXclear; + gc = XCreateGC( display, cursormask, GCFunction, &xgc ); + XFillRectangle( display, cursormask, gc, 0, 0, 1, 1 ); + col.pixel = 0; + col.red = 0; + col.flags = 4; + cursor = XCreatePixmapCursor( display, cursormask, cursormask, + &col,&col, 0,0 ); + XFreePixmap( display, cursormask ); + XFreeGC( display, gc ); + + return cursor; +} + + +//======================================================================== +// _glfwInitGLXExtensions() - Initialize GLX-specific extensions +//======================================================================== + +static void _glfwInitGLXExtensions( void ) +{ + int has_swap_control; + + // Initialize OpenGL extension: GLX_SGI_swap_control + has_swap_control = _glfwPlatformExtensionSupported( + "GLX_SGI_swap_control" + ); + + if( has_swap_control ) + { + _glfwWin.SwapInterval = (GLXSWAPINTERVALSGI_T) + _glfw_glXGetProcAddress( (GLubyte*) "glXSwapIntervalSGI" ); + } + else + { + _glfwWin.SwapInterval = NULL; + } +} + + + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// _glfwPlatformOpenWindow() - Here is where the window is created, and +// the OpenGL rendering context is created +//======================================================================== + +int _glfwPlatformOpenWindow( int width, int height, int redbits, + int greenbits, int bluebits, int alphabits, int depthbits, + int stencilbits, int mode, _GLFWhints* hints ) +{ + Colormap cmap; + XSetWindowAttributes wa; + XEvent event; + Atom protocols[2]; + + // Clear platform specific GLFW window state + _glfwWin.VI = NULL; + _glfwWin.CX = (GLXContext)0; + _glfwWin.Win = (Window)0; + _glfwWin.Hints = NULL; + _glfwWin.PointerGrabbed = GL_FALSE; + _glfwWin.KeyboardGrabbed = GL_FALSE; + _glfwWin.OverrideRedirect = GL_FALSE; + _glfwWin.FS.ModeChanged = GL_FALSE; + _glfwWin.Saver.Changed = GL_FALSE; + _glfwWin.RefreshRate = hints->RefreshRate; + + // Fullscreen & screen saver settings + // Check if GLX is supported on this display + if( !glXQueryExtension( _glfwLibrary.Dpy, NULL, NULL ) ) + { + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + // Get screen ID for this window + _glfwWin.Scrn = _glfwLibrary.DefaultScreen; + + // Get an appropriate visual + _glfwWin.VI = _glfwChooseVisual( _glfwLibrary.Dpy, + _glfwWin.Scrn, + redbits, greenbits, bluebits, + alphabits, depthbits, stencilbits, + hints->AccumRedBits, hints->AccumGreenBits, + hints->AccumBlueBits, hints->AccumAlphaBits, + hints->AuxBuffers, hints->Samples, hints->Stereo ); + if( _glfwWin.VI == NULL ) + { + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + // Create a GLX context + _glfwWin.CX = glXCreateContext( _glfwLibrary.Dpy, _glfwWin.VI, 0, GL_TRUE ); + if( _glfwWin.CX == NULL ) + { + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + // Create a colormap + cmap = XCreateColormap( _glfwLibrary.Dpy, RootWindow( _glfwLibrary.Dpy, + _glfwWin.VI->screen), _glfwWin.VI->visual, AllocNone ); + + // Do we want fullscreen? + if( mode == GLFW_FULLSCREEN ) + { + // Change video mode + _glfwSetVideoMode( _glfwWin.Scrn, &_glfwWin.Width, + &_glfwWin.Height, &_glfwWin.RefreshRate ); + + // Remember old screen saver settings + XGetScreenSaver( _glfwLibrary.Dpy, &_glfwWin.Saver.Timeout, + &_glfwWin.Saver.Interval, &_glfwWin.Saver.Blanking, + &_glfwWin.Saver.Exposure ); + + // Disable screen saver + XSetScreenSaver( _glfwLibrary.Dpy, 0, 0, DontPreferBlanking, + DefaultExposures ); + } + + // Attributes for window + wa.colormap = cmap; + wa.border_pixel = 0; + wa.event_mask = StructureNotifyMask | KeyPressMask | KeyReleaseMask | + PointerMotionMask | ButtonPressMask | ButtonReleaseMask | + ExposureMask | FocusChangeMask | VisibilityChangeMask; + + // Create a window + _glfwWin.Win = XCreateWindow( + _glfwLibrary.Dpy, + RootWindow( _glfwLibrary.Dpy, _glfwWin.VI->screen ), + 0, 0, // Upper left corner + _glfwWin.Width, _glfwWin.Height, // Width, height + 0, // Borderwidth + _glfwWin.VI->depth, // Depth + InputOutput, + _glfwWin.VI->visual, + CWBorderPixel | CWColormap | CWEventMask, + &wa + ); + if( !_glfwWin.Win ) + { + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + // Get the delete window WM protocol atom + _glfwWin.WMDeleteWindow = XInternAtom( _glfwLibrary.Dpy, + "WM_DELETE_WINDOW", + False ); + + // Get the ping WM protocol atom + _glfwWin.WMPing = XInternAtom( _glfwLibrary.Dpy, "_NET_WM_PING", False ); + + protocols[0] = _glfwWin.WMDeleteWindow; + protocols[1] = _glfwWin.WMPing; + + // Allow us to trap the Window Close protocol + XSetWMProtocols( _glfwLibrary.Dpy, _glfwWin.Win, protocols, + sizeof(protocols) / sizeof(Atom) ); + + // Remove window decorations for fullscreen windows + if( mode == GLFW_FULLSCREEN ) + { + _glfwDisableDecorations(); + } + + _glfwWin.Hints = XAllocSizeHints(); + + if( hints->WindowNoResize ) + { + _glfwWin.Hints->flags |= (PMinSize | PMaxSize); + _glfwWin.Hints->min_width = _glfwWin.Hints->max_width = _glfwWin.Width; + _glfwWin.Hints->min_height = _glfwWin.Hints->max_height = _glfwWin.Height; + } + + if( mode == GLFW_FULLSCREEN ) + { + _glfwWin.Hints->flags |= PPosition; + _glfwWin.Hints->x = 0; + _glfwWin.Hints->y = 0; + } + + XSetWMNormalHints( _glfwLibrary.Dpy, _glfwWin.Win, _glfwWin.Hints ); + + // Map window + XMapWindow( _glfwLibrary.Dpy, _glfwWin.Win ); + + // Wait for map notification + XIfEvent( _glfwLibrary.Dpy, &event, _glfwWaitForMapNotify, + (char*)_glfwWin.Win ); + + // Make sure that our window ends up on top of things + XRaiseWindow( _glfwLibrary.Dpy, _glfwWin.Win ); + + // Fullscreen mode "post processing" + if( mode == GLFW_FULLSCREEN ) + { +#if defined( _GLFW_HAS_XRANDR ) + // Request screen change notifications + if( _glfwLibrary.XRandR.Available ) + { + XRRSelectInput( _glfwLibrary.Dpy, + _glfwWin.Win, + RRScreenChangeNotifyMask ); + } +#endif + + // Force window position/size (some WMs do their own window + // geometry, which we want to override) + XMoveWindow( _glfwLibrary.Dpy, _glfwWin.Win, 0, 0 ); + XResizeWindow( _glfwLibrary.Dpy, _glfwWin.Win, _glfwWin.Width, + _glfwWin.Height ); + + // Grab keyboard + if( XGrabKeyboard( _glfwLibrary.Dpy, _glfwWin.Win, True, + GrabModeAsync, GrabModeAsync, CurrentTime ) == + GrabSuccess ) + { + _glfwWin.KeyboardGrabbed = GL_TRUE; + } + + // Grab mouse cursor + if( XGrabPointer( _glfwLibrary.Dpy, _glfwWin.Win, True, + ButtonPressMask | ButtonReleaseMask | + PointerMotionMask, GrabModeAsync, GrabModeAsync, + _glfwWin.Win, None, CurrentTime ) == + GrabSuccess ) + { + _glfwWin.PointerGrabbed = GL_TRUE; + } + + // Try to get window inside viewport (for virtual displays) by + // moving the mouse cursor to the upper left corner (and then to + // the center) - this works for XFree86 + XWarpPointer( _glfwLibrary.Dpy, None, _glfwWin.Win, 0,0,0,0, 0,0 ); + XWarpPointer( _glfwLibrary.Dpy, None, _glfwWin.Win, 0,0,0,0, + _glfwWin.Width/2, _glfwWin.Height/2 ); + } + + // Set window & icon name + _glfwPlatformSetWindowTitle( "GLFW Window" ); + + // Connect the context to the window + glXMakeCurrent( _glfwLibrary.Dpy, _glfwWin.Win, _glfwWin.CX ); + + // Start by clearing the front buffer to black (avoid ugly desktop + // remains in our OpenGL window) + glClear( GL_COLOR_BUFFER_BIT ); + glXSwapBuffers( _glfwLibrary.Dpy, _glfwWin.Win ); + + // Initialize GLX-specific OpenGL extensions + _glfwInitGLXExtensions(); + + return GL_TRUE; +} + + +//======================================================================== +// Properly kill the window/video display +//======================================================================== + +void _glfwPlatformCloseWindow( void ) +{ +#if defined( _GLFW_HAS_XRANDR ) + XRRScreenConfiguration *sc; + Window root; +#endif + + // Free WM size hints + if( _glfwWin.Hints ) + { + XFree( _glfwWin.Hints ); + _glfwWin.Hints = NULL; + } + + // Do we have a rendering context? + if( _glfwWin.CX ) + { + // Release the context + glXMakeCurrent( _glfwLibrary.Dpy, None, NULL ); + + // Delete the context + glXDestroyContext( _glfwLibrary.Dpy, _glfwWin.CX ); + _glfwWin.CX = NULL; + } + + // Ungrab pointer and/or keyboard? + if( _glfwWin.KeyboardGrabbed ) + { + XUngrabKeyboard( _glfwLibrary.Dpy, CurrentTime ); + _glfwWin.KeyboardGrabbed = GL_FALSE; + } + if( _glfwWin.PointerGrabbed ) + { + XUngrabPointer( _glfwLibrary.Dpy, CurrentTime ); + _glfwWin.PointerGrabbed = GL_FALSE; + } + + // Do we have a window? + if( _glfwWin.Win ) + { + // Unmap the window + XUnmapWindow( _glfwLibrary.Dpy, _glfwWin.Win ); + + // Destroy the window + XDestroyWindow( _glfwLibrary.Dpy, _glfwWin.Win ); + _glfwWin.Win = (Window) 0; + } + + // Did we change the fullscreen resolution? + if( _glfwWin.FS.ModeChanged ) + { +#if defined( _GLFW_HAS_XRANDR ) + if( _glfwLibrary.XRandR.Available ) + { + root = RootWindow( _glfwLibrary.Dpy, _glfwWin.Scrn ); + sc = XRRGetScreenInfo( _glfwLibrary.Dpy, root ); + + XRRSetScreenConfig( _glfwLibrary.Dpy, + sc, + root, + _glfwWin.FS.OldSizeID, + _glfwWin.FS.OldRotation, + CurrentTime ); + + XRRFreeScreenConfigInfo( sc ); + } +#elif defined( _GLFW_HAS_XF86VIDMODE ) + if( _glfwLibrary.XF86VidMode.Available ) + { + // Unlock mode switch + XF86VidModeLockModeSwitch( _glfwLibrary.Dpy, + _glfwWin.Scrn, + 0 ); + + // Change the video mode back to the old mode + XF86VidModeSwitchToMode( _glfwLibrary.Dpy, + _glfwWin.Scrn, &_glfwWin.FS.OldMode ); + } +#endif + _glfwWin.FS.ModeChanged = GL_FALSE; + } + + // Did we change the screen saver setting? + if( _glfwWin.Saver.Changed ) + { + // Restore old screen saver settings + XSetScreenSaver( _glfwLibrary.Dpy, _glfwWin.Saver.Timeout, + _glfwWin.Saver.Interval, _glfwWin.Saver.Blanking, + _glfwWin.Saver.Exposure ); + _glfwWin.Saver.Changed = GL_FALSE; + } + + XSync( _glfwLibrary.Dpy, True ); +} + + +//======================================================================== +// _glfwPlatformSetWindowTitle() - Set the window title. +//======================================================================== + +void _glfwPlatformSetWindowTitle( const char *title ) +{ + // Set window & icon title + XStoreName( _glfwLibrary.Dpy, _glfwWin.Win, title ); + XSetIconName( _glfwLibrary.Dpy, _glfwWin.Win, title ); +} + + +//======================================================================== +// _glfwPlatformSetWindowSize() - Set the window size. +//======================================================================== + +void _glfwPlatformSetWindowSize( int width, int height ) +{ + int mode = 0, rate, sizechanged = GL_FALSE; + GLint drawbuffer; + GLfloat clearcolor[4]; + + rate = _glfwWin.RefreshRate; + + // If we are in fullscreen mode, get some info about the current mode + if( _glfwWin.Fullscreen ) + { + // Get closest match for target video mode + mode = _glfwGetClosestVideoMode( _glfwWin.Scrn, &width, &height, &rate ); + } + + if( _glfwWin.WindowNoResize ) + { + _glfwWin.Hints->min_width = _glfwWin.Hints->max_width = width; + _glfwWin.Hints->min_height = _glfwWin.Hints->max_height = height; + } + + XSetWMNormalHints( _glfwLibrary.Dpy, _glfwWin.Win, _glfwWin.Hints ); + + // Change window size before changing fullscreen mode? + if( _glfwWin.Fullscreen && (width > _glfwWin.Width) ) + { + XResizeWindow( _glfwLibrary.Dpy, _glfwWin.Win, width, height ); + sizechanged = GL_TRUE; + } + + // Change fullscreen video mode? + if( _glfwWin.Fullscreen ) + { + // Change video mode (keeping current rate) + _glfwSetVideoModeMODE( _glfwWin.Scrn, mode, _glfwWin.RefreshRate ); + + // Clear the front buffer to black (avoid ugly desktop remains in + // our OpenGL window) + glGetIntegerv( GL_DRAW_BUFFER, &drawbuffer ); + glGetFloatv( GL_COLOR_CLEAR_VALUE, clearcolor ); + glClearColor( 0.0f, 0.0f, 0.0f, 0.0f ); + glClear( GL_COLOR_BUFFER_BIT ); + if( drawbuffer == GL_BACK ) + { + glXSwapBuffers( _glfwLibrary.Dpy, _glfwWin.Win ); + } + glClearColor( clearcolor[0], clearcolor[1], clearcolor[2], + clearcolor[3] ); + } + + // Set window size (if not already changed) + if( !sizechanged ) + { + XResizeWindow( _glfwLibrary.Dpy, _glfwWin.Win, width, height ); + } +} + + +//======================================================================== +// _glfwPlatformSetWindowPos() - Set the window position. +//======================================================================== + +void _glfwPlatformSetWindowPos( int x, int y ) +{ + // Set window position + XMoveWindow( _glfwLibrary.Dpy, _glfwWin.Win, x, y ); +} + + +//======================================================================== +// _glfwPlatformIconfyWindow() - Window iconification +//======================================================================== + +void _glfwPlatformIconifyWindow( void ) +{ + // We can't do this for override redirect windows + if( _glfwWin.OverrideRedirect ) + { + return; + } + + // In fullscreen mode, we need to restore the desktop video mode + if( _glfwWin.Fullscreen ) + { +#if defined( _GLFW_HAS_XF86VIDMODE ) + if( _glfwLibrary.XF86VidMode.Available ) + { + // Unlock mode switch + XF86VidModeLockModeSwitch( _glfwLibrary.Dpy, + _glfwWin.Scrn, + 0 ); + + // Change the video mode back to the old mode + XF86VidModeSwitchToMode( _glfwLibrary.Dpy, + _glfwWin.Scrn, &_glfwWin.FS.OldMode ); + } +#endif + _glfwWin.FS.ModeChanged = GL_FALSE; + } + + // Show mouse pointer + if( _glfwWin.PointerHidden ) + { + XUndefineCursor( _glfwLibrary.Dpy, _glfwWin.Win ); + _glfwWin.PointerHidden = GL_FALSE; + } + + // Un-grab mouse pointer + if( _glfwWin.PointerGrabbed ) + { + XUngrabPointer( _glfwLibrary.Dpy, CurrentTime ); + _glfwWin.PointerGrabbed = GL_FALSE; + } + + // Iconify window + XIconifyWindow( _glfwLibrary.Dpy, _glfwWin.Win, + _glfwWin.Scrn ); + + // Window is now iconified + _glfwWin.Iconified = GL_TRUE; +} + + +//======================================================================== +// Window un-iconification +//======================================================================== + +void _glfwPlatformRestoreWindow( void ) +{ + // We can't do this for override redirect windows + if( _glfwWin.OverrideRedirect ) + { + return; + } + + // In fullscreen mode, change back video mode to user selected mode + if( _glfwWin.Fullscreen ) + { + _glfwSetVideoMode( _glfwWin.Scrn, + &_glfwWin.Width, &_glfwWin.Height, &_glfwWin.RefreshRate ); + } + + // Un-iconify window + XMapWindow( _glfwLibrary.Dpy, _glfwWin.Win ); + + // In fullscreen mode... + if( _glfwWin.Fullscreen ) + { + // Make sure window is in upper left corner + XMoveWindow( _glfwLibrary.Dpy, _glfwWin.Win, 0, 0 ); + + // Get input focus + XSetInputFocus( _glfwLibrary.Dpy, _glfwWin.Win, RevertToParent, + CurrentTime ); + } + + // Lock mouse, if necessary + if( _glfwWin.MouseLock ) + { + // Hide cursor + if( !_glfwWin.PointerHidden ) + { + XDefineCursor( _glfwLibrary.Dpy, _glfwWin.Win, + _glfwCreateNULLCursor( _glfwLibrary.Dpy, + _glfwWin.Win ) ); + _glfwWin.PointerHidden = GL_TRUE; + } + + // Grab cursor + if( !_glfwWin.PointerGrabbed ) + { + if( XGrabPointer( _glfwLibrary.Dpy, _glfwWin.Win, True, + ButtonPressMask | ButtonReleaseMask | + PointerMotionMask, GrabModeAsync, + GrabModeAsync, _glfwWin.Win, None, + CurrentTime ) == GrabSuccess ) + { + _glfwWin.PointerGrabbed = GL_TRUE; + } + } + } + + // Window is no longer iconified + _glfwWin.Iconified = GL_FALSE; +} + + +//======================================================================== +// _glfwPlatformSwapBuffers() - Swap buffers (double-buffering) and poll +// any new events. +//======================================================================== + +void _glfwPlatformSwapBuffers( void ) +{ + // Update display-buffer + glXSwapBuffers( _glfwLibrary.Dpy, _glfwWin.Win ); +} + + +//======================================================================== +// _glfwPlatformSwapInterval() - Set double buffering swap interval +//======================================================================== + +void _glfwPlatformSwapInterval( int interval ) +{ + if( _glfwWin.SwapInterval ) + { + _glfwWin.SwapInterval( interval ); + } +} + + +//======================================================================== +// _glfwPlatformRefreshWindowParams() +//======================================================================== + +void _glfwPlatformRefreshWindowParams( void ) +{ +#if defined( _GLFW_HAS_XRANDR ) + XRRScreenConfiguration *sc; +#elif defined( _GLFW_HAS_XF86VIDMODE ) + XF86VidModeModeLine modeline; + int dotclock; + float pixels_per_second, pixels_per_frame; +#endif + int sample_buffers; + + // AFAIK, there is no easy/sure way of knowing if OpenGL is hardware + // accelerated + _glfwWin.Accelerated = GL_TRUE; + + // "Standard" window parameters + glXGetConfig( _glfwLibrary.Dpy, _glfwWin.VI, GLX_RED_SIZE, + &_glfwWin.RedBits ); + glXGetConfig( _glfwLibrary.Dpy, _glfwWin.VI, GLX_GREEN_SIZE, + &_glfwWin.GreenBits ); + glXGetConfig( _glfwLibrary.Dpy, _glfwWin.VI, GLX_BLUE_SIZE, + &_glfwWin.BlueBits ); + glXGetConfig( _glfwLibrary.Dpy, _glfwWin.VI, GLX_ALPHA_SIZE, + &_glfwWin.AlphaBits ); + glXGetConfig( _glfwLibrary.Dpy, _glfwWin.VI, GLX_DEPTH_SIZE, + &_glfwWin.DepthBits ); + glXGetConfig( _glfwLibrary.Dpy, _glfwWin.VI, GLX_STENCIL_SIZE, + &_glfwWin.StencilBits ); + glXGetConfig( _glfwLibrary.Dpy, _glfwWin.VI, GLX_ACCUM_RED_SIZE, + &_glfwWin.AccumRedBits ); + glXGetConfig( _glfwLibrary.Dpy, _glfwWin.VI, GLX_ACCUM_GREEN_SIZE, + &_glfwWin.AccumGreenBits ); + glXGetConfig( _glfwLibrary.Dpy, _glfwWin.VI, GLX_ACCUM_BLUE_SIZE, + &_glfwWin.AccumBlueBits ); + glXGetConfig( _glfwLibrary.Dpy, _glfwWin.VI, GLX_ACCUM_ALPHA_SIZE, + &_glfwWin.AccumAlphaBits ); + glXGetConfig( _glfwLibrary.Dpy, _glfwWin.VI, GLX_AUX_BUFFERS, + &_glfwWin.AuxBuffers ); + + // Get stereo rendering setting + glXGetConfig( _glfwLibrary.Dpy, _glfwWin.VI, GLX_STEREO, + &_glfwWin.Stereo ); + _glfwWin.Stereo = _glfwWin.Stereo ? 1 : 0; + + // Get multisample buffer samples + glXGetConfig( _glfwLibrary.Dpy, _glfwWin.VI, GLX_SAMPLES, + &_glfwWin.Samples ); + glXGetConfig( _glfwLibrary.Dpy, _glfwWin.VI, GLX_SAMPLE_BUFFERS, + &sample_buffers ); + if( sample_buffers == 0 ) + _glfwWin.Samples = 0; + + // Default to refresh rate unknown (=0 according to GLFW spec) + _glfwWin.RefreshRate = 0; + + // Retrieve refresh rate, if possible +#if defined( _GLFW_HAS_XRANDR ) + if( _glfwLibrary.XRandR.Available ) + { + sc = XRRGetScreenInfo( _glfwLibrary.Dpy, + RootWindow( _glfwLibrary.Dpy, _glfwWin.Scrn ) ); + _glfwWin.RefreshRate = XRRConfigCurrentRate( sc ); + XRRFreeScreenConfigInfo( sc ); + } +#elif defined( _GLFW_HAS_XF86VIDMODE ) + if( _glfwLibrary.XF86VidMode.Available ) + { + // Use the XF86VidMode extension to get current video mode + XF86VidModeGetModeLine( _glfwLibrary.Dpy, _glfwWin.Scrn, + &dotclock, &modeline ); + pixels_per_second = 1000.0f * (float) dotclock; + pixels_per_frame = (float) modeline.htotal * modeline.vtotal; + _glfwWin.RefreshRate = (int)(pixels_per_second/pixels_per_frame+0.5); + } +#endif +} + + +//======================================================================== +// _glfwPlatformPollEvents() - Poll for new window and input events +//======================================================================== + +void _glfwPlatformPollEvents( void ) +{ + int winclosed = GL_FALSE; + + // Flag that the cursor has not moved + _glfwInput.MouseMoved = GL_FALSE; + + // Clear MapNotify and FocusIn counts + _glfwWin.MapNotifyCount = 0; + _glfwWin.FocusInCount = 0; + + // Use XSync to synchronise events to the X display. + // I don't know if this can have a serious performance impact. My + // benchmarks with a GeForce card under Linux shows no difference with + // or without XSync, but when the GL window is rendered over a slow + // network I have noticed bad event syncronisation problems when XSync + // is not used, so I decided to use it. + XSync( _glfwLibrary.Dpy, False ); + + // Empty the window event queue + while( XPending( _glfwLibrary.Dpy ) ) + { + if( _glfwGetNextEvent() ) + { + winclosed = GL_TRUE; + } + } + + // Did we get mouse movement in locked cursor mode? + if( _glfwInput.MouseMoved && _glfwWin.MouseLock ) + { + int maxx, minx, maxy, miny; + + // Calculate movement threshold + minx = _glfwWin.Width / 4; + maxx = (_glfwWin.Width * 3) / 4; + miny = _glfwWin.Height / 4; + maxy = (_glfwWin.Height * 3) / 4; + + // Did the mouse cursor move beyond our movement threshold + if(_glfwInput.CursorPosX < minx || _glfwInput.CursorPosX > maxx || + _glfwInput.CursorPosY < miny || _glfwInput.CursorPosY > maxy) + { + // Move the mouse pointer back to the window center so that it + // does not wander off... + _glfwPlatformSetMouseCursorPos( _glfwWin.Width/2, + _glfwWin.Height/2 ); + XSync( _glfwLibrary.Dpy, False ); + } + } + + // Was the window (un)iconified? + if( _glfwWin.MapNotifyCount < 0 && !_glfwWin.Iconified ) + { + // Show mouse pointer + if( _glfwWin.PointerHidden ) + { + XUndefineCursor( _glfwLibrary.Dpy, _glfwWin.Win ); + _glfwWin.PointerHidden = GL_FALSE; + } + + // Un-grab mouse pointer + if( _glfwWin.PointerGrabbed ) + { + XUngrabPointer( _glfwLibrary.Dpy, CurrentTime ); + _glfwWin.PointerGrabbed = GL_FALSE; + } + + _glfwWin.Iconified = GL_TRUE; + } + else if( _glfwWin.MapNotifyCount > 0 && _glfwWin.Iconified ) + { + // Restore fullscreen mode properties + if( _glfwWin.Fullscreen ) + { + // Change back video mode to user selected mode + _glfwSetVideoMode( _glfwWin.Scrn, &_glfwWin.Width, + &_glfwWin.Height, &_glfwWin.RefreshRate ); + + // Disable window manager decorations + _glfwEnableDecorations(); + + // Make sure window is in upper left corner + XMoveWindow( _glfwLibrary.Dpy, _glfwWin.Win, 0, 0 ); + + // Get input focus + XSetInputFocus( _glfwLibrary.Dpy, _glfwWin.Win, + RevertToParent, CurrentTime ); + } + + // Hide cursor if necessary + if( _glfwWin.MouseLock && !_glfwWin.PointerHidden ) + { + if( !_glfwWin.PointerHidden ) + { + XDefineCursor( _glfwLibrary.Dpy, _glfwWin.Win, + _glfwCreateNULLCursor( _glfwLibrary.Dpy, + _glfwWin.Win ) ); + _glfwWin.PointerHidden = GL_TRUE; + } + } + + // Grab cursor if necessary + if( (_glfwWin.MouseLock || _glfwWin.Fullscreen) && + !_glfwWin.PointerGrabbed ) + { + if( XGrabPointer( _glfwLibrary.Dpy, _glfwWin.Win, True, + ButtonPressMask | ButtonReleaseMask | + PointerMotionMask, GrabModeAsync, + GrabModeAsync, _glfwWin.Win, None, + CurrentTime ) == GrabSuccess ) + { + _glfwWin.PointerGrabbed = GL_TRUE; + } + } + + _glfwWin.Iconified = GL_FALSE; + } + + // Did the window get/lose focus + if( _glfwWin.FocusInCount > 0 && !_glfwWin.Active ) + { + // If we are in fullscreen mode, restore window + if( _glfwWin.Fullscreen && _glfwWin.Iconified ) + { + _glfwPlatformRestoreWindow(); + } + + // Window is now active + _glfwWin.Active = GL_TRUE; + } + else if( _glfwWin.FocusInCount < 0 && _glfwWin.Active ) + { + // If we are in fullscreen mode, iconfify window + if( _glfwWin.Fullscreen ) + { + _glfwPlatformIconifyWindow(); + } + + // Window is not active + _glfwWin.Active = GL_FALSE; + _glfwInputDeactivation(); + } + + // Was there a window close request? + if( winclosed && _glfwWin.WindowCloseCallback ) + { + // Check if the program wants us to close the window + winclosed = _glfwWin.WindowCloseCallback(); + } + if( winclosed ) + { + glfwCloseWindow(); + } +} + + +//======================================================================== +// _glfwPlatformWaitEvents() - Wait for new window and input events +//======================================================================== + +void _glfwPlatformWaitEvents( void ) +{ + XEvent event; + + // Wait for new events (blocking) + XNextEvent( _glfwLibrary.Dpy, &event ); + XPutBackEvent( _glfwLibrary.Dpy, &event ); + + // Poll events from queue + _glfwPlatformPollEvents(); +} + + +//======================================================================== +// _glfwPlatformHideMouseCursor() - Hide mouse cursor (lock it) +//======================================================================== + +void _glfwPlatformHideMouseCursor( void ) +{ + // Hide cursor + if( !_glfwWin.PointerHidden ) + { + XDefineCursor( _glfwLibrary.Dpy, _glfwWin.Win, + _glfwCreateNULLCursor( _glfwLibrary.Dpy, + _glfwWin.Win ) ); + _glfwWin.PointerHidden = GL_TRUE; + } + + // Grab cursor to user window + if( !_glfwWin.PointerGrabbed ) + { + if( XGrabPointer( _glfwLibrary.Dpy, _glfwWin.Win, True, + ButtonPressMask | ButtonReleaseMask | + PointerMotionMask, GrabModeAsync, GrabModeAsync, + _glfwWin.Win, None, CurrentTime ) == + GrabSuccess ) + { + _glfwWin.PointerGrabbed = GL_TRUE; + } + } +} + + +//======================================================================== +// _glfwPlatformShowMouseCursor() - Show mouse cursor (unlock it) +//======================================================================== + +void _glfwPlatformShowMouseCursor( void ) +{ + // Un-grab cursor (only in windowed mode: in fullscreen mode we still + // want the mouse grabbed in order to confine the cursor to the window + // area) + if( _glfwWin.PointerGrabbed && !_glfwWin.Fullscreen ) + { + XUngrabPointer( _glfwLibrary.Dpy, CurrentTime ); + _glfwWin.PointerGrabbed = GL_FALSE; + } + + // Show cursor + if( _glfwWin.PointerHidden ) + { + XUndefineCursor( _glfwLibrary.Dpy, _glfwWin.Win ); + _glfwWin.PointerHidden = GL_FALSE; + } +} + + +//======================================================================== +// _glfwPlatformSetMouseCursorPos() - Set physical mouse cursor position +//======================================================================== + +void _glfwPlatformSetMouseCursorPos( int x, int y ) +{ + // Change cursor position + _glfwInput.CursorPosX = x; + _glfwInput.CursorPosY = y; + XWarpPointer( _glfwLibrary.Dpy, None, _glfwWin.Win, 0,0,0,0, x, y ); +} + |