Add proper fullscreen and resolution changing support using XRandR. This makes XRandR mandatory, but I don't see any reason why we can't do that, and providing alternatives would be difficult at best for little payoff.
This commit is contained in:
@@ -31,6 +31,25 @@ AC_DEFUN([SM_X_WITH_OPENGL],
|
||||
[$XLIBS])
|
||||
AC_DEFINE(HAVE_X11, 1, [X11 libraries present])
|
||||
fi
|
||||
|
||||
# Check for Xrandr
|
||||
# Can someone fix this for me? This is producing bizarre warnings from
|
||||
# configure... I have no clue what I'm doing -Ben
|
||||
AC_CHECK_LIB(Xrandr, XRRSizes, have_xrandr=yes, have_xrandr=no)
|
||||
AC_CHECK_HEADER(X11/extensions/Xrandr.h, have_xrandr_header=yes, have_xrandr_header=no)
|
||||
|
||||
if test "$have_xrandr_header" = "no"; then
|
||||
have_xrandr=no
|
||||
fi
|
||||
|
||||
if test "$have_xrandr" = "no"; then
|
||||
echo "*** Direct X11 support needs Xrandr libraries and headers."
|
||||
echo "*** Couldn't find needed headers. Continuing without X11 backend."
|
||||
$no_x = yes
|
||||
else
|
||||
LIBS="$LIBS -lXrandr"
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL(HAVE_X11, test "$no_x" != "yes")
|
||||
|
||||
AC_SUBST(XCFLAGS)
|
||||
|
||||
@@ -5,12 +5,15 @@
|
||||
#include "archutils/Unix/X11Helper.h"
|
||||
#include "PrefsManager.h" // XXX
|
||||
#include "RageDisplay.h" // VideoModeParams
|
||||
#include "DisplayResolutions.h"
|
||||
|
||||
#include <stack>
|
||||
#include <math.h> // ceil()
|
||||
#define GLX_GLXEXT_PROTOTYPES
|
||||
#include <GL/glx.h> // All sorts of stuff...
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/extensions/Xrandr.h>
|
||||
|
||||
#if defined(HAVE_LIBXTST)
|
||||
#include <X11/extensions/XTest.h>
|
||||
@@ -36,10 +39,21 @@ LowLevelWindow_X11::LowLevelWindow_X11()
|
||||
LOG->Info( "X server vendor: %s [%i.%i.%i.%i]", XServerVendor( X11Helper::Dpy ), iMajor, iMinor, iRevision, iPatch );
|
||||
LOG->Info( "Server GLX vendor: %s [%s]", glXQueryServerString( X11Helper::Dpy, iScreen, GLX_VENDOR ), glXQueryServerString( X11Helper::Dpy, iScreen, GLX_VERSION ) );
|
||||
LOG->Info( "Client GLX vendor: %s [%s]", glXGetClientString( X11Helper::Dpy, GLX_VENDOR ), glXGetClientString( X11Helper::Dpy, GLX_VERSION ) );
|
||||
|
||||
m_bWasWindowed = true;
|
||||
}
|
||||
|
||||
LowLevelWindow_X11::~LowLevelWindow_X11()
|
||||
{
|
||||
// Reset the display
|
||||
if( !m_bWasWindowed )
|
||||
{
|
||||
XRRScreenConfiguration *screenConfig = XRRGetScreenInfo( X11Helper::Dpy, RootWindow( X11Helper::Dpy, DefaultScreen( X11Helper::Dpy ) ) );
|
||||
XRRSetScreenConfig( X11Helper::Dpy, screenConfig, RootWindow( X11Helper::Dpy, DefaultScreen( X11Helper::Dpy ) ), 0, 1, CurrentTime );
|
||||
XRRFreeScreenConfigInfo( screenConfig );
|
||||
|
||||
XUngrabKeyboard( X11Helper::Dpy, CurrentTime );
|
||||
}
|
||||
X11Helper::Stop(); // Xlib cleans up the window for us
|
||||
}
|
||||
|
||||
@@ -74,7 +88,7 @@ CString LowLevelWindow_X11::TryVideoMode( const VideoModeParams &p, bool &bNewDe
|
||||
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( !m_bWindowIsOpen || p.bpp != CurrentParams.bpp || ( m_bWasWindowed != p.windowed ) )
|
||||
{
|
||||
// Different depth, or we didn't make a window before. New context.
|
||||
bNewDeviceOut = true;
|
||||
@@ -111,7 +125,9 @@ CString LowLevelWindow_X11::TryVideoMode( const VideoModeParams &p, bool &bNewDe
|
||||
/* 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( !X11Helper::MakeWindow(xvi->screen, xvi->depth, xvi->visual, p.width, p.height, !p.windowed) )
|
||||
{
|
||||
return "Failed to create the window.";
|
||||
}
|
||||
@@ -157,6 +173,58 @@ CString LowLevelWindow_X11::TryVideoMode( const VideoModeParams &p, bool &bNewDe
|
||||
bNewDeviceOut = false;
|
||||
|
||||
}
|
||||
|
||||
XRRScreenConfiguration *screenConfig = XRRGetScreenInfo( X11Helper::Dpy, RootWindow( X11Helper::Dpy, DefaultScreen( X11Helper::Dpy ) ) );
|
||||
|
||||
if( !p.windowed )
|
||||
{
|
||||
// Find a matching mode.
|
||||
int sizesXct;
|
||||
XRRScreenSize *sizesX = XRRSizes( X11Helper::Dpy, DefaultScreen( X11Helper::Dpy ), &sizesXct );
|
||||
ASSERT_M( sizesXct != 0, "Couldn't get resolution list from X server" );
|
||||
|
||||
int sizeMatch = -1;
|
||||
int i = 0;
|
||||
while(i < sizesXct)
|
||||
{
|
||||
if(sizesX[i].width == p.width && sizesX[i].height == p.height)
|
||||
{
|
||||
sizeMatch = i;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
// Set this mode.
|
||||
// XXX: This doesn't handle if the config has changed since we queried it (see man Xrandr)
|
||||
XRRSetScreenConfig( X11Helper::Dpy, screenConfig, RootWindow( X11Helper::Dpy, DefaultScreen( X11Helper::Dpy ) ), sizeMatch, 1, CurrentTime );
|
||||
|
||||
// Move the window to the corner that the screen focuses in on.
|
||||
XMoveWindow( X11Helper::Dpy, X11Helper::Win, 0, 0 );
|
||||
|
||||
|
||||
XRaiseWindow( X11Helper::Dpy, X11Helper::Win );
|
||||
|
||||
if( m_bWasWindowed )
|
||||
{
|
||||
// We want to prevent the WM from catching anything that comes from the keyboard.
|
||||
XGrabKeyboard( X11Helper::Dpy, X11Helper::Win, True,
|
||||
GrabModeAsync, GrabModeAsync, CurrentTime );
|
||||
m_bWasWindowed = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !m_bWasWindowed )
|
||||
{
|
||||
XRRSetScreenConfig( X11Helper::Dpy, screenConfig, RootWindow( X11Helper::Dpy, DefaultScreen( X11Helper::Dpy ) ), 0, 1, CurrentTime );
|
||||
// In windowed mode, we actually want the WM to function normally.
|
||||
// Release any previous grab.
|
||||
XUngrabKeyboard( X11Helper::Dpy, CurrentTime );
|
||||
m_bWasWindowed = true;
|
||||
}
|
||||
}
|
||||
|
||||
XRRFreeScreenConfigInfo( screenConfig );
|
||||
|
||||
// Do this before resizing the window so that pane-style WMs (Ion,
|
||||
// ratpoison) don't resize us back inappropriately.
|
||||
@@ -166,13 +234,6 @@ CString LowLevelWindow_X11::TryVideoMode( const VideoModeParams &p, bool &bNewDe
|
||||
// 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 );
|
||||
|
||||
CurrentParams = p;
|
||||
|
||||
return ""; // Success
|
||||
@@ -224,6 +285,23 @@ void LowLevelWindow_X11::SwapBuffers()
|
||||
}
|
||||
}
|
||||
|
||||
void LowLevelWindow_X11::GetDisplayResolutions( DisplayResolutions &out ) const
|
||||
{
|
||||
// This _NEEDS_ Xrandr to be present, but feck, who doesn't have it?
|
||||
|
||||
int sizesXct;
|
||||
XRRScreenSize *sizesX = XRRSizes( X11Helper::Dpy, DefaultScreen( X11Helper::Dpy ), &sizesXct );
|
||||
ASSERT_M( sizesXct != 0, "Couldn't get resolution list from X server" );
|
||||
|
||||
int i = 0;
|
||||
while(i < sizesXct)
|
||||
{
|
||||
DisplayResolution res = { sizesX[i].width, sizesX[i].height };
|
||||
out.s.insert( res );
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (c) 2005 Ben Anderson
|
||||
* All rights reserved.
|
||||
|
||||
@@ -18,9 +18,12 @@ public:
|
||||
void SwapBuffers();
|
||||
|
||||
VideoModeParams GetActualVideoModeParams() const { return CurrentParams; }
|
||||
|
||||
void GetDisplayResolutions( DisplayResolutions &out ) const;
|
||||
|
||||
private:
|
||||
bool m_bWindowIsOpen;
|
||||
bool m_bWasWindowed;
|
||||
VideoModeParams CurrentParams;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "global.h"
|
||||
#include "X11Helper.h"
|
||||
|
||||
#include <X11/Xlib.h> // Display, Window
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
#include "RageLog.h"
|
||||
#include "RageDisplay.h"
|
||||
@@ -86,7 +86,7 @@ static bool pApplyMasks()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool X11Helper::MakeWindow( int screenNum, int depth, Visual *visual, int width, int height )
|
||||
bool X11Helper::MakeWindow( int screenNum, int depth, Visual *visual, int width, int height, bool overrideRedirect )
|
||||
{
|
||||
vector<long>::iterator i;
|
||||
|
||||
@@ -116,9 +116,20 @@ bool X11Helper::MakeWindow( int screenNum, int depth, Visual *visual, int width,
|
||||
|
||||
winAttribs.colormap = XCreateColormap( Dpy, RootWindow(Dpy, screenNum), visual, AllocNone );
|
||||
|
||||
Win = XCreateWindow( Dpy, RootWindow(Dpy, screenNum), 0, 0, width,
|
||||
height, 0, depth, InputOutput, visual,
|
||||
CWBorderPixel | CWColormap | CWEventMask, &winAttribs );
|
||||
if( overrideRedirect )
|
||||
{
|
||||
winAttribs.override_redirect = True;
|
||||
Win = XCreateWindow( Dpy, RootWindow(Dpy, screenNum), 0, 0, width,
|
||||
height, 0, depth, InputOutput, visual,
|
||||
CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect, &winAttribs );
|
||||
}
|
||||
else
|
||||
{
|
||||
Win = XCreateWindow( Dpy, RootWindow(Dpy, screenNum), 0, 0, width,
|
||||
height, 0, depth, InputOutput, visual,
|
||||
CWBorderPixel | CWColormap | CWEventMask, &winAttribs );
|
||||
}
|
||||
|
||||
|
||||
g_bHaveWin = true;
|
||||
|
||||
|
||||
@@ -26,8 +26,9 @@ namespace X11Helper
|
||||
// (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).
|
||||
// Also, whether to enable override redirect on the window.
|
||||
bool MakeWindow(int screenNum, int depth, Visual *visual,
|
||||
int width=32, int height=32);
|
||||
int width=32, int height=32, bool overrideRedirect=false);
|
||||
|
||||
// Unmask one X event type mask thingy (XSelectInput() arg 3) on the
|
||||
// current window. Masked/unmasked events will carry between windows.
|
||||
|
||||
Reference in New Issue
Block a user