From cf282699120a05c4dc501d7383fad4a7dcc3cb2e Mon Sep 17 00:00:00 2001 From: Mark Cannon Date: Wed, 14 May 2008 04:10:57 +0000 Subject: [PATCH] Backported + changed LowLevelWindow_X11 and InputHandler_X11, updated text files, updated copyright notices in io folder git-svn-id: https://openitg.svn.sourceforge.net/svnroot/openitg@315 83fadc84-e282-4d84-a09a-c4228d6ae7e5 --- ToDo.txt | 5 +- changelog.txt | 4 +- src/EnumHelper.h | 7 + src/RageDisplay_OGL.cpp | 10 +- src/arch/InputHandler/InputHandler.cpp | 2 + src/arch/InputHandler/InputHandler_X11.cpp | 233 ++++++++++++---------- src/arch/InputHandler/InputHandler_X11.h | 9 +- src/arch/LowLevelWindow/LowLevelWindow_X11.cpp | 260 +++++++++++++++++++------ src/arch/LowLevelWindow/LowLevelWindow_X11.h | 4 +- src/archutils/Unix/X11Helper.cpp | 146 ++++---------- src/archutils/Unix/X11Helper.h | 36 ++-- src/io/PIUIO.cpp | 2 +- src/io/PIUIO.h | 2 +- src/io/USBDevice.h | 2 +- src/io/USBDriver.h | 2 +- 15 files changed, 410 insertions(+), 314 deletions(-) diff --git a/ToDo.txt b/ToDo.txt index 33713ce3..f49727dd 100644 --- a/ToDo.txt +++ b/ToDo.txt @@ -1,17 +1,15 @@ /* More-or-less in order of priority. */ /* Major bug fixing */ --"Revert from Disk" adds charts +-X11 full-screen causes scrolling brackets + desktop resize -Switching from free to home on the main menu causes OpenITG to hang /* Things to test on the arcade */ -See if separate coin counters have separate bit mappings /* Minor bug fixing */ --The next combo after a miss is 1 more than it should be (fixed 5/10/08) -Banner custom doesn't always show in ScreenRanking -Edit mode eats Edit difficulty charts --http://boxorroxors.net/forum/viewtopic.php?p=7044#7044 (course bug) (fixed 5/10/08) -"Random" selections for non-existant BGVids always return the same video /* Minor feature additions */ @@ -22,7 +20,6 @@ -Implement colors percentages in Versus to show who's ahead /* Major feature additions */ --Backport or update LowLevelWindow_X11 to include full-screen support -Implement custom courses from USB drive -Implement "lifebar graph shows FFC/FEC" -Improve code behind ITG2's beginner helper diff --git a/changelog.txt b/changelog.txt index 6e46d8d2..cda518c1 100755 --- a/changelog.txt +++ b/changelog.txt @@ -2,10 +2,12 @@ OpenITG, alpha 6 (in development) --------------------------------- -Code structure changes: Reverted InputFilter - too little gain for too many problems + Backported and modified 4.0's X11 code (Linux window/input) -Fixed bugs: - Repeating menu input error on ScreenSelectMusic Some custom songs end immediately after start + Repeating menu input error on ScreenSelectMusic Editor doesn't draw properly, causes failed asserts + "Revert from Disk" in editor causes duplicate charts, crashes OpenITG, alpha 5 (April 30th, 2008) ----------------------------------- diff --git a/src/EnumHelper.h b/src/EnumHelper.h index 8af84a2a..27aeadc7 100755 --- a/src/EnumHelper.h +++ b/src/EnumHelper.h @@ -32,6 +32,13 @@ static inline void enum_add( T &val, int iAmt ) val = c.value; } +template +static inline T enum_add2( T val, int iAmt ) +{ + return static_cast( val + iAmt ); +} + + #define FOREACH_ENUM( e, max, var ) for( e var=(e)0; var( var, +1 ) ) diff --git a/src/RageDisplay_OGL.cpp b/src/RageDisplay_OGL.cpp index adbb3b2c..19c3f8df 100755 --- a/src/RageDisplay_OGL.cpp +++ b/src/RageDisplay_OGL.cpp @@ -304,8 +304,10 @@ static void LogGLXDebugInformation() #if defined(UNIX) ASSERT( g_X11Display ); +#if 0 const int scr = DefaultScreen( g_X11Display ); + // Much more appropriate in LowLevelWindow_X11 LOG->Info( "Display: %s (screen %i)", DisplayString(g_X11Display), scr ); LOG->Info( "Direct rendering: %s", glXIsDirect( g_X11Display, glXGetCurrentContext() )? "yes":"no" ); @@ -319,6 +321,8 @@ static void LogGLXDebugInformation() LOG->Info( "Server GLX vendor: %s [%s]", glXQueryServerString( g_X11Display, scr, GLX_VENDOR ), glXQueryServerString( g_X11Display, scr, GLX_VERSION ) ); LOG->Info( "Client GLX vendor: %s [%s]", glXGetClientString( g_X11Display, GLX_VENDOR ), glXGetClientString( g_X11Display, GLX_VERSION ) ); #endif + +#endif } RageDisplay_OGL::RageDisplay_OGL() @@ -1175,6 +1179,7 @@ void RageCompiledGeometryHWOGL::Draw( int iMeshIndex ) const else { glDisableClientState(GL_NORMAL_ARRAY); + AssertNoGLError(); } if( m_bNeedsTextureMatrixScale && g_bTextureMatrixShader != 0 ) @@ -1190,10 +1195,13 @@ void RageCompiledGeometryHWOGL::Draw( int iMeshIndex ) const AssertNoGLError(); GLExt.glUseProgramObjectARB( g_bTextureMatrixShader ); + // XXX: This causes the scrolling brackets problem, but avoids a crash. +// AssertNoGLError(); + FlushGLErrors(); } GLExt.glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, m_nTriangles ); - AssertNoGLError(); +// AssertNoGLError(); #define BUFFER_OFFSET(o) ((char*)(o)) diff --git a/src/arch/InputHandler/InputHandler.cpp b/src/arch/InputHandler/InputHandler.cpp index 3d7408d9..ff6b3f67 100755 --- a/src/arch/InputHandler/InputHandler.cpp +++ b/src/arch/InputHandler/InputHandler.cpp @@ -12,6 +12,8 @@ void InputHandler::UpdateTimer() void InputHandler::ButtonPressed( DeviceInput di, bool Down ) { + //LOG->Debug( "%s %s", di.toString().c_str(), Down ? "pressed" : "released" ); + if( di.ts.IsZero() ) { di.ts = m_LastUpdate.Half(); diff --git a/src/arch/InputHandler/InputHandler_X11.cpp b/src/arch/InputHandler/InputHandler_X11.cpp index dfc1f570..3749ac17 100755 --- a/src/arch/InputHandler/InputHandler_X11.cpp +++ b/src/arch/InputHandler/InputHandler_X11.cpp @@ -3,15 +3,19 @@ #include "RageUtil.h" #include "RageLog.h" #include "RageDisplay.h" +#include "InputFilter.h" +#include "EnumHelper.h" #include "archutils/Unix/X11Helper.h" #include #include -static RageKeySym XSymToKeySym( int key ) +using namespace X11Helper; + +static DeviceButton XSymToDeviceButton( int key ) { -#define KEY_INV KEY_INVALID - const RageKeySym ASCIIKeySyms[] = +#define KEY_INV DEVICE_BUTTON_INVALID + static const DeviceButton ASCIIKeySyms[] = { KEY_INV , KEY_INV , KEY_INV , KEY_INV , KEY_INV , /* 0 - 4 */ KEY_INV , KEY_INV , KEY_INV , KEY_BACK , KEY_TAB , /* 5 - 9 */ @@ -41,145 +45,162 @@ static RageKeySym XSymToKeySym( int key ) KEY_RBRACE , KEY_INV , KEY_DEL /* 125 - 127 */ }; + /* 0...31: */ + if( key >= 0xFF00 && key < 0xFF20 ) + return ASCIIKeySyms[key & 0xFF]; + /* 32...127: */ if( key < int(ARRAYSIZE(ASCIIKeySyms))) return ASCIIKeySyms[key]; /* XK_KP_0 ... XK_KP_9 to KEY_KP_C0 ... KEY_KP_C9 */ if( key >= XK_KP_0 && key <= XK_KP_9 ) - return (RageKeySym) (key - XK_KP_0 + KEY_KP_C0); + return enum_add2(KEY_KP_C0, key - XK_KP_0); switch( key ) { - /* These are needed because of the way X registers - the keypad. */ - case XK_KP_Insert: return KEY_KP_C0; - case XK_KP_End: return KEY_KP_C1; - case XK_KP_Down: return KEY_KP_C2; - case XK_KP_Page_Down: return KEY_KP_C3; - case XK_KP_Left: return KEY_KP_C4; - case XK_KP_Begin: return KEY_KP_C5; - case XK_KP_Right: return KEY_KP_C6; - case XK_KP_Home: return KEY_KP_C7; - case XK_KP_Up: return KEY_KP_C8; - case XK_KP_Page_Up: return KEY_KP_C9; - case XK_KP_Decimal: return KEY_KP_PERIOD; - case XK_KP_Divide: return KEY_KP_SLASH; - case XK_KP_Multiply: return KEY_KP_ASTERISK; - case XK_KP_Subtract: return KEY_KP_HYPHEN; - case XK_KP_Add: return KEY_KP_PLUS; - case XK_KP_Equal: return KEY_KP_EQUAL; - case XK_KP_Enter: return KEY_KP_ENTER; - case XK_Up: return KEY_UP; - case XK_Down: return KEY_DOWN; - case XK_Right: return KEY_RIGHT; - case XK_Left: return KEY_LEFT; - case XK_Insert: return KEY_INSERT; - case XK_Home: return KEY_HOME; - case XK_Delete: return KEY_DEL; - case XK_End: return KEY_END; - case XK_Page_Up: return KEY_PGUP; - case XK_Page_Down: return KEY_PGDN; - case XK_F1: return KEY_F1; - case XK_F2: return KEY_F2; - case XK_F3: return KEY_F3; - case XK_F4: return KEY_F4; - case XK_F5: return KEY_F5; - case XK_F6: return KEY_F6; - case XK_F7: return KEY_F7; - case XK_F8: return KEY_F8; - case XK_F9: return KEY_F9; - case XK_F10: return KEY_F10; - case XK_F11: return KEY_F11; - case XK_F12: return KEY_F12; - case XK_F13: return KEY_F13; - case XK_F14: return KEY_F14; - case XK_F15: return KEY_F15; - - case XK_Num_Lock: return KEY_NUMLOCK; - case XK_Caps_Lock: return KEY_CAPSLOCK; - case XK_Scroll_Lock: return KEY_SCRLLOCK; - case XK_Return: return KEY_ENTER; - case XK_Sys_Req: return KEY_PRTSC; - case XK_Print: return KEY_PRTSC; - case XK_Shift_R: return KEY_RSHIFT; - case XK_Shift_L: return KEY_LSHIFT; - case XK_Control_R: return KEY_RCTRL; - case XK_Control_L: return KEY_LCTRL; - case XK_Alt_R: return KEY_RALT; - case XK_Alt_L: return KEY_LALT; - case XK_Meta_R: return KEY_RMETA; - case XK_Meta_L: return KEY_LMETA; - case XK_Super_L: return KEY_LSUPER; - case XK_Super_R: return KEY_RSUPER; - case XK_Menu: return KEY_MENU; + /* These are needed because of the way X registers the keypad. */ + case XK_KP_Insert: return KEY_KP_C0; + case XK_KP_End: return KEY_KP_C1; + case XK_KP_Down: return KEY_KP_C2; + case XK_KP_Page_Down: return KEY_KP_C3; + case XK_KP_Left: return KEY_KP_C4; + case XK_KP_Begin: return KEY_KP_C5; + case XK_KP_Right: return KEY_KP_C6; + case XK_KP_Home: return KEY_KP_C7; + case XK_KP_Up: return KEY_KP_C8; + case XK_KP_Page_Up: return KEY_KP_C9; + case XK_KP_Decimal: return KEY_KP_PERIOD; + case XK_KP_Divide: return KEY_KP_SLASH; + case XK_KP_Multiply: return KEY_KP_ASTERISK; + case XK_KP_Subtract: return KEY_KP_HYPHEN; + case XK_KP_Add: return KEY_KP_PLUS; + case XK_KP_Equal: return KEY_KP_EQUAL; + case XK_KP_Enter: return KEY_KP_ENTER; + case XK_Up: return KEY_UP; + case XK_Down: return KEY_DOWN; + case XK_Right: return KEY_RIGHT; + case XK_Left: return KEY_LEFT; + case XK_Insert: return KEY_INSERT; + case XK_Home: return KEY_HOME; + case XK_Delete: return KEY_DEL; + case XK_End: return KEY_END; + case XK_Page_Up: return KEY_PGUP; + case XK_Page_Down: return KEY_PGDN; + case XK_F1: return KEY_F1; + case XK_F2: return KEY_F2; + case XK_F3: return KEY_F3; + case XK_F4: return KEY_F4; + case XK_F5: return KEY_F5; + case XK_F6: return KEY_F6; + case XK_F7: return KEY_F7; + case XK_F8: return KEY_F8; + case XK_F9: return KEY_F9; + case XK_F10: return KEY_F10; + case XK_F11: return KEY_F11; + case XK_F12: return KEY_F12; + case XK_F13: return KEY_F13; + case XK_F14: return KEY_F14; + case XK_F15: return KEY_F15; + + case XK_Num_Lock: return KEY_NUMLOCK; + case XK_Caps_Lock: return KEY_CAPSLOCK; + case XK_Scroll_Lock: return KEY_SCRLLOCK; + case XK_Return: return KEY_ENTER; + case XK_Sys_Req: return KEY_PRTSC; + case XK_Print: return KEY_PRTSC; + case XK_Shift_R: return KEY_RSHIFT; + case XK_Shift_L: return KEY_LSHIFT; + case XK_Control_R: return KEY_RCTRL; + case XK_Control_L: return KEY_LCTRL; + case XK_Alt_R: return KEY_RALT; + case XK_Alt_L: return KEY_LALT; + case XK_Meta_R: return KEY_RMETA; + case XK_Meta_L: return KEY_LMETA; + case XK_Super_L: return KEY_LSUPER; + case XK_Super_R: return KEY_RSUPER; + case XK_Menu: return KEY_MENU; } - /* 0...31: */ - if( key - 0xFF00 < 0x20) - return ASCIIKeySyms[key - 0xFF00]; - - return KEY_INVALID; + return DEVICE_BUTTON_INVALID; } InputHandler_X11::InputHandler_X11() { - XKeyboardControl state; - state.auto_repeat_mode = AutoRepeatModeOff; - XChangeKeyboardControl(X11Helper::Dpy,KBAutoRepeatMode,&state); - X11Helper::Go(); - X11Helper::OpenMask(KeyPressMask); X11Helper::OpenMask(KeyReleaseMask); + if( Dpy == NULL || Win == None ) + return; + XWindowAttributes winAttrib; + + XGetWindowAttributes( Dpy, Win, &winAttrib ); + XSelectInput( Dpy, Win, winAttrib.your_event_mask | KeyPressMask | KeyReleaseMask ); } InputHandler_X11::~InputHandler_X11() { - XKeyboardControl state; - state.auto_repeat_mode = AutoRepeatModeDefault; - XChangeKeyboardControl(X11Helper::Dpy,KBAutoRepeatMode,&state); - X11Helper::CloseMask(KeyPressMask); X11Helper::CloseMask(KeyReleaseMask); - X11Helper::Stop(); + if( Dpy == NULL || Win == None ) + return; + XWindowAttributes winAttrib; + + XGetWindowAttributes( Dpy, Win, &winAttrib ); + XSelectInput( Dpy, Win, winAttrib.your_event_mask & ~(KeyPressMask|KeyReleaseMask) ); } -void InputHandler_X11::Update(float fDeltaTime) +void InputHandler_X11::Update( float fDeltaTime ) { - XEvent event; + if( Dpy == NULL || Win == None ) + { + InputHandler::UpdateTimer(); + return; + } - if (X11Helper::Win) - while(XCheckTypedWindowEvent(X11Helper::Dpy, - X11Helper::Win, KeyPress, &event) ) - { - LOG->Trace("key: sym %i, key %i, state true", - XLookupKeysym(&event.xkey,0), XSymToKeySym(XLookupKeysym(&event.xkey,0))); + XEvent event, lastEvent; + DeviceButton lastDB = DEVICE_BUTTON_INVALID; + lastEvent.type = 0; - DeviceInput di( DEVICE_KEYBOARD, - XSymToKeySym(XLookupKeysym(&event.xkey,0)) ); - ButtonPressed(di, true); - } - while(XCheckTypedWindowEvent(X11Helper::Dpy, - X11Helper::Win, KeyRelease, &event) ) + while( XCheckWindowEvent(Dpy, Win, KeyPressMask | KeyReleaseMask, &event) ) + { + const bool bPress = event.type == KeyPress; + if( lastEvent.type != 0 ) { - LOG->Trace("key: sym %i, key %i, state false", - XLookupKeysym(&event.xkey,0), XSymToKeySym(XLookupKeysym(&event.xkey,0))); - - DeviceInput di( DEVICE_KEYBOARD, - XSymToKeySym(XLookupKeysym(&event.xkey,0)) ); - ButtonPressed(di, false); - + if( bPress && event.xkey.time == lastEvent.xkey.time && + event.xkey.keycode == lastEvent.xkey.keycode ) + { + // This is a repeat event so ignore it. + lastEvent.type = 0; + continue; + } + // This is a new event so the last release was not a repeat. + ButtonPressed( DeviceInput(DEVICE_KEYBOARD, lastDB), false ); + lastEvent.type = 0; } - + // Why only the zero index? + lastDB = XSymToDeviceButton( XLookupKeysym(&event.xkey, 0) ); + if( lastDB == DEVICE_BUTTON_INVALID ) + continue; + + if( bPress ) + ButtonPressed( DeviceInput(DEVICE_KEYBOARD, lastDB), true ); + else + lastEvent = event; + } + // Handle any last releases. + if( lastEvent.type != 0 ) + ButtonPressed( DeviceInput(DEVICE_KEYBOARD, lastDB), false ); InputHandler::UpdateTimer(); } -void InputHandler_X11::GetDevicesAndDescriptions( - vector& vDevicesOut, vector& vDescriptionsOut) +void InputHandler_X11::GetDevicesAndDescriptions( vector& vDevicesOut, vector& vDescriptionsOut ) { + if( !Dpy || !Win ) + return; + vDevicesOut.push_back( DEVICE_KEYBOARD ); vDescriptionsOut.push_back( "Keyboard" ); } /* - * (c) 2005 Sean Burke, Ben Anderson + * (c) 2005, 2006 Sean Burke, Ben Anderson, Steve Checkoway * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a diff --git a/src/arch/InputHandler/InputHandler_X11.h b/src/arch/InputHandler/InputHandler_X11.h index 45959e2f..b0631269 100755 --- a/src/arch/InputHandler/InputHandler_X11.h +++ b/src/arch/InputHandler/InputHandler_X11.h @@ -1,8 +1,8 @@ +/* InputHandler_X11 - X-based keyboard input handler. */ + #ifndef INPUT_HANDLER_X11_H #define INPUT_HANDLER_X11_H -/* Get keyboard (and possibly pointer in the future) input through X. */ - #include "InputHandler.h" class InputHandler_X11: public InputHandler @@ -10,9 +10,10 @@ class InputHandler_X11: public InputHandler public: InputHandler_X11(); ~InputHandler_X11(); - void Update(float fDeltaTime); - void GetDevicesAndDescriptions(vector& vDevicesOut, vector& vDescriptionsOut); + void Update( float fDeltaTime ); + void GetDevicesAndDescriptions( vector& vDevicesOut, vector& vDescriptionsOut ); }; + #define USE_INPUT_HANDLER_X11 #endif diff --git a/src/arch/LowLevelWindow/LowLevelWindow_X11.cpp b/src/arch/LowLevelWindow/LowLevelWindow_X11.cpp index 8691fea8..f874cc9a 100755 --- a/src/arch/LowLevelWindow/LowLevelWindow_X11.cpp +++ b/src/arch/LowLevelWindow/LowLevelWindow_X11.cpp @@ -3,12 +3,27 @@ #include "RageLog.h" #include "RageException.h" #include "archutils/Unix/X11Helper.h" +#include "PrefsManager.h" // XXX + +using namespace X11Helper; #include #include // ceil() #define GLX_GLXEXT_PROTOTYPES #include // All sorts of stuff... +#include #include +#include + +#if defined(HAVE_LIBXTST) +#include +#endif + +static GLXContext g_pContext = NULL; +static GLXContext g_pBackgroundContext = NULL; +static Rotation g_OldRotation; +static int g_iOldSize; +XRRScreenConfiguration *g_pScreenConfig = NULL; // XXX HACK: RageDisplay_OGL is expecting us to set this for it so it can do // GLX-specific queries and whatnot. It's one ugly hackish mess, but hey, @@ -17,18 +32,56 @@ extern Display *g_X11Display; LowLevelWindow_X11::LowLevelWindow_X11() { - m_bWindowIsOpen = false; g_X11Display = NULL; - if( !X11Helper::Go() ) - { + if( !OpenXConnection() ) RageException::Throw( "Failed to establish a connection with the X server." ); - } - g_X11Display = X11Helper::Dpy; + + g_X11Display = Dpy; + + const int iScreen = DefaultScreen( Dpy ); + + LOG->Info( "Display: %s (screen %i)", DisplayString(Dpy), iScreen ); + LOG->Info( "Direct rendering: %s", glXIsDirect( Dpy, glXGetCurrentContext() )? "yes":"no" ); + + int iXServerVersion = XVendorRelease( Dpy ); /* eg. 40201001 */ + int iMajor = iXServerVersion / 10000000; iXServerVersion %= 10000000; + int iMinor = iXServerVersion / 100000; iXServerVersion %= 100000; + int iRevision = iXServerVersion / 1000; iXServerVersion %= 1000; + int iPatch = iXServerVersion; + + LOG->Info( "X server vendor: %s [%i.%i.%i.%i]", XServerVendor( Dpy ), iMajor, iMinor, iRevision, iPatch ); + LOG->Info( "Server GLX vendor: %s [%s]", glXQueryServerString( Dpy, iScreen, GLX_VENDOR ), glXQueryServerString( Dpy, iScreen, GLX_VERSION ) ); + LOG->Info( "Client GLX vendor: %s [%s]", glXGetClientString( Dpy, GLX_VENDOR ), glXGetClientString( Dpy, GLX_VERSION ) ); + + m_bWasWindowed = true; + g_pScreenConfig = XRRGetScreenInfo( Dpy, RootWindow(Dpy, DefaultScreen(Dpy)) ); } LowLevelWindow_X11::~LowLevelWindow_X11() { - X11Helper::Stop(); // Xlib cleans up the window for us + // Reset the display + if( !m_bWasWindowed ) + { + XRRSetScreenConfig( Dpy, g_pScreenConfig, RootWindow(Dpy, DefaultScreen(Dpy)), g_iOldSize, g_OldRotation, CurrentTime ); + + XUngrabKeyboard( Dpy, CurrentTime ); + } + if( g_pContext ) + { + glXDestroyContext( Dpy, g_pContext ); + g_pContext = NULL; + } + if( g_pBackgroundContext ) + { + glXDestroyContext( Dpy, g_pBackgroundContext ); + g_pBackgroundContext = NULL; + } + XRRFreeScreenConfigInfo( g_pScreenConfig ); + g_pScreenConfig = NULL; + + XDestroyWindow( Dpy, Win ); + Win = None; + CloseXConnection(); } void *LowLevelWindow_X11::GetProcAddress( CString s ) @@ -41,28 +94,21 @@ void *LowLevelWindow_X11::GetProcAddress( CString s ) CString LowLevelWindow_X11::TryVideoMode( RageDisplay::VideoModeParams p, bool &bNewDeviceOut ) { -#if defined(LINUX) - /* nVidia cards: +#if defined(UNIX) + /* + * nVidia cards: * * This only works the first time we set up a window; after that, the * drivers appear to cache the value, so you have to actually restart - * the program to change it again. */ + * the program to change it again. + */ static char buf[128]; strcpy( buf, "__GL_SYNC_TO_VBLANK=" ); strcat( buf, p.vsync?"1":"0" ); putenv( buf ); #endif - XSizeHints hints; - XEvent ev; - stack otherEvs; - - // XXX: LLW_SDL allows the window to be resized. Do we really want to? - hints.flags = PMinSize | PMaxSize | PBaseSize; - hints.min_width = hints.max_width = hints.base_width = p.width; - hints.min_height = hints.max_height = hints.base_height = p.height; - - if( !m_bWindowIsOpen || p.bpp != CurrentParams.bpp ) + if( g_pContext == NULL || p.bpp != CurrentParams.bpp || m_bWasWindowed != p.windowed ) { // Different depth, or we didn't make a window before. New context. bNewDeviceOut = true; @@ -70,6 +116,7 @@ CString LowLevelWindow_X11::TryVideoMode( RageDisplay::VideoModeParams p, bool & int visAttribs[32]; int i = 0; ASSERT( p.bpp == 16 || p.bpp == 32 ); + if( p.bpp == 32 ) { visAttribs[i++] = GLX_RED_SIZE; visAttribs[i++] = 8; @@ -89,53 +136,42 @@ CString LowLevelWindow_X11::TryVideoMode( RageDisplay::VideoModeParams p, bool & visAttribs[i++] = None; - XVisualInfo *xvi = glXChooseVisual( X11Helper::Dpy, DefaultScreen(X11Helper::Dpy), visAttribs ); - + XVisualInfo *xvi = glXChooseVisual( Dpy, DefaultScreen(Dpy), visAttribs ); if( xvi == NULL ) - { return "No visual available for that depth."; - } - /* Enable StructureNotifyMask, so we receive a MapNotify for the following XMapWindow. */ - X11Helper::OpenMask( StructureNotifyMask ); - - if( !X11Helper::MakeWindow(xvi->screen, xvi->depth, xvi->visual, p.width, p.height) ) - { + // I get strange behavior if I add override redirect after creating the window. + // So, let's recreate the window when changing that state. + if( !MakeWindow(Win, xvi->screen, xvi->depth, xvi->visual, p.width, p.height, !p.windowed) ) return "Failed to create the window."; - } - m_bWindowIsOpen = true; - + char *szWindowTitle = const_cast( p.sWindowTitle.c_str() ); - XChangeProperty( g_X11Display, X11Helper::Win, XA_WM_NAME, XA_STRING, 8, PropModeReplace, + XChangeProperty( Dpy, Win, XA_WM_NAME, XA_STRING, 8, PropModeReplace, reinterpret_cast(szWindowTitle), strlen(szWindowTitle) ); - GLXContext ctxt = glXCreateContext(X11Helper::Dpy, xvi, NULL, True); + if( g_pContext ) + glXDestroyContext( Dpy, g_pContext ); + if( g_pBackgroundContext ) + glXDestroyContext( Dpy, g_pBackgroundContext ); + g_pContext = glXCreateContext( Dpy, xvi, NULL, True ); + g_pBackgroundContext = glXCreateContext( Dpy, xvi, g_pContext, True ); - glXMakeCurrent( X11Helper::Dpy, X11Helper::Win, ctxt ); + glXMakeCurrent( Dpy, Win, g_pContext ); - XMapWindow( X11Helper::Dpy, X11Helper::Win ); + XWindowAttributes winAttrib; + XGetWindowAttributes( Dpy, Win, &winAttrib ); + XSelectInput( Dpy, Win, winAttrib.your_event_mask | StructureNotifyMask ); + XMapWindow( Dpy, Win ); - // HACK: Wait for the MapNotify event, without spinning and - // eating CPU unnecessarily, and without smothering other - // events. Do this by grabbing all events, remembering - // uninteresting events, and putting them back on the queue - // after MapNotify arrives. - while(true) + // XXX: Why do we need to wait for the MapNotify event? + while( true ) { - XNextEvent(X11Helper::Dpy, &ev); - if( ev.type == MapNotify ) + XEvent event; + XMaskEvent( Dpy, StructureNotifyMask, &event ); + if( event.type == MapNotify ) break; - - otherEvs.push(ev); } - - while( !otherEvs.empty() ) - { - XPutBackEvent( X11Helper::Dpy, &otherEvs.top() ); - otherEvs.pop(); - } - - X11Helper::CloseMask( StructureNotifyMask ); + XSelectInput( Dpy, Win, winAttrib.your_event_mask ); } else @@ -143,33 +179,129 @@ CString LowLevelWindow_X11::TryVideoMode( RageDisplay::VideoModeParams p, bool & // We're remodeling the existing window, and not touching the // context. bNewDeviceOut = false; + } + + g_iOldSize = XRRConfigCurrentConfiguration( g_pScreenConfig, &g_OldRotation ); + + if( !p.windowed ) + { + // Find a matching mode. + int iSizesXct; + XRRScreenSize *pSizesX = XRRSizes( Dpy, DefaultScreen(Dpy), &iSizesXct ); + ASSERT_M( iSizesXct != 0, "Couldn't get resolution list from X server" ); + + int iSizeMatch = -1; + for( int i = 0; i < iSizesXct; ++i ) + { + if( pSizesX[i].width == p.width && pSizesX[i].height == p.height ) + { + iSizeMatch = i; + break; + } + } + + // Set this mode. + // XXX: This doesn't handle if the config has changed since we queried it (see man Xrandr) + XRRSetScreenConfig( Dpy, g_pScreenConfig, RootWindow(Dpy, DefaultScreen(Dpy)), iSizeMatch, 1, CurrentTime ); + + // Move the window to the corner that the screen focuses in on. + XMoveWindow( Dpy, Win, 0, 0 ); + + XRaiseWindow( Dpy, Win ); + + if( m_bWasWindowed ) + { + // We want to prevent the WM from catching anything that comes from the keyboard. + XGrabKeyboard( Dpy, Win, True, GrabModeAsync, GrabModeAsync, CurrentTime ); + m_bWasWindowed = false; + } } + else + { + if( !m_bWasWindowed ) + { + XRRSetScreenConfig( Dpy, g_pScreenConfig, RootWindow(Dpy, DefaultScreen(Dpy)), g_iOldSize, g_OldRotation, CurrentTime ); + // In windowed mode, we actually want the WM to function normally. + // Release any previous grab. + XUngrabKeyboard( Dpy, CurrentTime ); + m_bWasWindowed = true; + } + } + int rate = XRRConfigCurrentRate( g_pScreenConfig ); // Do this before resizing the window so that pane-style WMs (Ion, // ratpoison) don't resize us back inappropriately. - XSetWMNormalHints( X11Helper::Dpy, X11Helper::Win, &hints ); + { + XSizeHints hints; + + hints.flags = PBaseSize; + hints.base_width = p.width; + hints.base_height = p.height; + + XSetWMNormalHints( Dpy, Win, &hints ); + } // Do this even if we just created the window -- works around Ion2 not // catching WM normal hints changes in mapped windows. - XResizeWindow( X11Helper::Dpy, X11Helper::Win, p.width, p.height ); - - // Center the window in the display. - int w = DisplayWidth( X11Helper::Dpy, DefaultScreen(X11Helper::Dpy) ); - int h = DisplayHeight( X11Helper::Dpy, DefaultScreen(X11Helper::Dpy) ); - int x = (w - p.width)/2; - int y = (h - p.height)/2; - XMoveWindow( X11Helper::Dpy, X11Helper::Win, x, y ); + XResizeWindow( Dpy, Win, p.width, p.height ); CurrentParams = p; - + CurrentParams.rate = rate; return ""; // Success } void LowLevelWindow_X11::SwapBuffers() { - glXSwapBuffers( X11Helper::Dpy, X11Helper::Win ); + glXSwapBuffers( Dpy, Win ); + + if( PREFSMAN->m_bDisableScreenSaver ) + { + /* Disable the screensaver. */ +#if defined(HAVE_LIBXTST) + /* This causes flicker. */ + // XForceScreenSaver( Dpy, ScreenSaverReset ); + + /* + * Instead, send a null relative mouse motion, to trick X into thinking there has been + * user activity. + * + * This also handles XScreenSaver; XForceScreenSaver only handles the internal X11 + * screen blanker. + * + * This will delay the X blanker, DPMS and XScreenSaver from activating, and will + * disable the blanker and XScreenSaver if they're already active (unless XSS is + * locked). For some reason, it doesn't un-blank DPMS if it's already active. + */ + + XLockDisplay( Dpy ); + + int event_base, error_base, major, minor; + if( XTestQueryExtension( Dpy, &event_base, &error_base, &major, &minor ) ) + { + XTestFakeRelativeMotionEvent( Dpy, 0, 0, 0 ); + XSync( Dpy, False ); + } + + XUnlockDisplay( Dpy ); +#endif + } +} + +#if 0 +void LowLevelWindow_X11::GetDisplayResolutions( DisplayResolutions &out ) const +{ + int iSizesXct; + XRRScreenSize *pSizesX = XRRSizes( Dpy, DefaultScreen( Dpy ), &iSizesXct ); + ASSERT_M( iSizesXct != 0, "Couldn't get resolution list from X server" ); + + for( int i = 0; i < iSizesXct; ++i ) + { + DisplayResolution res = { pSizesX[i].width, pSizesX[i].height, true }; + out.insert( res ); + } } +#endif /* * (c) 2005 Ben Anderson diff --git a/src/arch/LowLevelWindow/LowLevelWindow_X11.h b/src/arch/LowLevelWindow/LowLevelWindow_X11.h index eba02a70..a885a0fc 100755 --- a/src/arch/LowLevelWindow/LowLevelWindow_X11.h +++ b/src/arch/LowLevelWindow/LowLevelWindow_X11.h @@ -17,8 +17,10 @@ public: RageDisplay::VideoModeParams GetVideoModeParams() const { return CurrentParams; } +//Maybe use in the future...? +// void GetDisplayResolutions( DisplayResolutions &out ) const; private: - bool m_bWindowIsOpen; + bool m_bWasWindowed; RageDisplay::VideoModeParams CurrentParams; }; diff --git a/src/archutils/Unix/X11Helper.cpp b/src/archutils/Unix/X11Helper.cpp index 61dd575f..321994f8 100755 --- a/src/archutils/Unix/X11Helper.cpp +++ b/src/archutils/Unix/X11Helper.cpp @@ -1,160 +1,98 @@ #include "global.h" #include "X11Helper.h" - -#include // Display, Window - #include "RageLog.h" -#include "RageDisplay.h" -#include "RageThreads.h" - -// Currently open masks: -static vector g_aiMasks; - -// Number of subsystems using the X connection: -static int g_iRefCount = 0; - -// Do we have a window? -static bool g_bHaveWin = false; Display *X11Helper::Dpy = NULL; -Window X11Helper::Win; +Window X11Helper::Win = None; -int protoErrorCallback( Display*, XErrorEvent* ); -int protoFatalCallback( Display* ); +static int ErrorCallback( Display*, XErrorEvent* ); +static int FatalCallback( Display* ); -bool X11Helper::Go() +bool X11Helper::OpenXConnection() { - if( g_iRefCount == 0 ) - { - Dpy = XOpenDisplay(0); - if( Dpy == NULL ) - return false; - - XSetIOErrorHandler( &protoFatalCallback ); - XSetErrorHandler( &protoErrorCallback ); - } - g_iRefCount++; + DEBUG_ASSERT( Dpy == NULL && Win == None ); + Dpy = XOpenDisplay(0); + if( Dpy == NULL ) + return false; + XSetIOErrorHandler( FatalCallback ); + XSetErrorHandler( ErrorCallback ); return true; } -void X11Helper::Stop() +void X11Helper::CloseXConnection() { - g_iRefCount--; - - if( g_iRefCount == 0 ) - { - XCloseDisplay( Dpy ); - Dpy = NULL; // For sanity's sake - g_aiMasks.clear(); - } -} - -static bool pApplyMasks(); - -bool X11Helper::OpenMask( long mask ) -{ - g_aiMasks.push_back(mask); - return pApplyMasks(); -} - -bool X11Helper::CloseMask( long mask ) -{ - vector::iterator i = find( g_aiMasks.begin(), g_aiMasks.end(), mask ); - if( i == g_aiMasks.end() ) - return true; - - g_aiMasks.erase( i ); - - return pApplyMasks(); + // The window should have been shut down + DEBUG_ASSERT( Dpy != NULL ); + DEBUG_ASSERT( Win == None ); + XCloseDisplay( Dpy ); + Dpy = NULL; } -static bool pApplyMasks() +bool X11Helper::MakeWindow( Window &win, int screenNum, int depth, Visual *visual, int width, int height, bool overrideRedirect ) { - if( X11Helper::Dpy == NULL | !g_bHaveWin ) - return true; - - LOG->Trace("X11Helper: Reapplying event masks."); - - long iMask = 0; - for( unsigned i = 0; i < g_aiMasks.size(); ++i ) - iMask |= g_aiMasks[i]; - - if( XSelectInput(X11Helper::Dpy, X11Helper::Win, iMask) == 0 ) - return false; - - return true; -} - -bool X11Helper::MakeWindow( int screenNum, int depth, Visual *visual, int width, int height ) -{ - vector::iterator i; - - if( g_iRefCount == 0 ) + if( !Dpy ) return false; - if( g_bHaveWin ) - { - XDestroyWindow( Dpy, Win ); - g_bHaveWin = false; - } - // pHaveWin will stay false if an error occurs once I do error - // checking here... - XSetWindowAttributes winAttribs; - winAttribs.border_pixel = 0; - winAttribs.event_mask = 0; - i = g_aiMasks.begin(); - while( i != g_aiMasks.end() ) + winAttribs.event_mask = 0L; + + if( win ) { - winAttribs.event_mask |= *i; - i++; + // Preserve the event mask. + XWindowAttributes attribs; + XGetWindowAttributes( Dpy, win, &attribs ); + winAttribs.event_mask = attribs.your_event_mask; + XDestroyWindow( Dpy, win ); } - // XXX: Error catching/handling? - winAttribs.colormap = XCreateColormap( Dpy, RootWindow(Dpy, screenNum), visual, AllocNone ); + unsigned long mask = CWBorderPixel | CWColormap | CWEventMask; - Win = XCreateWindow( Dpy, RootWindow(Dpy, screenNum), 0, 0, width, - height, 0, depth, InputOutput, visual, - CWBorderPixel | CWColormap | CWEventMask, &winAttribs ); - - g_bHaveWin = true; + if( overrideRedirect ) + { + winAttribs.override_redirect = True; + mask |= CWOverrideRedirect; + } + win = XCreateWindow( Dpy, RootWindow(Dpy, screenNum), 0, 0, width, height, 0, + depth, InputOutput, visual, mask, &winAttribs ); + if( win == None ) + return false; /* Hide the mouse cursor. */ { const char pBlank[] = { 0,0,0,0,0,0,0,0 }; - Pixmap BlankBitmap = XCreateBitmapFromData( Dpy, Win, pBlank, 8, 8 ); + Pixmap BlankBitmap = XCreateBitmapFromData( Dpy, win, pBlank, 8, 8 ); XColor black = { 0, 0, 0, 0, 0, 0 }; Cursor pBlankPointer = XCreatePixmapCursor( Dpy, BlankBitmap, BlankBitmap, &black, &black, 0, 0 ); XFreePixmap( Dpy, BlankBitmap ); - XDefineCursor( Dpy, Win, pBlankPointer ); + XDefineCursor( Dpy, win, pBlankPointer ); XFreeCursor( Dpy, pBlankPointer ); } return true; } -int protoErrorCallback( Display *d, XErrorEvent *err ) +int ErrorCallback( Display *d, XErrorEvent *err ) { char errText[512]; XGetErrorText( d, err->error_code, errText, 512 ); LOG->Warn( "X11 Protocol error %s (%d) has occurred, caused by request %d,%d, resource ID %d", - errText, err->error_code, err->request_code, err->minor_code, err->resourceid ); + errText, err->error_code, err->request_code, err->minor_code, (int) err->resourceid ); return 0; // Xlib ignores our return value } -int protoFatalCallback( Display *d ) +int FatalCallback( Display *d ) { RageException::Throw( "Fatal I/O error communicating with X server." ); } /* - * (c) 2005 Ben Anderson + * (c) 2005, 2006 Ben Anderson, Steve Checkoway * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a diff --git a/src/archutils/Unix/X11Helper.h b/src/archutils/Unix/X11Helper.h index 0dd92762..255abbb7 100755 --- a/src/archutils/Unix/X11Helper.h +++ b/src/archutils/Unix/X11Helper.h @@ -3,9 +3,6 @@ #define X11_HELPER_H #include // Window - -#include "RageDisplay.h" // RageDisplay - namespace X11Helper { // All functions in here that return a bool return true on success, and @@ -13,39 +10,28 @@ namespace X11Helper // Create the connection, if necessary; otherwise do some important // internal session-tracking stuff (so you should call this anyway). - bool Go(); + bool OpenXConnection(); + + // Destroy the connection, if appropriate; otherwise do some important + // internal session-tracking stuff (so you should call it anyway). + void CloseXConnection(); // The current Display (connection). Initialized by the first call to - // Go(). + // OpenXConnection(). extern Display *Dpy; - // Get the current open window. Initialized by the first call to - // MakeWindow(). + // The Window used by LowLevelWindow_X11 as the main window. extern Window Win; - // (Re)create the window on the screen of this number with this depth, - // this visual type, this width (optional -- you can resize the window - // in your callback later), and this height (optional). - bool MakeWindow(int screenNum, int depth, Visual *visual, - int width=32, int height=32); - - // Unmask one X event type mask thingy (XSelectInput() arg 3) on the - // current window. Masked/unmasked events will carry between windows. - bool OpenMask(long mask); - - // (Re)mask one X event type mask thingy (XSelectInput() arg 3) on the - // current window. Masked/unmasked events will carry between windows. - bool CloseMask(long mask); - - // Destroy the connection, if appropriate; otherwise do some important - // internal session-tracking stuff (so you should call it anyway). - void Stop(); + // (Re)create the Window win. + bool MakeWindow( Window &win, int screenNum, int depth, Visual *visual, + int width, int height, bool overrideRedirect ); }; #endif /* - * (c) 2005 Ben Anderson + * (c) 2005, 2006 Ben Anderson, Steve Checkoway * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a diff --git a/src/io/PIUIO.cpp b/src/io/PIUIO.cpp index 642b664a..043853e3 100644 --- a/src/io/PIUIO.cpp +++ b/src/io/PIUIO.cpp @@ -78,7 +78,7 @@ bool PIUIO::BulkReadWrite( uint32_t pData[4] ) } /* - * Copyright (c) 2008 vyhd + * Copyright (c) 2008 BoXoRRoXoRs * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a diff --git a/src/io/PIUIO.h b/src/io/PIUIO.h index 758100dd..783d8b0a 100644 --- a/src/io/PIUIO.h +++ b/src/io/PIUIO.h @@ -17,7 +17,7 @@ protected: #endif /* IO_PIUIO_H */ /* - * (c) 2008 vyhd + * Copyright (c) 2008 BoXoRRoXoRs * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a diff --git a/src/io/USBDevice.h b/src/io/USBDevice.h index 73791da2..b8a5cbc2 100644 --- a/src/io/USBDevice.h +++ b/src/io/USBDevice.h @@ -59,7 +59,7 @@ bool GetUSBDeviceList(vector &pDevList); #endif /* IO_USBDEVICE_H */ /* - * (c) 2008 BoXoRRoXoRs + * Copyright (c) 2008 BoXoRRoXoRs * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a diff --git a/src/io/USBDriver.h b/src/io/USBDriver.h index 2c2d4ee0..dddbbf5b 100644 --- a/src/io/USBDriver.h +++ b/src/io/USBDriver.h @@ -26,7 +26,7 @@ protected: #endif /* - * (c) 2008 BoXoRRoXoRs + * Copyright (c) 2008 BoXoRRoXoRs * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a -- 2.11.0