5 1 new backport x11 fs rework (#1485)
* Use XRandR 1.2 to set fullscreen resolution for single output Squash of roothorick's PR #497 (also includes Kyzentun's CMake changes from PR #716) * Cherry-pick json c++1x stuff (b9e3d7174e) * Cherry-pick c++11 support from 5bba5c0038 and 9f8b045309 * rework Linux (X11) fullscreen, improve display-related Graphics Options Implement option to select between monitors for exclusive fullscreen mode on X11 (using XRandR 1.2), or use a fullscreen borderless window. Reimplement resolution/refresh rate/display mode-related option rows using Lua, update choices dynamically so only known-good groupings of resolution/refresh rate/aspect ratio can be selected. Minimally update Windows/MacOS LowLevelWindow implementations to support changes made for Linux side. Fullscreen Borderless Window/multi monitor support from X11 not implemented for those in this commit. * allow forcibly disabling xinerama use on Linux When libXinerama is available, SM tries to use it to find the proper monitor indexes to use to set _NET_WM_FULLSCREEN_MONITORS (on borderless fullscreen). xfwm4 seems to assume that monitors are numbered in increasing order from left to right (rather than using the Xinerama-assigned numbers), so _NET_WM_FULLSCREEN_MONITORS misbehaves on Xfce. This commit bypasses use of libXinerama, and instead forces SM to induce fullscreen on the desired monitor in the backup, hacky way: remove all window hints, move window to desired monitor, then add _NET_WM_STATE_FULLSCREEN hint. This works on mutter and Xfce. * Remove multiple warnings on redundant define. This used to be hard-coded due to pthread related items, but now it's dynamically determined. * fix _fallback menu behavior for unrecognized aspect ratios * Fix error recreating existing FS texture * Bump deployment target to 10.7 to use libc++ on XCode 8 * Add explicit casts to please clang * Update changelog
This commit is contained in:
committed by
Colby Klein
parent
7ef14c340d
commit
557be7cf1b
@@ -5,7 +5,6 @@
|
||||
extern "C" int sm_main( int argc, char *argv[] );
|
||||
|
||||
#define HAVE_CXA_DEMANGLE
|
||||
#define HAVE_PTHREAD_COND_TIMEDWAIT
|
||||
/* This must be defined to 1 because autoconf's AC_CHECK_DECLS macro decides to define
|
||||
* this in all cases. If only they could be consistent... */
|
||||
#define HAVE_DECL_SIGUSR1 1
|
||||
|
||||
@@ -129,6 +129,23 @@ bool X11Helper::MakeWindow( Window &win, int screenNum, int depth, Visual *visua
|
||||
return true;
|
||||
}
|
||||
|
||||
void X11Helper::SetWMState( const Window &root, const Window &win, const long action, const Atom atom )
|
||||
{
|
||||
if ( !Dpy )
|
||||
return;
|
||||
Atom wm_state = XInternAtom(Dpy, "_NET_WM_STATE", False);
|
||||
XEvent xev;
|
||||
memset( &xev, 0, sizeof( xev ));
|
||||
xev.type = ClientMessage;
|
||||
xev.xclient.window = Win;
|
||||
xev.xclient.message_type = wm_state;
|
||||
xev.xclient.format = 32;
|
||||
xev.xclient.data.l[0] = action; // 0 = Remove, 1 = Add, 2 = Toggle
|
||||
xev.xclient.data.l[1] = atom;
|
||||
xev.xclient.data.l[2] = 0; // end list of Atoms
|
||||
XSendEvent( Dpy, root, False, SubstructureRedirectMask | SubstructureNotifyMask, &xev );
|
||||
}
|
||||
|
||||
int ErrorCallback( Display *d, XErrorEvent *err )
|
||||
{
|
||||
char errText[512];
|
||||
@@ -144,6 +161,85 @@ int FatalCallback( Display *d )
|
||||
RageException::Throw( "Fatal I/O error communicating with X server." );
|
||||
}
|
||||
|
||||
#ifdef HAVE_XINERAMA
|
||||
#include <X11/extensions/Xinerama.h>
|
||||
|
||||
bool X11Helper::SetWMFullscreenMonitors( const DisplaySpec &target )
|
||||
{
|
||||
int num_screens = 0;
|
||||
XineramaScreenInfo *screens = XineramaQueryScreens( Dpy, &num_screens );
|
||||
if (screens == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
XineramaScreenInfo *end = screens + num_screens;
|
||||
RectI monitors{};
|
||||
bool found_bounds = false;
|
||||
|
||||
if (target.isVirtual())
|
||||
{
|
||||
auto topmost = std::min_element( screens, end, []( XineramaScreenInfo &a, XineramaScreenInfo &b ) {
|
||||
return a.y_org < b.y_org;
|
||||
} );
|
||||
monitors.top = topmost->screen_number;
|
||||
|
||||
auto bottommost = std::max_element( screens, end, []( XineramaScreenInfo &a, XineramaScreenInfo &b ) {
|
||||
return a.y_org < b.y_org;
|
||||
} );
|
||||
monitors.bottom = bottommost->screen_number;
|
||||
|
||||
auto leftmost = std::min_element( screens, end, []( XineramaScreenInfo &a, XineramaScreenInfo &b ) {
|
||||
return a.x_org < b.x_org;
|
||||
} );
|
||||
monitors.left = leftmost->screen_number;
|
||||
|
||||
auto rightmost = std::max_element( screens, end, []( XineramaScreenInfo &a, XineramaScreenInfo &b ) {
|
||||
return a.x_org < b.x_org;
|
||||
} );
|
||||
monitors.right = rightmost->screen_number;
|
||||
found_bounds = true;
|
||||
}
|
||||
else if (target.currentMode() != nullptr)
|
||||
{
|
||||
auto mon = std::find_if( screens, end, [&]( XineramaScreenInfo &screen ) {
|
||||
return screen.x_org == target.currentBounds().left && screen.y_org == target.currentBounds().top
|
||||
&& screen.width == target.currentMode()->width && screen.height == target.currentMode()->height;
|
||||
} );
|
||||
if (mon != end)
|
||||
{
|
||||
monitors.left = monitors.right = monitors.top = monitors.bottom = mon->screen_number;
|
||||
found_bounds = true;
|
||||
}
|
||||
}
|
||||
|
||||
XFree( screens );
|
||||
XWindowAttributes attr = {0};
|
||||
if (!found_bounds || !XGetWindowAttributes( Dpy, Win, &attr ))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
SetWMState( attr.root, Win, 1, XInternAtom( Dpy, "_NET_WM_STATE_FULLSCREEN", False ));
|
||||
|
||||
XClientMessageEvent xclient = {0};
|
||||
xclient.type = ClientMessage;
|
||||
xclient.window = Win;
|
||||
xclient.message_type = XInternAtom( Dpy, "_NET_WM_FULLSCREEN_MONITORS", False );
|
||||
xclient.format = 32;
|
||||
xclient.data.l[0] = monitors.top;
|
||||
xclient.data.l[1] = monitors.bottom;
|
||||
xclient.data.l[2] = monitors.left;
|
||||
xclient.data.l[3] = monitors.right;
|
||||
xclient.data.l[4] = 1;
|
||||
XSendEvent( Dpy, attr.root, False, SubstructureRedirectMask | SubstructureNotifyMask,
|
||||
reinterpret_cast<XEvent *> (&xclient));
|
||||
XFlush( Dpy );
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* (c) 2005, 2006 Ben Anderson, Steve Checkoway
|
||||
* All rights reserved.
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
#include <X11/Xlib.h> // Window
|
||||
#include <X11/Xutil.h>
|
||||
#include <DisplaySpec.h>
|
||||
|
||||
namespace X11Helper
|
||||
{
|
||||
// All functions in here that return a bool return true on success, and
|
||||
@@ -25,6 +27,12 @@ namespace X11Helper
|
||||
// (Re)create the Window win.
|
||||
bool MakeWindow( Window &win, int screenNum, int depth, Visual *visual,
|
||||
int width, int height, bool overrideRedirect );
|
||||
|
||||
void SetWMState( const Window &root, const Window &win, const long action, const Atom atom );
|
||||
|
||||
#ifdef HAVE_XINERAMA
|
||||
bool SetWMFullscreenMonitors( const DisplaySpec &target );
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "RageLog.h"
|
||||
#include "RageUtil.h"
|
||||
#include "RageDisplay.h"
|
||||
#include "DisplayResolutions.h"
|
||||
#include "DisplaySpec.h"
|
||||
#include "arch/ArchHooks/ArchHooks.h"
|
||||
#include "archutils/Win32/AppInstance.h"
|
||||
#include "archutils/Win32/Crash.h"
|
||||
@@ -539,29 +539,53 @@ HWND GraphicsWindow::GetHwnd()
|
||||
return g_hWndMain;
|
||||
}
|
||||
|
||||
void GraphicsWindow::GetDisplayResolutions( DisplayResolutions &out )
|
||||
void GraphicsWindow::GetDisplaySpecs( DisplaySpecs &out )
|
||||
{
|
||||
DEVMODE dm;
|
||||
ZERO( dm );
|
||||
dm.dmSize = sizeof(dm);
|
||||
int i=0;
|
||||
while(EnumDisplaySettings(NULL, i++, &dm))
|
||||
{
|
||||
const size_t DM_DRIVER_EXTRA_BYTES = 4096;
|
||||
const size_t DMSIZE = sizeof( DEVMODE ) + DM_DRIVER_EXTRA_BYTES;
|
||||
auto reset = [=]( std::unique_ptr<DEVMODE> &p ) {
|
||||
::memset( p.get(), 0, DMSIZE );
|
||||
p->dmSize = sizeof( DEVMODE );
|
||||
p->dmDriverExtra = static_cast<WORD> (DM_DRIVER_EXTRA_BYTES);
|
||||
};
|
||||
auto isvalid = []( std::unique_ptr<DEVMODE> &dm ) {
|
||||
// Windows 8 and later don't support less than 32bpp, so don't even test
|
||||
// for them. GetDisplayResolutions is only for resolutions anyway. -Kyz
|
||||
if(dm.dmBitsPerPel < 32)
|
||||
// for them. GetDisplaySpecs only tracks resolution/refresh rate anyway. -Kyz, drewbarbs
|
||||
return (dm->dmFields & DM_PELSWIDTH) && (dm->dmFields & DM_PELSHEIGHT) && (dm->dmFields & DM_DISPLAYFREQUENCY)
|
||||
&& (dm->dmBitsPerPel >= 32 || !(dm->dmFields & DM_BITSPERPEL));
|
||||
};
|
||||
|
||||
std::unique_ptr<DEVMODE> dm( static_cast<DEVMODE*> (operator new(DMSIZE)) );
|
||||
reset( dm );
|
||||
|
||||
int i = 0;
|
||||
std::set<DisplayMode> modes;
|
||||
while ( EnumDisplaySettingsEx( nullptr, i++, dm.get(), 0 ) )
|
||||
{
|
||||
if ( isvalid( dm ) && ChangeDisplaySettingsEx( nullptr, dm.get(), nullptr, CDS_TEST, nullptr ) == DISP_CHANGE_SUCCESSFUL )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
DisplayResolution res = { dm.dmPelsWidth, dm.dmPelsHeight };
|
||||
std::set<DisplayResolution>::iterator entry= out.find(res);
|
||||
if(entry == out.end())
|
||||
{
|
||||
if(ChangeDisplaySettings(&dm, CDS_TEST)==DISP_CHANGE_SUCCESSFUL)
|
||||
{
|
||||
out.insert(res);
|
||||
}
|
||||
DisplayMode m = { dm->dmPelsWidth, dm->dmPelsHeight, static_cast<double> (dm->dmDisplayFrequency) };
|
||||
modes.insert(m);
|
||||
}
|
||||
reset( dm );
|
||||
}
|
||||
|
||||
reset( dm );
|
||||
// Get the current display mode
|
||||
if ( EnumDisplaySettingsEx( nullptr, ENUM_CURRENT_SETTINGS, dm.get(), 0 ) && isvalid( dm ) )
|
||||
{
|
||||
DisplayMode m = { dm->dmPelsWidth, dm->dmPelsHeight, static_cast<double> (dm->dmDisplayFrequency) };
|
||||
RectI bounds = { 0, 0, static_cast<int> (m.width), static_cast<int> (m.height) };
|
||||
out.insert( DisplaySpec( "", "Fullscreen", modes, m, bounds ) );
|
||||
}
|
||||
else if ( !modes.empty() )
|
||||
{
|
||||
LOG->Warn( "Could not retrieve valid current display mode" );
|
||||
out.insert( DisplaySpec( "", "Fullscreen", *modes.begin() ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG->Warn( "Could not retrieve *any* DisplaySpec's!" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#define GRAPHICS_WINDOW_H
|
||||
|
||||
#include <windows.h>
|
||||
#include "DisplayResolutions.h"
|
||||
#include "DisplaySpec.h"
|
||||
class VideoModeParams;
|
||||
class DisplayResolution;
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace GraphicsWindow
|
||||
void CreateGraphicsWindow( const VideoModeParams &p, bool bForceRecreateWindow = false );
|
||||
void DestroyGraphicsWindow();
|
||||
|
||||
void GetDisplayResolutions( DisplayResolutions &out );
|
||||
void GetDisplaySpecs( DisplaySpecs &out );
|
||||
|
||||
const VideoModeParams &GetParams();
|
||||
HDC GetHDC();
|
||||
|
||||
Reference in New Issue
Block a user