mirror of
https://github.com/libretro/gambatte-libretro.git
synced 2025-02-17 07:10:19 +00:00
gditoggler: add multi-monitor support (win32)
videodialog: save actual hz values for real this time quartztoggler: avoid potentially reverting to the wrong mode on double setFullMode(false) in multi-head configs make sure window is within screen after mode change, so Qt doesn't reset it to the primary screen revert to previous win32 fullscreen geometry correction behaviour so that the geometry gets properly reset after fullscreen git-svn-id: https://gambatte.svn.sourceforge.net/svnroot/gambatte@137 9dfb2916-2d38-0410-aef4-c5fe6c9ffc24
This commit is contained in:
parent
b5e5dc54df
commit
e9b4561695
@ -57,52 +57,154 @@ static void addMode(const DEVMODE &devmode, std::vector<ResInfo> &infoVector, un
|
||||
*rateIndex = std::distance(it->rates.begin(), rateIt);
|
||||
}
|
||||
|
||||
class GdiToggler::MultiMon {
|
||||
struct MonInfo {
|
||||
DWORD cbSize;
|
||||
RECT rcMonitor;
|
||||
RECT rcWork;
|
||||
DWORD dwFlags;
|
||||
TCHAR szDevice[CCHDEVICENAME];
|
||||
};
|
||||
|
||||
typedef BOOL (WINAPI *GetMonInfo)(HMONITOR, MonInfo*);
|
||||
typedef HMONITOR (WINAPI *MonFromPoint)(POINT pt, DWORD dwFlags);
|
||||
typedef LONG (WINAPI *ChangeDspSettingsEx)(LPCTSTR, LPDEVMODE, HWND, DWORD, LPVOID);
|
||||
enum { MON_DEFAULTTONEAREST = 2 };
|
||||
|
||||
HMODULE user32handle;
|
||||
ChangeDspSettingsEx changeDisplaySettingsEx;
|
||||
TCHAR *devNames;
|
||||
unsigned numDevs;
|
||||
|
||||
TCHAR *name(int screen) { return devNames ? devNames + screen * CCHDEVICENAME : NULL; }
|
||||
|
||||
public:
|
||||
MultiMon() : user32handle(NULL), changeDisplaySettingsEx(NULL), devNames(NULL), numDevs(1) {
|
||||
GetMonInfo getMonitorInfo = NULL;
|
||||
MonFromPoint monitorFromPoint = NULL;
|
||||
|
||||
user32handle = LoadLibraryA("user32.dll");
|
||||
|
||||
if (user32handle) {
|
||||
QT_WA(
|
||||
{getMonitorInfo = (GetMonInfo)GetProcAddress(user32handle, "GetMonitorInfoW");},
|
||||
{getMonitorInfo = (GetMonInfo)GetProcAddress(user32handle, "GetMonitorInfoA");}
|
||||
);
|
||||
|
||||
QT_WA(
|
||||
{changeDisplaySettingsEx = (ChangeDspSettingsEx)GetProcAddress(user32handle, "ChangeDisplaySettingsExW");},
|
||||
{changeDisplaySettingsEx = (ChangeDspSettingsEx)GetProcAddress(user32handle, "ChangeDisplaySettingsExA");}
|
||||
);
|
||||
|
||||
monitorFromPoint = (MonFromPoint)GetProcAddress(user32handle, "MonitorFromPoint");
|
||||
}
|
||||
|
||||
if (getMonitorInfo && monitorFromPoint && changeDisplaySettingsEx) {
|
||||
numDevs = QApplication::desktop()->numScreens();
|
||||
devNames = new TCHAR[numDevs * CCHDEVICENAME];
|
||||
|
||||
MonInfo moninfo;
|
||||
moninfo.cbSize = sizeof(MonInfo);
|
||||
|
||||
for (unsigned i = 0; i < numDevs; ++i) {
|
||||
const QPoint &qpoint = QApplication::desktop()->screenGeometry(i).center();
|
||||
POINT point = { x: qpoint.x(), y: qpoint.y() };
|
||||
getMonitorInfo(monitorFromPoint(point, MON_DEFAULTTONEAREST), &moninfo);
|
||||
|
||||
std::memcpy(devNames + i * CCHDEVICENAME, moninfo.szDevice, CCHDEVICENAME * sizeof(TCHAR));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
~MultiMon() {
|
||||
if (user32handle)
|
||||
FreeLibrary(user32handle);
|
||||
|
||||
delete []devNames;
|
||||
}
|
||||
|
||||
unsigned numScreens() const { return numDevs; }
|
||||
|
||||
BOOL enumDisplaySettings(unsigned screen, DWORD iModeNum, LPDEVMODE devmode) {
|
||||
return EnumDisplaySettings(name(screen), iModeNum, devmode);
|
||||
}
|
||||
|
||||
LONG changeDisplaySettings(unsigned screen, LPDEVMODE devmode, DWORD dwflags) {
|
||||
return changeDisplaySettingsEx ?
|
||||
changeDisplaySettingsEx(name(screen), devmode, NULL, dwflags, NULL) :
|
||||
ChangeDisplaySettings(devmode, dwflags);
|
||||
}
|
||||
};
|
||||
|
||||
GdiToggler::GdiToggler() :
|
||||
mon(new MultiMon),
|
||||
originalWidth(0),
|
||||
originalHeight(0),
|
||||
originalRate(0),
|
||||
fullResIndex(0),
|
||||
fullRateIndex(0),
|
||||
widgetScreen(0),
|
||||
isFull(false)
|
||||
{
|
||||
infoVector.resize(mon->numScreens());
|
||||
fullResIndex.resize(mon->numScreens());
|
||||
fullRateIndex.resize(mon->numScreens());
|
||||
|
||||
DEVMODE devmode;
|
||||
devmode.dmSize = sizeof(DEVMODE);
|
||||
devmode.dmDriverExtra = 0;
|
||||
|
||||
EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &devmode);
|
||||
for (unsigned i = 0; i < mon->numScreens(); ++i) {
|
||||
mon->enumDisplaySettings(i, ENUM_CURRENT_SETTINGS, &devmode);
|
||||
|
||||
const unsigned bpp = devmode.dmBitsPerPel;
|
||||
|
||||
int n = 0;
|
||||
|
||||
while (mon->enumDisplaySettings(i, n++, &devmode)) {
|
||||
if (devmode.dmBitsPerPel == bpp)
|
||||
addMode(devmode, infoVector[i], NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < mon->numScreens(); ++i) {
|
||||
mon->enumDisplaySettings(i, ENUM_CURRENT_SETTINGS, &devmode);
|
||||
addMode(devmode, infoVector[i], &fullResIndex[i], &fullRateIndex[i]);
|
||||
}
|
||||
|
||||
mon->enumDisplaySettings(widgetScreen, ENUM_CURRENT_SETTINGS, &devmode);
|
||||
originalWidth = devmode.dmPelsWidth;
|
||||
originalHeight = devmode.dmPelsHeight;
|
||||
originalRate = devmode.dmDisplayFrequency;
|
||||
|
||||
const unsigned bpp = devmode.dmBitsPerPel;
|
||||
|
||||
int n = 0;
|
||||
|
||||
while (EnumDisplaySettings(NULL, n++, &devmode)) {
|
||||
if (devmode.dmBitsPerPel == bpp)
|
||||
addMode(devmode, infoVector, NULL, NULL);
|
||||
}
|
||||
|
||||
devmode.dmPelsWidth = originalWidth;
|
||||
devmode.dmPelsHeight = originalHeight;
|
||||
devmode.dmDisplayFrequency = originalRate;
|
||||
|
||||
addMode(devmode, infoVector, &fullResIndex, &fullRateIndex);
|
||||
}
|
||||
|
||||
GdiToggler::~GdiToggler() {
|
||||
setFullMode(false);
|
||||
delete mon;
|
||||
}
|
||||
|
||||
const QRect GdiToggler::fullScreenRect(const QWidget */*wdgt*/) const {
|
||||
return QApplication::desktop()->screenGeometry(/*wdgt*/);
|
||||
}
|
||||
/*const QRect GdiToggler::fullScreenRect(const QWidget *wdgt) const {
|
||||
return QApplication::desktop()->screenGeometry(wdgt);
|
||||
}*/
|
||||
|
||||
void GdiToggler::setMode(unsigned /*screen*/, const unsigned resIndex, const unsigned rateIndex) {
|
||||
fullResIndex = resIndex;
|
||||
fullRateIndex = rateIndex;
|
||||
void GdiToggler::setScreen(const QWidget *widget) {
|
||||
unsigned n = QApplication::desktop()->screenNumber(widget);
|
||||
|
||||
if (isFullMode())
|
||||
if (n != widgetScreen && n < mon->numScreens()) {
|
||||
if (isFullMode()) {
|
||||
setFullMode(false);
|
||||
widgetScreen = n;
|
||||
setFullMode(true);
|
||||
} else {
|
||||
widgetScreen = n;
|
||||
emitRate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GdiToggler::setMode(const unsigned screen, const unsigned resIndex, const unsigned rateIndex) {
|
||||
fullResIndex[screen] = resIndex;
|
||||
fullRateIndex[screen] = rateIndex;
|
||||
|
||||
if (isFullMode() && screen == widgetScreen)
|
||||
setFullMode(true);
|
||||
}
|
||||
|
||||
@ -111,23 +213,23 @@ void GdiToggler::setFullMode(const bool enable) {
|
||||
devmode.dmSize = sizeof(DEVMODE);
|
||||
devmode.dmDriverExtra = 0;
|
||||
|
||||
EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &devmode);
|
||||
mon->enumDisplaySettings(widgetScreen, ENUM_CURRENT_SETTINGS, &devmode);
|
||||
const unsigned currentWidth = devmode.dmPelsWidth;
|
||||
const unsigned currentHeight = devmode.dmPelsHeight;
|
||||
const unsigned currentRate = devmode.dmDisplayFrequency;
|
||||
|
||||
if (enable) {
|
||||
const ResInfo &info = infoVector[fullResIndex];
|
||||
const ResInfo &info = infoVector[widgetScreen][fullResIndex[widgetScreen]];
|
||||
devmode.dmPelsWidth = info.w;
|
||||
devmode.dmPelsHeight = info.h;
|
||||
devmode.dmDisplayFrequency = info.rates[fullRateIndex];
|
||||
devmode.dmDisplayFrequency = info.rates[fullRateIndex[widgetScreen]];
|
||||
|
||||
if (!isFull) {
|
||||
originalWidth = currentWidth;
|
||||
originalHeight = currentHeight;
|
||||
originalRate = currentRate;
|
||||
}
|
||||
} else {
|
||||
} else if (isFull) {
|
||||
devmode.dmPelsWidth = originalWidth;
|
||||
devmode.dmPelsHeight = originalHeight;
|
||||
devmode.dmDisplayFrequency = originalRate;
|
||||
@ -135,7 +237,7 @@ void GdiToggler::setFullMode(const bool enable) {
|
||||
|
||||
if (devmode.dmPelsWidth != currentWidth || devmode.dmPelsHeight != currentHeight || devmode.dmDisplayFrequency != currentRate) {
|
||||
devmode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY;
|
||||
ChangeDisplaySettings(&devmode, CDS_FULLSCREEN);
|
||||
mon->changeDisplaySettings(widgetScreen, &devmode, enable ? CDS_FULLSCREEN : 0);
|
||||
|
||||
if (devmode.dmDisplayFrequency != currentRate)
|
||||
emit rateChange(devmode.dmDisplayFrequency);
|
||||
@ -148,6 +250,6 @@ void GdiToggler::emitRate() {
|
||||
DEVMODE devmode;
|
||||
devmode.dmSize = sizeof(DEVMODE);
|
||||
devmode.dmDriverExtra = 0;
|
||||
EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &devmode);
|
||||
mon->enumDisplaySettings(widgetScreen, ENUM_CURRENT_SETTINGS, &devmode);
|
||||
emit rateChange(devmode.dmDisplayFrequency);
|
||||
}
|
||||
|
@ -21,37 +21,39 @@
|
||||
#define GDITOGGLER_H_
|
||||
|
||||
#include "../fullmodetoggler.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <vector>
|
||||
|
||||
#include "../resinfo.h"
|
||||
|
||||
class GdiToggler : public FullModeToggler {
|
||||
Q_OBJECT
|
||||
|
||||
std::vector<ResInfo> infoVector;
|
||||
|
||||
class MultiMon;
|
||||
|
||||
MultiMon *const mon;
|
||||
std::vector<std::vector<ResInfo> > infoVector;
|
||||
std::vector<unsigned> fullResIndex;
|
||||
std::vector<unsigned> fullRateIndex;
|
||||
unsigned originalWidth;
|
||||
unsigned originalHeight;
|
||||
unsigned originalRate;
|
||||
unsigned fullResIndex;
|
||||
unsigned fullRateIndex;
|
||||
unsigned widgetScreen;
|
||||
bool isFull;
|
||||
|
||||
public:
|
||||
GdiToggler();
|
||||
~GdiToggler();
|
||||
unsigned currentResIndex(unsigned /*screen*/) const { return fullResIndex; }
|
||||
unsigned currentRateIndex(unsigned /*screen*/) const { return fullRateIndex; }
|
||||
const QRect fullScreenRect(const QWidget *w) const;
|
||||
unsigned currentResIndex(unsigned screen) const { return fullResIndex[screen]; }
|
||||
unsigned currentRateIndex(unsigned screen) const { return fullRateIndex[screen]; }
|
||||
//const QRect fullScreenRect(const QWidget *w) const;
|
||||
bool isFullMode() const { return isFull; }
|
||||
void setMode(unsigned screen, unsigned resIndex, unsigned rateIndex);
|
||||
void setFullMode(bool enable);
|
||||
void emitRate();
|
||||
const std::vector<ResInfo>& modeVector(unsigned /*screen*/) const { return infoVector; }
|
||||
void setScreen(const QWidget */*widget*/) {}
|
||||
unsigned screen() const { return 0; }
|
||||
unsigned screens() const { return 1; }
|
||||
const std::vector<ResInfo>& modeVector(unsigned screen) const { return infoVector[screen]; }
|
||||
void setScreen(const QWidget *widget);
|
||||
unsigned screen() const { return widgetScreen; }
|
||||
unsigned screens() const { return infoVector.size(); }
|
||||
|
||||
signals:
|
||||
void rateChange(int newHz);
|
||||
|
@ -145,7 +145,7 @@ void QuartzToggler::setFullMode(const bool enable) {
|
||||
CGDirectDisplayID display = activeDspys[widgetScreen];
|
||||
CFDictionaryRef currentMode = CGDisplayCurrentMode(display);
|
||||
|
||||
CFDictionaryRef mode;
|
||||
CFDictionaryRef mode = currentMode;
|
||||
|
||||
if (enable) {
|
||||
int bpp = 0;
|
||||
@ -162,7 +162,7 @@ void QuartzToggler::setFullMode(const bool enable) {
|
||||
|
||||
if (!isFull)
|
||||
originalMode = currentMode;
|
||||
} else
|
||||
} else if (isFull)
|
||||
mode = originalMode;
|
||||
|
||||
if (mode != currentMode) {
|
||||
|
@ -242,9 +242,6 @@ void MainWindow::correctFullScreenGeometry() {
|
||||
|
||||
if (geometry() != screenRect) {
|
||||
setGeometry(screenRect);
|
||||
#ifdef Q_WS_WIN
|
||||
showFullScreen();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -255,9 +252,27 @@ void MainWindow::toggleFullScreen() {
|
||||
resetWindowSize(videoDialog->winRes());
|
||||
activateWindow();
|
||||
} else {
|
||||
const int screen = QApplication::desktop()->screenNumber(this);
|
||||
|
||||
fullModeToggler->setFullMode(true);
|
||||
saveWindowSize(size());
|
||||
resetWindowSize(QSize(-1, -1));
|
||||
|
||||
// If the window is outside the screen it will be moved to the primary screen by Qt.
|
||||
{
|
||||
const QRect &rect = QApplication::desktop()->screenGeometry(screen);
|
||||
QPoint p(pos());
|
||||
|
||||
if (p.x() > rect.right())
|
||||
p.setX(rect.right());
|
||||
|
||||
if (p.y() > rect.bottom())
|
||||
p.setY(rect.bottom());
|
||||
|
||||
if (p != pos())
|
||||
move(p);
|
||||
}
|
||||
|
||||
showFullScreen();
|
||||
correctFullScreenGeometry();
|
||||
}
|
||||
@ -369,6 +384,10 @@ void MainWindow::videoSettingsChange() {
|
||||
fullModeToggler->setMode(i, videoDialog->fullMode(i), videoDialog->fullRate(i));
|
||||
|
||||
if (fullModeToggler->isFullMode() && i == fullModeToggler->screen()) {
|
||||
#ifdef Q_WS_WIN
|
||||
showNormal();
|
||||
showFullScreen();
|
||||
#endif
|
||||
correctFullScreenGeometry();
|
||||
}
|
||||
}
|
||||
|
@ -168,7 +168,7 @@ sourceIndexStore(0)
|
||||
restore();
|
||||
|
||||
for (unsigned i = 0; i < hzIndex.size(); ++i) {
|
||||
hzIndex[i] = filterValue(hzSelector[i]->findData(settings.value("hz" + QString::number(i)).toUInt()),
|
||||
hzIndex[i] = filterValue(hzSelector[i]->findText(settings.value("hz" + QString::number(i)).toString()),
|
||||
hzSelector[i]->count(),
|
||||
0,
|
||||
resHandler->currentRateIndex(i));
|
||||
@ -195,7 +195,7 @@ VideoDialog::~VideoDialog() {
|
||||
settings.setValue("winIndex", winIndex);
|
||||
|
||||
for (unsigned i = 0; i < hzIndex.size(); ++i) {
|
||||
settings.setValue("hz" + QString::number(i), fullRate(i));
|
||||
settings.setValue("hz" + QString::number(i), hzSelector[i]->itemText(hzIndex[i]));
|
||||
}
|
||||
|
||||
settings.setValue("scalingType", (int)scaling);
|
||||
@ -349,7 +349,7 @@ void VideoDialog::engineChange(int index) {
|
||||
|
||||
void VideoDialog::fullresChange(int index) {
|
||||
for (unsigned i = 0; i < fullResSelector.size(); ++i) {
|
||||
if (fullResSelector[i]->currentIndex() == index) {
|
||||
if (sender() == fullResSelector[i]) {
|
||||
hzSelector[i]->clear();
|
||||
|
||||
if (index >= 0) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user