- one more decimal position in refresh rate representation.

- use xrandr screen names
- hide empty full mode comboboxes
- windowed resolution -> window size
- lots of refactoring.


git-svn-id: https://gambatte.svn.sourceforge.net/svnroot/gambatte@247 9dfb2916-2d38-0410-aef4-c5fe6c9ffc24
This commit is contained in:
sinamas 2011-08-01 06:01:08 +00:00
parent e1470f5279
commit d21f4d5f91
42 changed files with 1347 additions and 1253 deletions

View File

@ -30,8 +30,10 @@ class Array : Uncopyable {
public:
Array(const std::size_t size = 0) : a(size ? new T[size] : 0), sz(size) {}
~Array() { delete []a; }
void reset(const std::size_t size) { delete []a; a = size ? new T[size] : 0; sz = size; }
void reset(const std::size_t size = 0) { delete []a; a = size ? new T[size] : 0; sz = size; }
std::size_t size() const { return sz; }
T * get() { return a; }
const T * get() const { return a; }
operator T*() { return a; }
operator const T*() const { return a; }
};

View File

@ -46,7 +46,6 @@ public:
bool operator==(AudioEngineConf r) const { return ae == r.ae; }
bool operator!=(AudioEngineConf r) const { return ae != r.ae; }
operator ConstAudioEngineConf() { return ConstAudioEngineConf(ae); }
operator const ConstAudioEngineConf() const { return ConstAudioEngineConf(ae); }
};

View File

@ -48,7 +48,6 @@ public:
bool operator==(BlitterConf r) const { return blitter == r.blitter; }
bool operator!=(BlitterConf r) const { return blitter != r.blitter; }
operator ConstBlitterConf() { return ConstBlitterConf(blitter); }
operator const ConstBlitterConf() const { return ConstBlitterConf(blitter); }
};

View File

@ -13,7 +13,8 @@ SOURCES += framework/src/blittercontainer.cpp \
framework/src/mediaworker.cpp \
framework/src/samplebuffer.cpp \
framework/src/blitterwidget.cpp \
framework/src/joysticklock.cpp
framework/src/joysticklock.cpp \
framework/src/persistcheckbox.cpp
SOURCES += $$COMMONPATH/resample/src/chainresampler.cpp \
$$COMMONPATH/resample/src/i0.cpp \
$$COMMONPATH/resample/src/makesinckernel.cpp \
@ -31,6 +32,7 @@ HEADERS += framework/src/blitterwidget.h \
framework/inputdialog.h \
framework/src/audioengine.h \
framework/audioengineconf.h \
framework/persistcheckbox.h \
framework/src/addaudioengines.h \
framework/src/addblitterwidgets.h \
framework/src/getfullmodetoggler.h \

View File

@ -93,7 +93,7 @@ private:
void restore();
public:
InputDialog(const std::vector<Button> &buttonInfos,
explicit InputDialog(const std::vector<Button> &buttonInfos,
bool deleteButtonActions = true,
QWidget *parent = 0);
~InputDialog();
@ -108,7 +108,7 @@ public slots:
void reject();
};
// used in implementation of InputDialog
// used in the implementation of InputDialog, included here because it's a Q_OBJECT
class InputBox : public QLineEdit {
Q_OBJECT
@ -130,7 +130,7 @@ protected:
public:
enum { NULL_VALUE = 0, KBD_VALUE = 0x7FFFFFFF };
InputBox(QWidget *nextFocus = 0);
explicit InputBox(QWidget *nextFocus = 0);
void setData(const SDL_Event &data) { setData(data.id, data.value); }
void setData(unsigned id, int value = KBD_VALUE);
void setNextFocus(QWidget *const nextFocus) { this->nextFocus = nextFocus; }
@ -140,7 +140,7 @@ public slots:
void clearData() { setData(0, NULL_VALUE); }
};
// used in implementation of InputDialog
// used in the implementation of InputDialog, included here because it's a Q_OBJECT
class InputBoxPair : public QObject {
Q_OBJECT

View File

@ -71,7 +71,7 @@ class MainWindow : public QMainWindow {
PixelBuffer::PixelFormat pixelFormat = PixelBuffer::RGB32*/) : width(width), height(height)/*, pixelFormat(pixelFormat)*/ {}
};
class JoystickIniter {
class JoystickIniter : Uncopyable {
std::vector<SDL_Joystick*> joysticks;
public:
JoystickIniter();
@ -97,10 +97,8 @@ class MainWindow : public QMainWindow {
QSize windowSize;
Rational frameTime_;
unsigned focusPauseBit;
// int timerId;
int hz;
int refreshRate;
bool running;
// bool threaded;
bool refreshRateSync;
bool cursorHidden;
@ -118,7 +116,7 @@ class MainWindow : public QMainWindow {
void execPausedQueue();
void updateMinimumSize();
void setBlitter(BlitterWidget *blitter);
void setVideo(unsigned w, unsigned h, /*PixelBuffer::PixelFormat pf,*/ /*const VideoFilter *vf, */BlitterWidget *blitter);
void setVideo(unsigned w, unsigned h, BlitterWidget *blitter);
void correctFullScreenGeometry();
void doSetWindowSize(const QSize &sz);
void updateSwapInterval();
@ -127,14 +125,14 @@ class MainWindow : public QMainWindow {
void emitAudioEngineFailure() { emit audioEngineFailure(); worker->recover(); }
private slots:
void hzChange(int hz);
void refreshRateChange(int refreshRate);
void updateJoysticks();
public:
/** Can be used to gain frame buffer access outside the MediaSource
* methods that take the frame buffer as argument.
* The frame buffer is the buffer that a MediaSource should write
* its video content to. It's generally not an actual video memory frame buffer.
* its video content to.
*/
class FrameBuffer {
MainWindow *const mw;
@ -151,7 +149,7 @@ public:
};
};
MainWindow(MediaSource *source);
explicit MainWindow(MediaSource *source);
/** Sets the duration in seconds of each video frame.
* Eg. use setFrameTime(1, 60) for 60 fps video.
@ -230,12 +228,6 @@ public:
setVideo(w, h,/* pf,*/ blitters[blitterNo]);
}
/** Will synchronize frame rate to vertical retrace if the blitter supports a swapInterval of at least 1.
* Picks a swapInterval closest to the current frame rate.
* Literally speeds things up or slows things down to match the swapInterval. Audio pitch will change accordingly.
*/
void setSyncToRefreshRate(bool on);
/** speed = N, gives N times faster than normal when fastForward is enabled. */
void setFastForwardSpeed(unsigned speed) { worker->setFastForwardSpeed(speed); }
@ -251,6 +243,8 @@ public:
/** Returns the modes supported by each screen. */
const std::vector<ResInfo>& modeVector(unsigned screen) const { return fullModeToggler->modeVector(screen); }
const QString screenName(unsigned screen) const { return fullModeToggler->screenName(screen); }
/** Returns the number of screens. */
unsigned screens() const { return fullModeToggler->screens(); }
@ -309,6 +303,12 @@ public slots:
void hideCursor();
void setFastForward(bool enable) { worker->setFastForward(enable); }
/** Will synchronize frame rate to vertical retrace if the blitter supports a swapInterval of at least 1.
* Picks a swapInterval closest to the current frame rate.
* Literally speeds things up or slows things down to match the swapInterval. Audio pitch will change accordingly.
*/
void setSyncToRefreshRate(bool on);
signals:
void audioEngineFailure();
void videoBlitterFailure();

View File

@ -0,0 +1,41 @@
/***************************************************************************
* Copyright (C) 2011 by Sindre Aamås *
* aamas@stud.ntnu.no *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License version 2 as *
* published by the Free Software Foundation. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License version 2 for more details. *
* *
* You should have received a copy of the GNU General Public License *
* version 2 along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef PERSIST_CHECKBOX_H
#define PERSIST_CHECKBOX_H
#include <QString>
class QCheckBox;
class QWidget;
class PersistCheckBox {
QCheckBox *const checkBox_;
const QString key_;
bool value_;
public:
PersistCheckBox(QCheckBox *checkBox, const QString &key, bool defaultValue);
~PersistCheckBox();
void accept();
void reject() const;
bool value() const { return value_; }
QCheckBox * checkBox() const { return checkBox_; }
};
#endif

View File

@ -19,6 +19,6 @@
#ifndef SCALINGMETHOD_H
#define SCALINGMETHOD_H
enum ScalingMethod { UNRESTRICTED, KEEP_RATIO, INTEGER };
enum ScalingMethod { UNRESTRICTED, KEEP_RATIO, INTEGER }; enum { NUM_SCALING_METHODS = INTEGER + 1 };
#endif

View File

@ -29,6 +29,7 @@ public:
typedef typename std::vector<T*, Allocator>::size_type size_type;
explicit auto_vector(const Allocator& a = Allocator()) : std::vector<T*, Allocator>(a) {}
explicit auto_vector(size_type n, const Allocator& a = Allocator()) : std::vector<T*, Allocator>(n, 0, a) {}
explicit auto_vector(const std::vector<T*, Allocator> &v) : std::vector<T*, Allocator>(v) {}
template<class InputIterator>
auto_vector(InputIterator first, InputIterator last, const Allocator& a = Allocator()) : std::vector<T*, Allocator>(first, last, a) {}

View File

@ -40,7 +40,7 @@ class FtEst {
unsigned count;
public:
FtEst(long frameTime = 0) { init(frameTime); }
explicit FtEst(long frameTime = 0) { init(frameTime); }
void init(long frameTime);
void update(usec_t t);
long est() const { return (ftAvg + UP / 2) >> UPSHIFT; }
@ -51,8 +51,6 @@ class BlitterWidget : public QWidget {
VideoBufferLocker vbl;
const QString nameString_;
const unsigned maxSwapInterval_;
private:
bool paused;
protected:
@ -93,7 +91,10 @@ public:
// return pf == pixbuf.pixelFormat;
}
virtual void setCorrectedGeometry(int w, int h, int new_w, int new_h) { setGeometry((w - new_w) >> 1, (h - new_h) >> 1, new_w, new_h); }
virtual void setCorrectedGeometry(int w, int h, int new_w, int new_h) {
setGeometry((w - new_w) >> 1, (h - new_h) >> 1, new_w, new_h);
}
virtual long frameTimeEst() const { return 0; }
virtual long sync() { return 0; }
virtual void setExclusive(bool) {}

View File

@ -1,5 +1,5 @@
/***************************************************************************
* Copyright (C) 2008 by Sindre Aamås *
* Copyright (C) 2008 by Sindre Aam<EFBFBD>s *
* aamas@stud.ntnu.no *
* *
* This program is free software; you can redistribute it and/or modify *
@ -76,7 +76,7 @@ Direct3DBlitter::Direct3DBlitter(VideoBufferLocker vbl, QWidget *parent) :
backBufferWidth(1),
backBufferHeight(1),
clear(0),
hz(0),
dhz(600),
swapInterval(0),
adapterIndex(0),
exclusive(false),
@ -329,7 +329,7 @@ void Direct3DBlitter::setSwapInterval(const unsigned newSwapInterval) {
if (newSwapInterval != swapInterval) {
swapInterval = newSwapInterval;
resetDevice();
ftEst.init(hz ? swapInterval * 1000000 / hz : 0);
ftEst.init(swapInterval * 10000000 / dhz);
}
}
@ -356,7 +356,7 @@ void Direct3DBlitter::present() {
if (device) {
if (swapInterval) {
const unsigned long estft = ftEst.est();
const usec_t swaplimit = getusecs() - lastblank > estft - estft / 32 ? estft * 2 - 500000 / hz : 0;
const usec_t swaplimit = getusecs() - lastblank > estft - estft / 32 ? estft * 2 - 5000000 / dhz : 0;
device->Present(NULL, NULL, 0, NULL);
@ -590,9 +590,9 @@ void Direct3DBlitter::rejectSettings() const {
bfBox->setChecked(bf);
}
void Direct3DBlitter::rateChange(int hz) {
this->hz = hz;
ftEst.init(hz ? swapInterval * 1000000 / hz : 0);
void Direct3DBlitter::rateChange(const int dhz) {
this->dhz = dhz ? dhz : 600;
ftEst.init(swapInterval * 10000000 / this->dhz);
}
void Direct3DBlitter::resizeEvent(QResizeEvent */*e*/) {

View File

@ -50,7 +50,7 @@ class Direct3DBlitter : public BlitterWidget {
unsigned backBufferWidth;
unsigned backBufferHeight;
unsigned clear;
unsigned hz;
unsigned dhz;
unsigned swapInterval;
unsigned adapterIndex;
bool exclusive;
@ -94,7 +94,7 @@ public:
QPaintEngine* paintEngine () const { return NULL; }
void setSwapInterval(unsigned si);
void rateChange(int hz);
void rateChange(int dhz);
};
#endif /*DIRECT3DBLITTER_H_*/

View File

@ -61,7 +61,7 @@ DirectDrawBlitter::DirectDrawBlitter(VideoBufferLocker vbl, QWidget *parent) :
pixelFormat(PixelBuffer::RGB32),
lastblank(0),
clear(0),
hz(0),
dhz(600),
swapInterval(0),
deviceIndex(0),
inWidth(1),
@ -495,7 +495,7 @@ long DirectDrawBlitter::frameTimeEst() const {
void DirectDrawBlitter::setSwapInterval(const unsigned newSwapInterval) {
if (newSwapInterval != swapInterval) {
swapInterval = newSwapInterval;
ftEst.init(hz ? swapInterval * 1000000 / hz : 0);
ftEst.init(swapInterval * 10000000 / dhz);
}
}
@ -550,7 +550,7 @@ long DirectDrawBlitter::sync() {
if (exclusive & flipping) {
if (swapInterval) {
const unsigned long estft = ftEst.est();
const usec_t swaplimit = getusecs() - lastblank > estft - estft / 32 ? estft * 2 - 500000 / hz : 0;
const usec_t swaplimit = getusecs() - lastblank > estft - estft / 32 ? estft * 2 - 5000000 / dhz : 0;
if (!blitted)
finalBlit(DDBLT_WAIT);
@ -584,7 +584,7 @@ long DirectDrawBlitter::sync() {
}
} else {
if (const unsigned si = swapInterval ? swapInterval : vblank) {
const usec_t refreshPeriod = 1000000 / hz;
const usec_t refreshPeriod = 10000000 / dhz;
while (getusecs() - lastblank < (si - 1) * refreshPeriod + refreshPeriod / 2)
Sleep(1);
@ -600,7 +600,7 @@ long DirectDrawBlitter::sync() {
ftEst.update(lastblank);
blitted = false;
if (ddrval != DD_OK && ddrval != DDERR_WASSTILLDRAWING)
std::cout << "lpDDSPrimary->Flip failed" << std::endl;
@ -648,9 +648,9 @@ void DirectDrawBlitter::rejectSettings() const {
deviceSelector->setCurrentIndex(deviceIndex);
}
void DirectDrawBlitter::rateChange(int hz) {
this->hz = hz;
ftEst.init(hz ? swapInterval * 1000000 / hz : 0);
void DirectDrawBlitter::rateChange(const int dhz) {
this->dhz = dhz ? dhz : 600;
ftEst.init(swapInterval * 10000000 / this->dhz);
}
void DirectDrawBlitter::paintEvent(QPaintEvent */*event*/) {

View File

@ -46,7 +46,7 @@ class DirectDrawBlitter : public BlitterWidget {
PixelBuffer::PixelFormat pixelFormat;
usec_t lastblank;
unsigned clear;
unsigned hz;
unsigned dhz;
unsigned swapInterval;
unsigned deviceIndex;
unsigned inWidth;
@ -94,7 +94,7 @@ public:
QPaintEngine* paintEngine () const { return NULL; }
void rateChange(int hz);
void rateChange(int dhz);
void setSwapInterval(unsigned si);
};

View File

@ -60,7 +60,6 @@ protected:
public:
SubWidget(unsigned swapInterval, bool bf, QGLBlitter *parent);
~SubWidget();
void blit();
//void blitFront();
@ -118,20 +117,6 @@ QGLBlitter::SubWidget::SubWidget(const unsigned swapInterval_in, const bool bf_i
setAutoBufferSwap(false);
setMouseTracking(true);
// setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
// QSettings settings;
// settings.beginGroup("qglsubwidget");
// bf = settings.value("bf", true).toBool();
// settings.endGroup();
}
QGLBlitter::SubWidget::~SubWidget() {
uninit();
// QSettings settings;
// settings.beginGroup("qglsubwidget");
// settings.setValue("bf", bf);
// settings.endGroup();
}
void QGLBlitter::SubWidget::blit() {
@ -292,45 +277,24 @@ void QGLBlitter::SubWidget::updateTexture(quint32 *const buffer) {
QGLBlitter::QGLBlitter(VideoBufferLocker vbl, QWidget *parent) :
BlitterWidget(vbl, QString("OpenGL"), 2, parent),
confWidget(new QWidget),
vsyncBox(new QCheckBox(QString("Wait for vertical blank"))),
bfBox(new QCheckBox(QString("Bilinear filtering"))),
buffer(NULL),
vsync_(new QCheckBox(QString("Wait for vertical blank")), "qglblitter/vsync", false),
bf_(new QCheckBox(QString("Bilinear filtering")), "qglblitter/bf", true),
swapInterval_(0),
hz(60)
// hz1(60),
// hz2(119)
dhz(600),
subWidget(new SubWidget(0, bf_.value(), this))
{
// setLayout(new QVBoxLayout);
// layout()->setMargin(0);
// layout()->setSpacing(0);
// layout()->addWidget(subWidget);
QSettings settings;
settings.beginGroup("qglblitter");
vsync = settings.value("vsync", false).toBool();
bf = settings.value("bf", true).toBool();
settings.endGroup();
confWidget->setLayout(new QVBoxLayout);
confWidget->layout()->setMargin(0);
confWidget->layout()->addWidget(vsyncBox);
confWidget->layout()->addWidget(bfBox);
vsyncBox->setChecked(vsync);
bfBox->setChecked(bf);
subWidget = new SubWidget(0, bf, this);
confWidget->layout()->addWidget(vsync_.checkBox());
confWidget->layout()->addWidget(bf_.checkBox());
}
QGLBlitter::~QGLBlitter() {
uninit();
// delete subWidget;
QSettings settings;
settings.beginGroup("qglblitter");
settings.setValue("vsync", vsync);
settings.setValue("bf", bf);
settings.endGroup();
}
void QGLBlitter::resizeEvent(QResizeEvent *const event) {
@ -339,9 +303,7 @@ void QGLBlitter::resizeEvent(QResizeEvent *const event) {
void QGLBlitter::uninit() {
subWidget->uninit();
delete []buffer;
buffer = NULL;
buffer.reset();
}
bool QGLBlitter::isUnusable() const {
@ -349,8 +311,7 @@ bool QGLBlitter::isUnusable() const {
}
void QGLBlitter::setBufferDimensions(const unsigned int width, const unsigned int height) {
delete []buffer;
buffer = new quint32[width * height];
buffer.reset(width * height);
subWidget->setBufferDimensions(width, height);
setPixelBuffer(buffer, PixelBuffer::RGB32, width);
@ -444,7 +405,7 @@ void QGLBlitter::resetSubWidget() {
// else if (hz == hz2 || hz == hz1 * 2)
// swapInterval = 2;
// }
const unsigned swapInterval = swapInterval_ ? swapInterval_ : vsync;
const unsigned swapInterval = swapInterval_ ? swapInterval_ : vsync_.value();
if (swapInterval == subWidget->getSwapInterval())
return;
@ -455,29 +416,28 @@ void QGLBlitter::resetSubWidget() {
const unsigned h = subWidget->getInHeight();
// subWidget->hide();
delete subWidget;
subWidget = new SubWidget(swapInterval, bf, this);
subWidget.reset();
subWidget.reset(new SubWidget(swapInterval, bf_.value(), this));
subWidget->corrected_w = corrected_w;
subWidget->corrected_h = corrected_h;
subWidget->setGeometry(0, 0, width(), height());
subWidget->show();
ftEst.init(hz ? swapInterval * 1000000 / hz : 0);
ftEst.init(swapInterval * 10000000 / dhz);
if (buffer)
subWidget->setBufferDimensions(w, h);
}
void QGLBlitter::acceptSettings() {
bf = bfBox->isChecked();
subWidget->setBilinearFiltering(bf);
vsync = vsyncBox->isChecked();
bf_.accept();
subWidget->setBilinearFiltering(bf_.value());
vsync_.accept();
resetSubWidget();
}
void QGLBlitter::rejectSettings() const {
vsyncBox->setChecked(vsync);
bfBox->setChecked(bf);
vsync_.reject();
bf_.reject();
}
void QGLBlitter::setSwapInterval(unsigned si) {
@ -485,7 +445,7 @@ void QGLBlitter::setSwapInterval(unsigned si) {
resetSubWidget();
}
void QGLBlitter::rateChange(const int hz) {
this->hz = hz;
ftEst.init(hz ? subWidget->getSwapInterval() * 1000000 / hz : 0);
void QGLBlitter::rateChange(const int dhz) {
this->dhz = dhz ? dhz : 600;
ftEst.init(subWidget->getSwapInterval() * 10000000 / this->dhz);
}

View File

@ -1,5 +1,5 @@
/***************************************************************************
* Copyright (C) 2007 by Sindre Aam<EFBFBD>s *
* Copyright (C) 2007 by Sindre Aamås *
* aamas@stud.ntnu.no *
* *
* This program is free software; you can redistribute it and/or modify *
@ -20,23 +20,21 @@
#define QGLBLITTER_H
#include "../blitterwidget.h"
#include "../../persistcheckbox.h"
#include "array.h"
#include <memory>
class QCheckBox;
class QGLBlitter : public BlitterWidget {
class SubWidget;
FtEst ftEst;
SubWidget *subWidget;
const std::auto_ptr<QWidget> confWidget;
QCheckBox *const vsyncBox;
QCheckBox *const bfBox;
quint32 *buffer;
PersistCheckBox vsync_;
PersistCheckBox bf_;
Array<quint32> buffer;
unsigned swapInterval_;
int hz;
bool vsync;
bool bf;
int dhz;
std::auto_ptr<SubWidget> subWidget;
void resetSubWidget();
void privSetPaused(const bool /*paused*/) {}
@ -46,9 +44,8 @@ protected:
void resizeEvent(QResizeEvent *event);
public:
QGLBlitter(VideoBufferLocker vbl, QWidget *parent = 0);
explicit QGLBlitter(VideoBufferLocker vbl, QWidget *parent = 0);
~QGLBlitter();
// void init();
void uninit();
bool isUnusable() const;
void setCorrectedGeometry(int w, int h, int new_w, int new_h);
@ -58,12 +55,11 @@ public:
long sync();
QWidget* settingsWidget() const { return confWidget.get(); }
// // public slots:
void acceptSettings();
void rejectSettings() const;
void setSwapInterval(unsigned);
void rateChange(int hz);
void rateChange(int dhz);
};

View File

@ -1,5 +1,5 @@
/***************************************************************************
* Copyright (C) 2007 by Sindre Aam<EFBFBD>s *
* Copyright (C) 2007 by Sindre Aamås *
* aamas@stud.ntnu.no *
* *
* This program is free software; you can redistribute it and/or modify *
@ -27,32 +27,18 @@
QPainterBlitter::QPainterBlitter(VideoBufferLocker vbl, QWidget *parent) :
BlitterWidget(vbl, "QPainter", false, parent),
confWidget(new QWidget),
bfBox(new QCheckBox(QString("Semi-bilinear filtering"))),
buffer(NULL),
inWidth(160),
inHeight(144),
bf(false)
bf_(new QCheckBox(QString("Semi-bilinear filtering"), confWidget.get()), "qpainterblitter/bf", false),
buffer(0)
{
QSettings settings;
settings.beginGroup("qpainterblitter");
bf = settings.value("bf", false).toBool();
settings.endGroup();
confWidget->setLayout(new QVBoxLayout);
confWidget->layout()->setMargin(0);
confWidget->layout()->addWidget(bfBox);
bfBox->setChecked(bf);
confWidget->layout()->addWidget(bf_.checkBox());
setAttribute(Qt::WA_OpaquePaintEvent, true);
}
QPainterBlitter::~QPainterBlitter() {
uninit();
QSettings settings;
settings.beginGroup("qpainterblitter");
settings.setValue("bf", bf);
settings.endGroup();
}
void QPainterBlitter::blit() {
@ -60,10 +46,13 @@ void QPainterBlitter::blit() {
backImage = backImage == image2.get() ? image.get() : image2.get();
setPixelBuffer(backImage->bits(), PixelBuffer::RGB32, backImage->bytesPerLine() >> 2);
} else {
if (bf)
semiLinearScale<quint32, 0xFF00FF, 0x00FF00, 8>(buffer, reinterpret_cast<quint32*>(image->bits()), inWidth, inHeight, image->width(), image->height(), image->bytesPerLine() >> 2);
else
nearestNeighborScale(buffer, reinterpret_cast<quint32*>(image->bits()), inWidth, inHeight, image->width(), image->height(), image->bytesPerLine() >> 2);
if (bf_.value()) {
semiLinearScale<quint32, 0xFF00FF, 0x00FF00, 8>(buffer, reinterpret_cast<quint32*>(image->bits()),
inBuffer().width, inBuffer().height, image->width(), image->height(), image->bytesPerLine() >> 2);
} else {
nearestNeighborScale(buffer, reinterpret_cast<quint32*>(image->bits()),
inBuffer().width, inBuffer().height, image->width(), image->height(), image->bytesPerLine() >> 2);
}
}
}
@ -84,15 +73,12 @@ void QPainterBlitter::paintEvent(QPaintEvent *const event) {
void QPainterBlitter::resizeEvent(QResizeEvent */*event*/) {
if (image.get()) {
lockPixelBuffer();
setBufferDimensions(inWidth, inHeight);
setBufferDimensions(inBuffer().width, inBuffer().height);
unlockPixelBuffer();
}
}
void QPainterBlitter::setBufferDimensions(const unsigned int w, const unsigned int h) {
inWidth = w;
inHeight = h;
uninit();
image.reset(new QImage(width(), height(), QImage::Format_RGB32));
@ -119,9 +105,9 @@ void QPainterBlitter::uninit() {
}
void QPainterBlitter::acceptSettings() {
bf = bfBox->isChecked();
bf_.accept();
}
void QPainterBlitter::rejectSettings() const {
bfBox->setChecked(bf);
bf_.reject();
}

View File

@ -20,6 +20,7 @@
#define QPAINTERBLITTER_H
#include "../blitterwidget.h"
#include "../../persistcheckbox.h"
#include <memory>
#include <QImage>
@ -30,10 +31,8 @@ class QPainterBlitter : public BlitterWidget {
const std::auto_ptr<QWidget> confWidget;
std::auto_ptr<QImage> image;
std::auto_ptr<QImage> image2;
QCheckBox *const bfBox;
PersistCheckBox bf_;
union { quint32 *buffer; QImage *backImage; };
unsigned int inWidth, inHeight;
bool bf;
protected:
void privSetPaused(bool) {}
@ -41,7 +40,7 @@ protected:
void resizeEvent(QResizeEvent *event);
public:
QPainterBlitter(VideoBufferLocker vbl, QWidget *parent = 0);
explicit QPainterBlitter(VideoBufferLocker vbl, QWidget *parent = 0);
~QPainterBlitter();
void blit();
void draw();

View File

@ -1,5 +1,5 @@
/***************************************************************************
* Copyright (C) 2007 by Sindre Aam<EFBFBD>s *
* Copyright (C) 2007 by Sindre Aamås *
* aamas@stud.ntnu.no *
* *
* This program is free software; you can redistribute it and/or modify *
@ -40,7 +40,7 @@ public:
virtual ~SubBlitter() {};
};
class X11Blitter::ShmBlitter : public SubBlitter {
class X11Blitter::ShmBlitter : public SubBlitter, Uncopyable {
XShmSegmentInfo shminfo;
XImage *ximage;
const bool doubleBuffer;
@ -56,7 +56,6 @@ public:
X11Blitter::ShmBlitter::ShmBlitter(const unsigned width, const unsigned height, const VisInfo &visInfo, const bool db) : doubleBuffer(db) {
shminfo.shmaddr = NULL;
std::cout << "creating shm ximage...\n";
ximage = XShmCreateImage(QX11Info::display(), reinterpret_cast<Visual*>(visInfo.visual), visInfo.depth, ZPixmap, NULL, &shminfo, width, height);
if (ximage == NULL) {
@ -110,8 +109,8 @@ unsigned X11Blitter::ShmBlitter::pitch() const {
return ximage ? ximage->width : 0;
}
class X11Blitter::PlainBlitter : public X11Blitter::SubBlitter {
XImage *ximage;
class X11Blitter::PlainBlitter : public X11Blitter::SubBlitter, Uncopyable {
XImage *const ximage;
char *data;
bool doubleBuffer() const { return data; }
@ -125,25 +124,26 @@ public:
~PlainBlitter();
};
X11Blitter::PlainBlitter::PlainBlitter(const unsigned int width, const unsigned int height, const VisInfo &visInfo, const bool db) : data(0) {
std::cout << "creating ximage...\n";
ximage = XCreateImage(QX11Info::display(), reinterpret_cast<Visual*>(visInfo.visual), visInfo.depth, ZPixmap, 0, NULL, width, height, visInfo.depth <= 16 ? 16 : 32, 0);
if (ximage == NULL) {
std::cout << "failed to create ximage\n";
} else {
X11Blitter::PlainBlitter::PlainBlitter(const unsigned int width, const unsigned int height, const VisInfo &visInfo, const bool db)
: ximage(XCreateImage(QX11Info::display(), reinterpret_cast<Visual*>(visInfo.visual),
visInfo.depth, ZPixmap, 0, NULL, width, height, visInfo.depth <= 16 ? 16 : 32, 0)),
data(0)
{
if (ximage) {
ximage->data = new char[ximage->bytes_per_line * ximage->height << db];
if (db)
data = ximage->data;
} else {
std::cout << "failed to create ximage\n";
}
}
X11Blitter::PlainBlitter::~PlainBlitter () {
if (ximage) {
if (doubleBuffer())
if (doubleBuffer()) {
delete[] data;
else
} else
delete[] ximage->data;
XFree(ximage);
@ -243,24 +243,14 @@ static XVisualInfo* getVisualPtr() {
X11Blitter::X11Blitter(VideoBufferLocker vbl, QWidget *parent) :
BlitterWidget(vbl, QString("X11"), false, parent),
confWidget(new QWidget),
bfBox(new QCheckBox(QString("Semi-bilinear filtering"))),
buffer(NULL),
inWidth(160),
inHeight(144),
bf(false)
bf_(new QCheckBox(QString("Semi-bilinear filtering")), "x11blitter/bf", false)
{
visInfo.visual = NULL;
visInfo.depth = 0;
QSettings settings;
settings.beginGroup("x11blitter");
bf = settings.value("bf", false).toBool();
settings.endGroup();
confWidget->setLayout(new QVBoxLayout);
confWidget->layout()->setMargin(0);
confWidget->layout()->addWidget(bfBox);
bfBox->setChecked(bf);
confWidget->layout()->addWidget(bf_.checkBox());
setAttribute(Qt::WA_OpaquePaintEvent, true);
setAttribute(Qt::WA_PaintOnScreen, true);
@ -272,32 +262,20 @@ bf(false)
}
}
X11Blitter::~X11Blitter() {
}
bool X11Blitter::isUnusable() const {
return visInfo.visual == NULL;
}
void X11Blitter::init() {
XSync(QX11Info::display(), 0);
shm = XShmQueryExtension(QX11Info::display());
// shm = false;
std::cout << "shm: " << shm << std::endl;
}
void X11Blitter::uninit() {
subBlitter.reset();
delete[] buffer;
buffer = NULL;
}
X11Blitter::~X11Blitter() {
uninit();
QSettings settings;
settings.beginGroup("x11blitter");
settings.setValue("bf", bf);
settings.endGroup();
buffer.reset();
}
long X11Blitter::sync() {
@ -331,12 +309,11 @@ void X11Blitter::paintEvent(QPaintEvent *event) {
}
void X11Blitter::setBufferDimensions(const unsigned int w, const unsigned int h) {
inWidth = w;
inHeight = h;
uninit();
const bool scale = width() != static_cast<int>(w) || height() != static_cast<int>(h);
bool shm = XShmQueryExtension(QX11Info::display());
std::cout << "shm: " << shm << std::endl;
if (shm) {
subBlitter.reset(new ShmBlitter(width(), height(), visInfo, !scale));
@ -351,7 +328,7 @@ void X11Blitter::setBufferDimensions(const unsigned int w, const unsigned int h)
subBlitter.reset(new PlainBlitter(width(), height(), visInfo, !scale));
if (scale) {
buffer = new char[w * h * (visInfo.depth <= 16 ? 2 : 4)];
buffer.reset(w * h * (visInfo.depth <= 16 ? 2 : 4));
setPixelBuffer(buffer, visInfo.depth <= 16 ? PixelBuffer::RGB16 : PixelBuffer::RGB32, w);
} else
setPixelBuffer(subBlitter->pixels(), visInfo.depth <= 16 ? PixelBuffer::RGB16 : PixelBuffer::RGB32, subBlitter->pitch());
@ -360,24 +337,24 @@ void X11Blitter::setBufferDimensions(const unsigned int w, const unsigned int h)
void X11Blitter::blit() {
if (buffer) {
if (visInfo.depth <= 16) {
if (bf) {
semiLinearScale<quint16, 0xF81F, 0x07E0, 6>(reinterpret_cast<quint16*>(buffer),
static_cast<quint16*>(subBlitter->pixels()),
inWidth, inHeight, width(), height(), subBlitter->pitch());
if (bf_.value()) {
semiLinearScale<quint16, 0xF81F, 0x07E0, 6>(
reinterpret_cast<quint16*>(buffer.get()), static_cast<quint16*>(subBlitter->pixels()),
inBuffer().width, inBuffer().height, width(), height(), subBlitter->pitch());
} else {
nearestNeighborScale(reinterpret_cast<quint16*>(buffer),
nearestNeighborScale(reinterpret_cast<quint16*>(buffer.get()),
static_cast<quint16*>(subBlitter->pixels()),
inWidth, inHeight, width(), height(), subBlitter->pitch());
inBuffer().width, inBuffer().height, width(), height(), subBlitter->pitch());
}
} else {
if (bf) {
semiLinearScale<quint32, 0xFF00FF, 0x00FF00, 8>(reinterpret_cast<quint32*>(buffer),
static_cast<quint32*>(subBlitter->pixels()),
inWidth, inHeight, width(), height(), subBlitter->pitch());
if (bf_.value()) {
semiLinearScale<quint32, 0xFF00FF, 0x00FF00, 8>(
reinterpret_cast<quint32*>(buffer.get()), static_cast<quint32*>(subBlitter->pixels()),
inBuffer().width, inBuffer().height, width(), height(), subBlitter->pitch());
} else {
nearestNeighborScale(reinterpret_cast<quint32*>(buffer),
nearestNeighborScale(reinterpret_cast<quint32*>(buffer.get()),
static_cast<quint32*>(subBlitter->pixels()),
inWidth, inHeight, width(), height(), subBlitter->pitch());
inBuffer().width, inBuffer().height, width(), height(), subBlitter->pitch());
}
}
} else {
@ -389,15 +366,15 @@ void X11Blitter::blit() {
void X11Blitter::resizeEvent(QResizeEvent */*event*/) {
if (subBlitter.get()) {
lockPixelBuffer();
setBufferDimensions(inWidth, inHeight);
setBufferDimensions(inBuffer().width, inBuffer().height);
unlockPixelBuffer();
}
}
void X11Blitter::acceptSettings() {
bf = bfBox->isChecked();
bf_.accept();
}
void X11Blitter::rejectSettings() const {
bfBox->setChecked(bf);
bf_.reject();
}

View File

@ -20,11 +20,10 @@
#define X11BLITTER_H
#include "../blitterwidget.h"
#include "../../persistcheckbox.h"
#include "array.h"
#include <memory>
class QCheckBox;
class X11Blitter : public BlitterWidget {
class SubBlitter;
class ShmBlitter;
@ -37,13 +36,9 @@ class X11Blitter : public BlitterWidget {
const std::auto_ptr<QWidget> confWidget;
std::auto_ptr<SubBlitter> subBlitter;
QCheckBox *const bfBox;
char *buffer;
unsigned int inWidth, inHeight;
PersistCheckBox bf_;
Array<char> buffer;
VisInfo visInfo;
// unsigned int scale;
bool shm;
bool bf;
protected:
void setBufferDimensions(const unsigned width, const unsigned height);
@ -51,7 +46,7 @@ protected:
void resizeEvent(QResizeEvent *event);
public:
X11Blitter(VideoBufferLocker vbl, QWidget *parent = 0);
explicit X11Blitter(VideoBufferLocker vbl, QWidget *parent = 0);
~X11Blitter();
void init();
void uninit();
@ -62,7 +57,7 @@ public:
void acceptSettings();
void rejectSettings() const;
QPaintEngine* paintEngine() const { return NULL; }
QPaintEngine* paintEngine() const { return 0; }
};
#endif

View File

@ -1,5 +1,5 @@
/***************************************************************************
* Copyright (C) 2007 by Sindre Aam<EFBFBD>s *
* Copyright (C) 2007 by Sindre Aamås *
* aamas@stud.ntnu.no *
* *
* This program is free software; you can redistribute it and/or modify *
@ -23,6 +23,7 @@
#include <QList>
#include "xvblitter.h"
#include "uncopyable.h"
#include <iostream>
@ -58,7 +59,6 @@ public:
};
XvBlitter::ShmBlitter::ShmBlitter(const XvPortID xvport, const int formatid, const unsigned int width, const unsigned int height) {
std::cout << "creating shm xvimage...\n";
shminfo.shmaddr = NULL;
xvimage = XvShmCreateImage(QX11Info::display(), xvport, formatid, NULL, width << (formatid != 3), height, &shminfo);
@ -114,7 +114,7 @@ unsigned XvBlitter::ShmBlitter::pitch() const {
}
class XvBlitter::PlainBlitter : public SubBlitter {
XvImage *xvimage;
XvImage *const xvimage;
char *data;
public:
@ -127,15 +127,14 @@ public:
~PlainBlitter();
};
XvBlitter::PlainBlitter::PlainBlitter(const XvPortID xvport, const int formatid, const unsigned int width, const unsigned int height) : data(0) {
std::cout << "creating xvimage...\n";
xvimage = XvCreateImage(QX11Info::display(), xvport, formatid, NULL, width << (formatid != 3), height);
if (xvimage == NULL) {
std::cout << "failed to create xvimage\n";
} else {
XvBlitter::PlainBlitter::PlainBlitter(const XvPortID xvport, const int formatid, const unsigned int width, const unsigned int height)
: xvimage(XvCreateImage(QX11Info::display(), xvport, formatid, 0, width << (formatid != 3), height)),
data(0)
{
if (xvimage) {
xvimage->data = data = new char[xvimage->data_size * 2];
}
} else
std::cout << "failed to create xvimage\n";
}
XvBlitter::PlainBlitter::~PlainBlitter() {
@ -173,64 +172,146 @@ unsigned XvBlitter::PlainBlitter::pitch() const {
return xvimage ? xvimage->pitches[0] >> 2 : 0;
}
static int search(const XvImageFormatValues *const formats, const int numFormats, const int id) {
namespace {
class XvAdaptorInfos : Uncopyable {
unsigned num_;
XvAdaptorInfo *infos_;
public:
XvAdaptorInfos() : num_(0), infos_(0) {
if (XvQueryAdaptors(QX11Info::display(), QX11Info::appRootWindow(), &num_, &infos_) != Success) {
std::cout << "failed to query xv adaptors\n";
num_ = 0;
}
}
~XvAdaptorInfos() {
if (infos_)
XvFreeAdaptorInfo(infos_);
}
unsigned len() const { return num_; }
operator const XvAdaptorInfo*() const { return infos_; }
};
class XvPortImageFormats : Uncopyable {
int num_;
XvImageFormatValues *const formats_;
public:
explicit XvPortImageFormats(const XvPortID baseId)
: num_(0), formats_(XvListImageFormats(QX11Info::display(), baseId, &num_))
{
}
~XvPortImageFormats() {
if (formats_)
XFree(formats_);
}
int len() const { return num_; }
operator const XvImageFormatValues*() const { return formats_; }
};
static int findId(const XvPortImageFormats &formats, const int id) {
int i = 0;
while (i < numFormats && formats[i].id != id)
while (i < formats.len() && formats[i].id != id)
++i;
return i;
}
static void addPorts(QComboBox *portSelector) {
unsigned int num_adaptors;
XvAdaptorInfo *adaptor_info;
XvAdaptorInfos adaptors;
if (XvQueryAdaptors(QX11Info::display(), QX11Info::appRootWindow(), &num_adaptors, &adaptor_info) == Success) {
for (unsigned int i = 0; i < num_adaptors; ++i) {
if (!(adaptor_info[i].type & XvImageMask))
continue;
int numFormats;
XvImageFormatValues *const formats = XvListImageFormats(QX11Info::display(), adaptor_info[i].base_id, &numFormats);
int formatId = 0x3;
int j = search(formats, numFormats, formatId);
if (j == numFormats) {
formatId = 0x59565955;
j = search(formats, numFormats, formatId);
}
if (j < numFormats) {
QList<QVariant> l;
l.append(static_cast<uint>(adaptor_info[i].base_id));
l.append(formats[j].id);
portSelector->addItem(adaptor_info[i].name, l);
}
XFree(formats);
for (unsigned i = 0; i < adaptors.len(); ++i) {
if (!(adaptors[i].type & XvImageMask))
continue;
const XvPortImageFormats formats(adaptors[i].base_id);
int formatId = 0x3;
int j = findId(formats, formatId);
if (j == formats.len()) {
formatId = 0x59565955;
j = findId(formats, formatId);
}
XvFreeAdaptorInfo(adaptor_info);
} else {
std::cout << "failed to query xv adaptors\n";
if (j < formats.len()) {
QList<QVariant> l;
l.append(static_cast<uint>(adaptors[i].base_id));
l.append(formats[j].id);
portSelector->addItem(adaptors[i].name, l);
}
}
}
}
XvBlitter::ConfWidget::ConfWidget()
: widget_(new QWidget), portSelector_(new QComboBox(widget_.get())), portIndex_(0)
{
addPorts(portSelector_);
if ((portIndex_ = QSettings().value("xvblitter/portIndex", 0).toUInt()) >= static_cast<unsigned>(portSelector_->count()))
portIndex_ = 0;
restore();
widget_->setLayout(new QHBoxLayout);
widget_->layout()->setMargin(0);
widget_->layout()->addWidget(new QLabel(QString(tr("Xv Port:"))));
widget_->layout()->addWidget(portSelector_);
}
XvBlitter::ConfWidget::~ConfWidget() {
QSettings settings;
settings.setValue("xvblitter/portIndex", portIndex_);
}
void XvBlitter::ConfWidget::store() {
portIndex_ = portSelector_->currentIndex();
}
void XvBlitter::ConfWidget::restore() const {
portSelector_->setCurrentIndex(portIndex_);
}
XvPortID XvBlitter::ConfWidget::portId() const {
return static_cast<XvPortID>(portSelector_->itemData(portIndex_).toList().front().toUInt());
}
int XvBlitter::ConfWidget::formatId() const {
return portSelector_->itemData(portIndex_).toList().back().toInt();
}
int XvBlitter::ConfWidget::numPorts() const {
return portSelector_->count();
}
XvBlitter::PortGrabber::PortGrabber() : port_(0), grabbed_(false) {}
XvBlitter::PortGrabber::~PortGrabber() {
ungrab();
}
bool XvBlitter::PortGrabber::grab(const XvPortID port) {
ungrab();
port_ = port;
return grabbed_ = XvGrabPort(QX11Info::display(), port, CurrentTime) == Success;
}
void XvBlitter::PortGrabber::ungrab() {
if (grabbed_) {
XvUngrabPort(QX11Info::display(), port_, CurrentTime);
grabbed_ = false;
}
}
XvBlitter::XvBlitter(VideoBufferLocker vbl, QWidget *parent) :
BlitterWidget(vbl, QString("Xv"), 0, parent),
// xvbuffer(NULL),
// yuv_table(NULL),
// xvimage(NULL),
confWidget(new QWidget()),
portSelector(new QComboBox),
inWidth(160),
inHeight(144),
old_w(0),
old_h(0),
portGrabbed(false),
failed(true),
initialized(false)
{
@ -248,26 +329,10 @@ XvBlitter::XvBlitter(VideoBufferLocker vbl, QWidget *parent) :
gcValues.foreground = gcValues.background = 2110;
gc = XCreateGC(QX11Info::display(), QX11Info::appRootWindow(), GCForeground | GCBackground, &gcValues);
}
QHBoxLayout *layout = new QHBoxLayout;
layout->setMargin(0);
layout->addWidget(new QLabel(QString(tr("Xv Port:"))));
addPorts(portSelector);
layout->addWidget(portSelector);
confWidget->setLayout(layout);
QSettings settings;
settings.beginGroup("xvblitter");
if ((portIndex = settings.value("portIndex", 0).toUInt()) >= static_cast<unsigned>(portSelector->count()))
portIndex = 0;
settings.endGroup();
rejectSettings();
}
bool XvBlitter::isUnusable() const {
return portSelector->count() == 0;
return confWidget.numPorts() == 0;
}
/*static bool getBestPort(const unsigned int num_adaptors, const XvAdaptorInfo *const adaptor_info, XvPortID *const port_out) {
@ -313,46 +378,26 @@ void XvBlitter::init() {
XSync(QX11Info::display(), 0);
shm = XShmQueryExtension(QX11Info::display());
std::cout << "shm: " << shm << std::endl;
initPort();
initialized = true;
}
void XvBlitter::uninit() {
// delete []xvbuffer;
// xvbuffer = NULL;
// delete []yuv_table;
// yuv_table = NULL;
subBlitter.reset();
if (portGrabbed) {
XvUngrabPort(QX11Info::display(), xvport, CurrentTime);
portGrabbed = false;
}
failed = true;
portGrabber.ungrab();
initialized = false;
}
XvBlitter::~XvBlitter() {
uninit();
XFreeGC(QX11Info::display(), gc);
QSettings settings;
settings.beginGroup("xvblitter");
settings.setValue("portIndex", portIndex);
settings.endGroup();
}
long XvBlitter::sync() {
if (failed || subBlitter->failed())
if (!portGrabber.grabbed() || subBlitter->failed())
return -1;
subBlitter->blit(winId(), xvport, width(), height());
subBlitter->blit(winId(), portGrabber.port(), width(), height());
XSync(QX11Info::display(), 0);
return 0;
@ -362,21 +407,21 @@ void XvBlitter::paintEvent(QPaintEvent *event) {
const QRect &rect = event->rect();
XFillRectangle(QX11Info::display(), winId(), gc, rect.x(), rect.y(), rect.width(), rect.height());
if (isPaused() && !failed) {
subBlitter->blit(winId(), xvport, width(), height());
if (isPaused() && portGrabber.grabbed()) {
subBlitter->blit(winId(), portGrabber.port(), width(), height());
}
}
void XvBlitter::setBufferDimensions(const unsigned int width, const unsigned int height) {
inWidth = width;
inHeight = height;
const int formatid = portSelector->itemData(portIndex).toList().back().toInt();
void XvBlitter::setBufferDimensions(const unsigned width, const unsigned height) {
const int formatid = confWidget.formatId();
subBlitter.reset(); // predestruct previous object to ensure resource availability.
bool shm = XShmQueryExtension(QX11Info::display());
std::cout << "shm: " << shm << std::endl;
if (shm) {
subBlitter.reset(new ShmBlitter(xvport, formatid, width, height));
subBlitter.reset(new ShmBlitter(portGrabber.port(), formatid, width, height));
if (subBlitter->failed()) {
shm = false;
@ -385,77 +430,75 @@ void XvBlitter::setBufferDimensions(const unsigned int width, const unsigned int
}
if (!shm)
subBlitter.reset(new PlainBlitter(xvport, formatid, width, height));
subBlitter.reset(new PlainBlitter(portGrabber.port(), formatid, width, height));
// delete []xvbuffer;
// xvbuffer = new u_int16_t[width*height];
setPixelBuffer(subBlitter->pixels(), formatid == 3 ? PixelBuffer::RGB32 : PixelBuffer::UYVY, subBlitter->pitch());
old_w = old_h = 0;
}
void XvBlitter::blit() {
if (!failed) {
/*{
u_int32_t *yuv_pixel = (u_int32_t*)(subBlitter->inBuffer().pixels);
const u_int16_t *s = xvbuffer;
unsigned n = inWidth * inHeight;
while (n--) {
*yuv_pixel++ = yuv_table[*s++];
}
}*/
if (portGrabber.grabbed()) {
subBlitter->flip();
setPixelBuffer(subBlitter->pixels(), inBuffer().pixelFormat, subBlitter->pitch());
}
}
static void setAttrib(XvAttribute *const attribs, const int nattr, const char *const name, const int value, const XvPortID xvport) {
Atom atom;
namespace {
class XvAttributes : Uncopyable {
const XvPortID xvport_;
int numAttribs_;
XvAttribute *const attribs_;
for (int i = 0; i < nattr; ++i) {
if (!strcmp(attribs[i].name, name)) {
if ((atom = XInternAtom(QX11Info::display(), name, True)) != None)
XvSetPortAttribute(QX11Info::display(), xvport, atom, value);
break;
Atom atomOf(const char *const name) const {
for (int i = 0; i < numAttribs_; ++i) {
if (!strcmp(attribs_[i].name, name))
return XInternAtom(QX11Info::display(), name, True);
}
return None;
}
public:
explicit XvAttributes(const XvPortID xvport)
: xvport_(xvport), numAttribs_(0), attribs_(XvQueryPortAttributes(QX11Info::display(), xvport, &numAttribs_))
{
}
~XvAttributes() {
if (attribs_)
XFree(attribs_);
}
void set(const char *const name, const int value) {
const Atom atom = atomOf(name);
if (atom != None)
XvSetPortAttribute(QX11Info::display(), xvport_, atom, value);
}
};
}
void XvBlitter::initPort() {
xvport = static_cast<XvPortID>(portSelector->itemData(portIndex).toList().front().toUInt());
failed = !(portGrabbed = (XvGrabPort(QX11Info::display(), xvport, CurrentTime) == Success));
if (!failed) {
int nattr = 0;
XvAttribute *const attribs = XvQueryPortAttributes(QX11Info::display(), xvport, &nattr);
setAttrib(attribs, nattr, "XV_AUTOPAINT_COLORKEY", 0, xvport);
setAttrib(attribs, nattr, "XV_COLORKEY", 2110, xvport);
XFree(attribs);
if (portGrabber.grab(confWidget.portId())) {
XvAttributes attribs(portGrabber.port());
attribs.set("XV_AUTOPAINT_COLORKEY", 0);
attribs.set("XV_COLORKEY", 2110);
}
}
void XvBlitter::acceptSettings() {
if (static_cast<int>(portIndex) != portSelector->currentIndex()) {
portIndex = portSelector->currentIndex();
if (initialized) {
if (portGrabbed) {
XvUngrabPort(QX11Info::display(), xvport, CurrentTime);
portGrabbed = false;
}
initPort();
lockPixelBuffer();
setBufferDimensions(inWidth, inHeight);
unlockPixelBuffer();
repaint();
}
confWidget.store();
if (initialized && confWidget.portId() != portGrabber.port()) {
initPort();
lockPixelBuffer();
setBufferDimensions(inBuffer().width, inBuffer().height);
unlockPixelBuffer();
repaint();
}
}
void XvBlitter::rejectSettings() const {
portSelector->setCurrentIndex(portIndex);
confWidget.restore();
}

View File

@ -23,6 +23,7 @@
#include <memory>
#include "../blitterwidget.h"
#include "uncopyable.h"
#include <X11/Xlib.h>
#include <X11/extensions/XShm.h>
@ -33,22 +34,38 @@ class XvBlitter : public BlitterWidget {
class ShmBlitter;
class PlainBlitter;
// XShmSegmentInfo shminfo;
class ConfWidget {
const std::auto_ptr<QWidget> widget_;
QComboBox *const portSelector_;
unsigned portIndex_;
public:
ConfWidget();
~ConfWidget();
void store();
void restore() const;
XvPortID portId() const;
int formatId() const;
int numPorts() const;
QWidget * qwidget() const { return widget_.get(); }
};
class PortGrabber : Uncopyable {
XvPortID port_;
bool grabbed_;
public:
PortGrabber();
~PortGrabber();
bool grab(XvPortID port);
void ungrab();
bool grabbed() const { return grabbed_; }
XvPortID port() const { return port_; }
};
ConfWidget confWidget;
PortGrabber portGrabber;
std::auto_ptr<SubBlitter> subBlitter;
XvPortID xvport;
// u_int16_t *xvbuffer;
// u_int32_t *yuv_table;
// XvImage *xvimage;
const std::auto_ptr<QWidget> confWidget;
QComboBox *const portSelector;
unsigned int inWidth, inHeight;
int old_w, old_h;
unsigned portIndex;
GC gc;
// bool init;
bool shm;
bool portGrabbed;
bool failed;
bool initialized;
void initPort();
@ -59,7 +76,7 @@ protected:
// void resizeEvent(QResizeEvent *event);
public:
XvBlitter(VideoBufferLocker vbl, QWidget *parent = 0);
explicit XvBlitter(VideoBufferLocker vbl, QWidget *parent = 0);
~XvBlitter();
void init();
void uninit();
@ -68,7 +85,7 @@ public:
void setBufferDimensions(const unsigned int width, const unsigned int height);
void blit();
QWidget* settingsWidget() const { return confWidget.get(); }
QWidget* settingsWidget() const { return confWidget.qwidget(); }
void acceptSettings();
void rejectSettings() const;

View File

@ -22,6 +22,7 @@
#include <QObject>
#include <QWidget>
#include <QRect>
#include <QString>
#include <vector>
#include "../resinfo.h"
@ -42,6 +43,7 @@ public:
virtual void setScreen(const QWidget *widget) = 0;
virtual unsigned screen() const = 0;
virtual unsigned screens() const = 0;
virtual const QString screenName(unsigned screen) const { return QString::number(screen); }
signals:
void rateChange(int newHz);

View File

@ -1,5 +1,5 @@
/***************************************************************************
* Copyright (C) 2007 by Sindre Aamås *
* Copyright (C) 2007 by Sindre Aam<EFBFBD>s *
* aamas@stud.ntnu.no *
* *
* This program is free software; you can redistribute it and/or modify *
@ -38,7 +38,7 @@ static void addMode(const DEVMODE &devmode, std::vector<ResInfo> &infoVector, un
info.w = devmode.dmPelsWidth;
info.h = devmode.dmPelsHeight;
rate = devmode.dmDisplayFrequency;
rate = devmode.dmDisplayFrequency * 10;
std::vector<ResInfo>::iterator it = std::lower_bound(infoVector.begin(), infoVector.end(), info, std::greater<ResInfo>());
@ -170,7 +170,7 @@ void GdiToggler::setFullMode(const bool enable) {
const ResInfo &info = infoVector[widgetScreen][fullResIndex[widgetScreen]];
devmode.dmPelsWidth = info.w;
devmode.dmPelsHeight = info.h;
devmode.dmDisplayFrequency = info.rates[fullRateIndex[widgetScreen]];
devmode.dmDisplayFrequency = info.rates[fullRateIndex[widgetScreen]] / 10;
} else if (isFull) {
mon->enumDisplaySettings(widgetScreen, ENUM_REGISTRY_SETTINGS, &devmode);
}
@ -180,7 +180,7 @@ void GdiToggler::setFullMode(const bool enable) {
mon->changeDisplaySettings(widgetScreen, &devmode, enable ? CDS_FULLSCREEN : 0);
if (devmode.dmDisplayFrequency != currentRate)
emit rateChange(devmode.dmDisplayFrequency);
emit rateChange(devmode.dmDisplayFrequency * 10);
}
isFull = enable;
@ -191,5 +191,5 @@ void GdiToggler::emitRate() {
devmode.dmSize = sizeof(DEVMODE);
devmode.dmDriverExtra = 0;
mon->enumDisplaySettings(widgetScreen, ENUM_CURRENT_SETTINGS, &devmode);
emit rateChange(devmode.dmDisplayFrequency);
emit rateChange(devmode.dmDisplayFrequency * 10);
}

View File

@ -1,5 +1,5 @@
/***************************************************************************
* Copyright (C) 2008 by Sindre Aamås *
* Copyright (C) 2008 by Sindre Aamås *
* aamas@stud.ntnu.no *
* *
* This program is free software; you can redistribute it and/or modify *
@ -44,7 +44,7 @@ static void addMode(CFDictionaryRef mode, std::vector<ResInfo> &infoVector, unsi
info.w = w;
info.h = h;
rate = static_cast<short>(r + 0.5);
rate = static_cast<short>(r * 10.0 + 0.5);
}
std::vector<ResInfo>::iterator it = std::lower_bound(infoVector.begin(), infoVector.end(), info, std::greater<ResInfo>());
@ -156,7 +156,7 @@ void QuartzToggler::setFullMode(const bool enable) {
bpp,
infoVector[widgetScreen][fullResIndex[widgetScreen]].w,
infoVector[widgetScreen][fullResIndex[widgetScreen]].h,
infoVector[widgetScreen][fullResIndex[widgetScreen]].rates[fullRateIndex[widgetScreen]],
infoVector[widgetScreen][fullResIndex[widgetScreen]].rates[fullRateIndex[widgetScreen]] / 10.0,
NULL
);
@ -174,8 +174,8 @@ void QuartzToggler::setFullMode(const bool enable) {
CFNumberGetValue(static_cast<CFNumberRef>(CFDictionaryGetValue(currentMode, kCGDisplayRefreshRate)), kCFNumberDoubleType, &oldRate);
CFNumberGetValue(static_cast<CFNumberRef>(CFDictionaryGetValue(mode, kCGDisplayRefreshRate)), kCFNumberDoubleType, &newRate);
if (static_cast<int>(oldRate + 0.5) != static_cast<int>(newRate + 0.5))
emit rateChange(static_cast<int>(newRate + 0.5));
if (static_cast<int>(oldRate * 10.0 + 0.5) != static_cast<int>(newRate * 10.0 + 0.5))
emit rateChange(static_cast<int>(newRate * 10.0 + 0.5));
}
isFull = enable;
@ -186,5 +186,5 @@ void QuartzToggler::emitRate() {
CFNumberGetValue(static_cast<CFNumberRef>(CFDictionaryGetValue(CGDisplayCurrentMode(activeDspys[widgetScreen]), kCGDisplayRefreshRate)), kCFNumberDoubleType, &rate);
emit rateChange(static_cast<int>(rate + 0.5));
emit rateChange(static_cast<int>(rate * 10.0 + 0.5));
}

View File

@ -1,5 +1,5 @@
/***************************************************************************
* Copyright (C) 2008 by Sindre Aamås *
* Copyright (C) 2008 by Sindre Aam<EFBFBD>s *
* aamas@stud.ntnu.no *
* *
* This program is free software; you can redistribute it and/or modify *
@ -57,7 +57,7 @@ static inline bool operator>(const ResInfo &l, const ResInfo &r) {
static unsigned getRate(const unsigned dotclock, const unsigned htotal, const unsigned vtotal) {
if (unsigned long pixels = htotal * vtotal)
return (dotclock * 1000ul + (pixels >> 1)) / pixels;
return (dotclock * 10000ull + (pixels >> 1)) / pixels;
return 0;
}

View File

@ -1,5 +1,5 @@
/***************************************************************************
* Copyright (C) 2008 by Sindre Aam<EFBFBD>s *
* Copyright (C) 2008 by Sindre Aamås *
* aamas@stud.ntnu.no *
* *
* This program is free software; you can redistribute it and/or modify *
@ -17,6 +17,7 @@
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "xrandr12toggler.h"
#include "uncopyable.h"
#include <functional>
#include <algorithm>
#include <QWidget>
@ -30,9 +31,9 @@ static inline bool operator>(const ResInfo &l, const ResInfo &r) {
return l.w > r.w || (l.w == r.w && l.h > r.h);
}
static unsigned getRate(const unsigned dotclock, const unsigned htotal, const unsigned vtotal) {
static unsigned getRate(const unsigned long dotclock, const unsigned htotal, const unsigned vtotal) {
if (unsigned long pixels = htotal * vtotal)
return (dotclock + (pixels >> 1)) / pixels;
return (dotclock * 10ull + (pixels >> 1)) / pixels;
return 0;
}
@ -76,19 +77,19 @@ static XRRModeInfo* getModeInfo(const XRRScreenResources *const resources, const
}
static bool isGood(const RRMode mode, const std::vector<XRROutputInfo*> &outputInfos) {
bool good = true;
for (std::size_t o = 0; o < outputInfos.size() && good; ++o) {
int mm = 0;
while ((good = mm < outputInfos[o]->nmode) && outputInfos[o]->modes[mm] != mode)
++mm;
for (std::size_t o = 0; o < outputInfos.size(); ++o) {
RRMode *const modesEnd = outputInfos[o]->modes + outputInfos[o]->nmode;
if (std::find(outputInfos[o]->modes, modesEnd, mode) == modesEnd)
return false;
}
return good;
return true;
}
class OutputInfos {
namespace {
class OutputInfos : Uncopyable {
std::vector<XRROutputInfo*> v;
public:
OutputInfos(XRRScreenResources *resources, const XRRCrtcInfo *crtcInfo);
@ -96,8 +97,10 @@ public:
const std::vector<XRROutputInfo*>& get() { return v; }
};
OutputInfos::OutputInfos(XRRScreenResources *const resources, const XRRCrtcInfo *const crtcInfo) : v(crtcInfo->noutput) {
for (int i = 0; i < crtcInfo->noutput;) {
OutputInfos::OutputInfos(XRRScreenResources *const resources, const XRRCrtcInfo *const crtcInfo)
: v(crtcInfo ? crtcInfo->noutput : 0)
{
for (std::size_t i = 0; i < v.size();) {
v[i] = XRRGetOutputInfo(QX11Info::display(), resources, crtcInfo->outputs[i]);
if (v[i])
@ -112,11 +115,12 @@ OutputInfos::~OutputInfos() {
XRRFreeOutputInfo(v[i]);
}
class CrtcInfoPtr {
class CrtcInfoPtr : Uncopyable {
XRRCrtcInfo *const crtcInfo;
public:
CrtcInfoPtr(XRRScreenResources *const resources, const RRCrtc crtc) : crtcInfo(XRRGetCrtcInfo(QX11Info::display(), resources, crtc)) {}
CrtcInfoPtr(XRRScreenResources *const resources, const RRCrtc crtc)
: crtcInfo(XRRGetCrtcInfo(QX11Info::display(), resources, crtc)) {}
~CrtcInfoPtr() { if (crtcInfo) XRRFreeCrtcInfo(crtcInfo); }
operator XRRCrtcInfo*() { return crtcInfo; }
operator const XRRCrtcInfo*() const { return crtcInfo; }
@ -148,6 +152,8 @@ static RRMode getMode(XRRScreenResources *const resources, const XRRCrtcInfo *co
return crtcInfo->mode;
}
}
bool XRandR12Toggler::isUsable() {
int unused = 0;
int major = 1;
@ -300,8 +306,7 @@ void XRandR12Toggler::setFullMode(const bool enable) {
}
void XRandR12Toggler::emitRate() {
CrtcInfoPtr crtcInfo(resources, resources->crtcs[widgetScreen]);
const CrtcInfoPtr crtcInfo(resources, resources->crtcs[widgetScreen]);
short rate = 0;
if (crtcInfo) {
@ -311,3 +316,12 @@ void XRandR12Toggler::emitRate() {
emit rateChange(rate);
}
const QString XRandR12Toggler::screenName(const unsigned screen) const {
OutputInfos outputInfos(resources, CrtcInfoPtr(resources, resources->crtcs[screen]));
if (!outputInfos.get().empty())
return QString(outputInfos.get()[0]->name);
return FullModeToggler::screenName(screen);
}

View File

@ -1,5 +1,5 @@
/***************************************************************************
* Copyright (C) 2008 by Sindre Aam<EFBFBD>s *
* Copyright (C) 2008 by Sindre Aamås *
* aamas@stud.ntnu.no *
* *
* This program is free software; you can redistribute it and/or modify *
@ -20,10 +20,11 @@
#define XRANDR12TOGGLER_H_
#include "../fullmodetoggler.h"
#include "uncopyable.h"
#include <X11/Xlib.h>
#include <X11/extensions/Xrandr.h>
class XRandR12Toggler : public FullModeToggler {
class XRandR12Toggler : public FullModeToggler, Uncopyable {
Q_OBJECT
RRMode originalMode;
@ -49,6 +50,7 @@ public:
void setScreen(const QWidget *widget);
unsigned screen() const { return widgetScreen; }
unsigned screens() const { return infoVector.size(); }
const QString screenName(unsigned screen) const;
signals:
void rateChange(int newHz);

View File

@ -32,7 +32,7 @@ bool XRandRToggler::isUsable() {
}
XRandRToggler::XRandRToggler() :
config(0),
config(XRRGetScreenInfo(QX11Info::display(), QX11Info::appRootWindow())),
originalResIndex(0),
fullResIndex(0),
rotation(0),
@ -40,7 +40,6 @@ fullRateIndex(0),
originalRate(0),
isFull(false)
{
config = XRRGetScreenInfo(QX11Info::display(), QX11Info::appRootWindow());
fullResIndex = originalResIndex = XRRConfigCurrentConfiguration(config, &rotation);
originalRate = XRRConfigCurrentRate(config);
@ -56,7 +55,7 @@ isFull(false)
short *rates = XRRConfigRates(config, i, &nHz);
for (int j = 0; j < nHz; ++j)
info.rates.push_back(rates[j]);
info.rates.push_back(rates[j] * 10);
infoVector.push_back(info);
}
@ -64,11 +63,11 @@ isFull(false)
{
unsigned i = 0;
while (i < infoVector[fullResIndex].rates.size() && infoVector[fullResIndex].rates[i] != originalRate)
while (i < infoVector[fullResIndex].rates.size() && infoVector[fullResIndex].rates[i] != originalRate * 10)
++i;
if (i == infoVector[fullResIndex].rates.size())
infoVector[fullResIndex].rates.push_back(originalRate);
infoVector[fullResIndex].rates.push_back(originalRate * 10);
fullRateIndex = i;
}
@ -118,7 +117,7 @@ void XRandRToggler::setFullMode(const bool enable) {
if (enable) {
newID = fullResIndex;
newRate = infoVector[fullResIndex].rates[fullRateIndex];
newRate = infoVector[fullResIndex].rates[fullRateIndex] / 10;
if (!isFull) {
originalResIndex = currentID;
@ -133,12 +132,12 @@ void XRandRToggler::setFullMode(const bool enable) {
XRRSetScreenConfigAndRate(QX11Info::display(), config, QX11Info::appRootWindow(), newID, rotation, newRate, CurrentTime);
if (newRate != currentRate)
emit rateChange(newRate);
emit rateChange(newRate * 10);
}
isFull = enable;
}
void XRandRToggler::emitRate() {
emit rateChange(XRRConfigCurrentRate(config));
emit rateChange(XRRConfigCurrentRate(config) * 10);
}

View File

@ -20,15 +20,16 @@
#define XRANDRTOGGLER_H
#include "../fullmodetoggler.h"
#include "uncopyable.h"
#include <X11/Xlib.h>
#include <X11/extensions/Xrandr.h>
class XRandRToggler : public FullModeToggler {
class XRandRToggler : public FullModeToggler, Uncopyable {
Q_OBJECT
std::vector<ResInfo> infoVector;
XRRScreenConfiguration *config;
XRRScreenConfiguration *const config;
unsigned originalResIndex;
unsigned fullResIndex;
Rotation rotation;

View File

@ -47,9 +47,7 @@ MainWindow::JoystickIniter::JoystickIniter() {
const int numJs = SDL_NumJoysticks();
for (int i = 0; i < numJs; ++i) {
SDL_Joystick *joy = SDL_JoystickOpen(i);
if (joy)
if (SDL_Joystick *joy = SDL_JoystickOpen(i))
joysticks.push_back(joy);
}
@ -74,12 +72,6 @@ struct MainWindow::Pauser::DoPause {
void operator()(MainWindow *const mw) {
if (mw->running) {
mw->worker->pause();
// if (mw->timerId) {
// mw->killTimer(mw->timerId);
// mw->timerId = 0;
// }
mw->jsTimer->start();
}
@ -92,9 +84,6 @@ struct MainWindow::Pauser::DoUnpause {
if (mw->running) {
mw->jsTimer->stop();
mw->worker->unpause();
// if (!mw->threaded && !mw->timerId)
// mw->timerId = mw->startTimer(0);
}
mw->blitterContainer->blitter()->setPaused(false);
@ -141,14 +130,14 @@ public:
bool tryLockVideoBuffer() { return mw->vbmut.tryLock(); }
void unlockVideoBuffer() { mw->vbmut.unlock(); }
const PixelBuffer& videoBuffer() {
return /*mw->videoChain.empty() ? */mw->blitterContainer->blitter()->inBuffer()/* : mw->videoChain.front()->inBuffer()*/;
return mw->blitterContainer->blitter()->inBuffer();
}
};
void MainWindow::WorkerCallback::blit(const usec_t synctimebase, const usec_t synctimeinc) {
struct BlitEvent : CustomEvent {
WorkerCallback &cb;
BlitEvent(WorkerCallback &cb) : cb(cb) {}
explicit BlitEvent(WorkerCallback &cb) : cb(cb) {}
void exec(MainWindow *const mw) {
if (blitRequested(cb.blitState) && mw->running) {
@ -241,10 +230,8 @@ MainWindow::MainWindow(MediaSource *const source)
windowSize(-1, -1),
frameTime_(1, 60),
focusPauseBit(0),
// timerId(0),
hz(60),
refreshRate(600),
running(false),
// threaded(true),
refreshRateSync(false),
cursorHidden(false)
{
@ -277,7 +264,7 @@ MainWindow::MainWindow(MediaSource *const source)
blitterContainer->setMinimumSize(QSize(imageFormat.width, imageFormat.height));
blitterContainer->setSourceSize(QSize(imageFormat.width, imageFormat.height));
blitterContainer->setAspectRatio(QSize(imageFormat.width, imageFormat.height));
connect(fullModeToggler.get(), SIGNAL(rateChange(int)), this, SLOT(hzChange(int)));
connect(fullModeToggler.get(), SIGNAL(rateChange(int)), this, SLOT(refreshRateChange(int)));
fullModeToggler->emitRate();
cursorTimer->setSingleShot(true);
@ -308,11 +295,7 @@ void MainWindow::run() {
if (pauser.isPaused()) {
jsTimer->start();
worker->pause();
}/* else if (!threaded)
timerId = startTimer(0);*/
// if (!threaded)
// worker->deactivate();
}
SDL_JoystickUpdate();
SDL_ClearEvents();
@ -325,14 +308,8 @@ void MainWindow::stop() {
worker->stop();
jsTimer->stop();
// videoChain.clear();
running = false;
// if (timerId) {
// killTimer(timerId);
// timerId = 0;
// }
blitterContainer->blitter()->uninit();
blitterContainer->blitter()->setVisible(false);
@ -342,44 +319,18 @@ void MainWindow::stop() {
}
void MainWindow::rebuildVideoChain() {
ImageFormat ifmt(imageFormat);
/*videoChain.clear(); // and delete. can we do better than complete reinitialization?
if (vfilter) {
VideoLink *const filterLink = vfilter->create(ifmt.width, ifmt.height, ifmt.pixelFormat);
if (filterLink->inBuffer().pixelFormat != ifmt.pixelFormat) {
videoChain.push_back(VideoFormatConverter::create(ifmt.width,
ifmt.height, ifmt.pixelFormat, vfilter->inBuffer().pixelFormat));
}
videoChain.push_back(filterLink);
ifmt.width = filterLink->outWidth();
ifmt.height = filterLink->outHeight();
ifmt.pixelFormat = filterLink->outPixelFormat();
}*/
/*if (!*/blitterContainer->blitter()->setVideoFormat(ifmt.width, ifmt.height/*, ifmt.pixelFormat*/)/*) {*/;
// videoChain.push_back(VideoFormatConverter::create(ifmt.width, ifmt.height,
// ifmt.pixelFormat, blitterContainer->blitter()->inBuffer().pixelFormat));
// }
// worker->setVideoBuffer(/*videoChain.empty() ? */blitterContainer->blitter()->inBuffer()/* : videoChain.front()->inBuffer()*/);
}
static const QSize getFilteredSize(const QSize &sz/*, const VideoFiler *const filter*/) {
return /*filter ? filter->outSize(sz) : */sz;
blitterContainer->blitter()->setVideoFormat(imageFormat.width, imageFormat.height);
}
void MainWindow::updateMinimumSize() {
if (layout()->sizeConstraint() != QLayout::SetFixedSize)
centralWidget()->setMinimumSize(getFilteredSize(QSize(imageFormat.width, imageFormat.height)/*, vfilter*/));
centralWidget()->setMinimumSize(QSize(imageFormat.width, imageFormat.height));
}
void MainWindow::doSetWindowSize(const QSize &sz) {
if (!isFullScreen() && isVisible()) {
if (sz == QSize(-1, -1)) {
centralWidget()->setMinimumSize(getFilteredSize(QSize(imageFormat.width, imageFormat.height)/*, vfilter*/));
centralWidget()->setMinimumSize(QSize(imageFormat.width, imageFormat.height));
layout()->setSizeConstraint(QLayout::SetMinimumSize);
setMinimumSize(1, 1); // needed on macx
setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); // needed on macx. needed for metacity full screen switching, layout()->setSizeConstraint(QLayout::SetMinAndMaxSize) won't do.
@ -414,7 +365,7 @@ void MainWindow::setBlitter(BlitterWidget *const blitter) {
blitterContainer->setBlitter(blitter);
blitterContainer->blitter()->setVisible(visible);
blitterContainer->blitter()->setPaused(paused);
blitterContainer->blitter()->rateChange(hz);
blitterContainer->blitter()->rateChange(refreshRate);
updateSwapInterval();
if (running)
@ -422,16 +373,12 @@ void MainWindow::setBlitter(BlitterWidget *const blitter) {
}
}
void MainWindow::setVideo(const unsigned w, const unsigned h,
/*const PixelBuffer::PixelFormat pf,*/ /*const VideoFilter *const vf, */BlitterWidget *const blitter)
void MainWindow::setVideo(const unsigned w, const unsigned h, BlitterWidget *const blitter)
{
if (imageFormat.width != w || imageFormat.height != h /*|| imageFormat.pixelFormat != pf*/ ||
/*vfilter != vf || */blitter != blitterContainer->blitter())
{
if (imageFormat.width != w || imageFormat.height != h || blitter != blitterContainer->blitter()) {
vbmut.lock();
imageFormat = ImageFormat(w, h/*, pf*/);
imageFormat = ImageFormat(w, h);
setBlitter(blitter);
// vfilter = vf;
if (running)
rebuildVideoChain();
@ -556,8 +503,10 @@ void MainWindow::setFrameTime(unsigned num, unsigned denom) {
denom = 1;
}
frameTime_ = Rational(num, denom);
updateSwapInterval();
if (static_cast<long>(num) != frameTime_.num || static_cast<long>(denom) != frameTime_.denom) {
frameTime_ = Rational(num, denom);
updateSwapInterval();
}
}
void MainWindow::waitUntilPaused() {
@ -577,9 +526,9 @@ void MainWindow::setSyncToRefreshRate(bool on) {
void MainWindow::correctFullScreenGeometry() {
const QRect &screenRect = fullModeToggler->fullScreenRect(this);
if (geometry() != screenRect) {
if (geometry() != screenRect)
setGeometry(screenRect);
}
}
void MainWindow::setFullScreenMode(const unsigned screenNo, const unsigned resIndex, const unsigned rateIndex) {
@ -591,7 +540,7 @@ void MainWindow::setFullScreenMode(const unsigned screenNo, const unsigned resIn
if (fullModeToggler->isFullMode() && screenNo == fullModeToggler->screen()) {
#ifdef Q_WS_WIN
showNormal(); // is this really neccessary anymore?
showNormal();
showFullScreen();
#endif
correctFullScreenGeometry();
@ -648,7 +597,7 @@ void MainWindow::updateSwapInterval() {
unsigned si = 0;
if (refreshRateSync) {
si = (frameTime_.num * hz + (frameTime_.denom >> 1)) / frameTime_.denom;
si = (frameTime_.num * refreshRate + (frameTime_.denom * 10 >> 1)) / (frameTime_.denom * 10);
if (si < 1)
si = 1;
@ -659,20 +608,20 @@ void MainWindow::updateSwapInterval() {
blitterContainer->blitter()->setSwapInterval(si);
if (si)
worker->setFrameTime(Rational(si, hz));
else
if (si) {
worker->setFrameTime(Rational(si * 10, refreshRate));
} else
worker->setFrameTime(frameTime_);
worker->setFrameTimeEstimate(blitterContainer->blitter()->frameTimeEst());
}
void MainWindow::hzChange(int hz) {
if (hz < 1)
hz = 60;
void MainWindow::refreshRateChange(int refreshRate) {
if (refreshRate < 1)
refreshRate = 600;
this->hz = hz;
blitterContainer->blitter()->rateChange(hz);
this->refreshRate = refreshRate;
blitterContainer->blitter()->rateChange(refreshRate);
updateSwapInterval();
}

View File

@ -20,6 +20,7 @@
#include "joysticklock.h"
#include "SDL_joystick.h"
#include "../mediasource.h"
#include "skipsched.h"
#ifdef Q_WS_WIN
#include <Objbase.h> // For CoInitialize
@ -44,33 +45,6 @@ void MediaWorker::MeanQueue::push(const long i) {
q.push_back(newelem);
}
// void MediaWorker::FrameWaiter::frameWait(const long syncft, SyncVar &waitingForSync) {
// const usec_t now = getusecs();
//
// if (now - base < syncft) {
// {
// SyncVar::Locked wfs(waitingForSync);
//
// /*while*/if (!wfs.get() && /*wfs.wait(now, syncft - (now - base)*/ wfs.wait((syncft - (now - base)) / 1000))
// ;
//
// if (wfs.get())
// wfs.set(false);
// }
//
// asleep.sleepUntil(base, syncft);
// base += syncft;
// } else
// base = now;
// }
//
// void MediaWorker::FrameWaiter::syncedFrameWait(const long ft) {
// if (ft) {
// base += asleep.sleepUntil(base, ft);
// base += ft;
// }
// }
void MediaWorker::PauseVar::unpause(const unsigned bits) {
mut.lock();
@ -108,14 +82,11 @@ meanQueue(0, 0),
frameTimeEst(0),
doneVar(true),
sampleBuffer(source),
ae(NULL),
ae(0),
usecft(0),
estsrate(0),
base(0),
/*turbo(0), */
aelatency(0),
aerate(0),
audioBufLow(false) {
aerate(0) {
}
void MediaWorker::start() {
@ -131,10 +102,8 @@ void MediaWorker::start() {
void MediaWorker::stop() {
AtomicVar<bool>::Locked(doneVar).set(true);
// SyncVar::Locked(syncVar_).set(PREPARE);
pauseVar.unpause(~0U);
wait();
// SyncVar::Locked(syncVar_).set(0);
pauseVar.rewait();
sampleBuffer.setOutSampleRate(0);
sndOutBuffer.reset(0);
@ -275,26 +244,6 @@ long MediaWorker::adaptToRateEstimation(const long estft) {
return calculateSyncft(sampleBuffer.resamplerOutRate(), estsrate, usecft);
}
// we try to force the sync to begin in the GUI thread before we continue, which is why this code looks a bit funky.
// static void signalSync(SyncVar &syncVar, MediaWorker::Callback *cb) {
// // unsigned sync;
//
// {
// SyncVar::Locked sv(syncVar);
// sv.set(/*sync = */(sv.get() & PREPARE) ? 0 : SYNC);
// }
//
// // if (sync)
// // cb->sync();
//
// {
// SyncVar::Locked sv(syncVar);
//
// while (sv.get() & SYNC)
// sv.wait();
// }
// }
long MediaWorker::sourceUpdate() {
class VidBuf {
Callback *cb;
@ -311,7 +260,6 @@ long MediaWorker::sourceUpdate() {
const PixelBuffer& get() const { return pb; }
} vidbuf(callback.get());
// turbo += turbo << 4;
updateJoysticks();
return sampleBuffer.update(vidbuf.get());
}
@ -342,15 +290,6 @@ static usec_t frameWait(const usec_t base, const usec_t syncft, SyncVar &waiting
}
static void blitWait(MediaWorker::Callback *const cb, SyncVar &waitingForSync) {
// unsigned notAcked;
//
// {
// SyncVar::Locked sv(syncVar);
//
// if ((notAcked = sv.get() & PREPARE))
// sv.set(0);
// }
if (!cb->cancelBlit()) {
SyncVar::Locked wfs(waitingForSync);
@ -370,10 +309,30 @@ static bool audioBufIsLow(const AudioEngine::BufferState &bstate, const int outs
void MediaWorker::run() {
#ifdef Q_WS_WIN
CoInitializeEx(NULL, COINIT_MULTITHREADED);
const class CoInit : Uncopyable {
public:
CoInit() { CoInitializeEx(NULL, COINIT_MULTITHREADED); }
~CoInit() { CoUninitialize(); }
} coinit;
#endif
if (ae)
initAudioEngine();
const class AeInit : Uncopyable {
MediaWorker &w_;
public:
explicit AeInit(MediaWorker &w) : w_(w) {
if (w.ae)
w.initAudioEngine();
}
~AeInit() {
if (w_.ae)
w_.ae->uninit();
}
} aeinit(*this);
SkipSched skipSched;
bool audioBufLow = false;
usec_t base = 0;
for (;;) {
pauseVar.waitWhilePaused(callback.get(), ae);
@ -387,15 +346,18 @@ void MediaWorker::run() {
sampleBuffer.read(blitSamples >= 0 ? blitSamples : sampleBuffer.samplesBuffered(), 0);
} else {
const long syncft = blitSamples >= 0 ? adaptToRateEstimation(AtomicVar<long>::ConstLocked(frameTimeEst).get()) : 0;
const bool blit = blitSamples >= 0 && !skipSched.skipNext(audioBufLow);
const bool blit = blitSamples >= 0 && !skipSched.skipNext(audioBufLow);
if (blit)
callback->blit(base, syncft);
{
const long outsamples = sampleBuffer.read(blit ? blitSamples : sampleBuffer.samplesBuffered(),
static_cast<qint16*>(sndOutBuffer));
AudioEngine::BufferState bstate = { AudioEngine::BufferState::NOT_SUPPORTED, AudioEngine::BufferState::NOT_SUPPORTED };
const long outsamples = sampleBuffer.read(
blit ? blitSamples : sampleBuffer.samplesBuffered(),
static_cast<qint16*>(sndOutBuffer));
AudioEngine::BufferState bstate = { AudioEngine::BufferState::NOT_SUPPORTED,
AudioEngine::BufferState::NOT_SUPPORTED };
if (ae->rate() > 0 && ae->write(sndOutBuffer, outsamples, bstate, estsrate) < 0) {
ae->pause();
@ -412,120 +374,22 @@ void MediaWorker::run() {
}
}
}
ae->uninit();
#ifdef Q_WS_WIN
CoUninitialize();
#endif
}
bool MediaWorker::frameStep() {
const long blitSamples = sourceUpdate();
const long outsamples = sampleBuffer.read(
blitSamples >= 0 ? blitSamples : sampleBuffer.samplesBuffered(),
static_cast<qint16*>(sndOutBuffer));
{
const long outsamples = sampleBuffer.read(blitSamples >= 0 ? blitSamples : sampleBuffer.samplesBuffered(),
static_cast<qint16*>(sndOutBuffer));
if (ae->rate() > 0) {
if (ae->write(sndOutBuffer, outsamples) < 0) {
ae->pause();
pauseVar.pause(8);
callback->audioEngineFailure();
} else
ae->pause();
}
if (ae->rate() > 0) {
if (ae->write(sndOutBuffer, outsamples) < 0) {
ae->pause();
pauseVar.pause(8);
callback->audioEngineFailure();
} else
ae->pause();
}
return blitSamples >= 0;
}
#if 0
// returns syncft
long MediaWorker::adaptToRateEstimation(const long estft) {
if (estft) {
meanQueue.push(static_cast<long>(static_cast<float>(estsrate) * estft / (usecft - (usecft >> 11)) + 0.5f));
const long mean = meanQueue.mean();
const long var = std::max(meanQueue.var(), 1);
if (sampleBuffer.resamplerOutRate() < mean || sampleBuffer.resamplerOutRate() > mean + var * 2)
adjustResamplerRate(mean + var);
return 0;
}
if (sampleBuffer.resamplerOutRate() != ae->rate())
adjustResamplerRate(ae->rate());
return calculateSyncft(ae->rate(), estsrate, usecft);
}
void MediaWorker::syncedUpdate(BlitterWidget *const blitter) {
CallQ::Locked(callq)->pop_all();
if (!ae || ae->rate() < 0) { // avoid stupid recursive call detection by checking here rather than on init.
emit soundEngineFailure();
return;
}
long outsamples = 0;
pauseVar.unwait();
const bool blit = sourceUpdate(&outsamples);
pauseVar.rewait();
const long syncft = blit ? adaptToRateEstimation(blitter->frameTimeEst()) : 0;
if (blit)
blitter->prepare();
if (!(turbo & 0x30) && ae->write(sndOutBuffer, outsamples, bstate, estsrate) < 0) {
ae->pause();
emit soundEngineFailure();
return;
}
if (blit) {
frameWaiter.syncedFrameWait(syncft);
if (blitter->sync() < 0) {
emit videoEngineFailure();
return;
}
}
}
void MainWindow::timerEvent(QTimerEvent*) {
worker->syncedUpdate(blitter);
workerPaused(this);
}
// NOTE: callInGuiThread
void MainWindow::setThreaded(const bool threaded) {
if (threaded ^ this->threaded) {
this->threaded = threaded;
if (running) {
if (threaded) {
if (timerId)
killTimer(timerId);
timerId = 0;
worker->reactivate();
} else {
struct StartTimer {
void operator()(MainWindow *const mw) {
if (mw->running && mw->threaded)
mw->timerId = mw->startTimer(0);
}
};
worker->deactivate();
callWhenPaused(StartTimer());
}
}
}
}
#endif

View File

@ -29,7 +29,6 @@
#include "audioengine.h"
#include "uncopyable.h"
#include "usec.h"
#include "skipsched.h"
// enum { PREPARE = 1, SYNC = 2 };
@ -43,7 +42,7 @@ public:
SyncVar &sv;
public:
explicit Locked(SyncVar &sv) : sv(sv) { sv.mut.lock(); }
Locked(SyncVar &sv) : sv(sv) { sv.mut.lock(); }
~Locked() { sv.mut.unlock(); }
unsigned get() const { return sv.var; }
void set(const unsigned var) { sv.var = var; sv.cond.wakeAll(); }
@ -95,7 +94,7 @@ public:
class Locked : Uncopyable {
Mutual &lc;
public:
explicit Locked(Mutual &lc) : lc(lc) { lc.mut.lock(); }
Locked(Mutual &lc) : lc(lc) { lc.mut.lock(); }
~Locked() { lc.mut.unlock(); }
T* operator->() { return &lc.t; }
const T* operator->() const { return &lc.t; }
@ -106,7 +105,7 @@ public:
class ConstLocked : Uncopyable {
const Mutual &lc;
public:
explicit ConstLocked(const Mutual &lc) : lc(lc) { lc.mut.lock(); }
ConstLocked(const Mutual &lc) : lc(lc) { lc.mut.lock(); }
~ConstLocked() { lc.mut.unlock(); }
const T* operator->() const { return &lc.t; }
const T& get() const { return lc.t; }
@ -124,7 +123,7 @@ public:
class Locked : Uncopyable {
AtomicVar &av;
public:
explicit Locked(AtomicVar &av) : av(av) { av.mut.lock(); }
Locked(AtomicVar &av) : av(av) { av.mut.lock(); }
~Locked() { av.mut.unlock(); }
T get() const { return av.var; }
void set(const T v) { av.var = v; }
@ -133,7 +132,7 @@ public:
class ConstLocked : Uncopyable {
const AtomicVar &av;
public:
explicit ConstLocked(const AtomicVar &av) : av(av) { av.mut.lock(); }
ConstLocked(const AtomicVar &av) : av(av) { av.mut.lock(); }
~ConstLocked() { av.mut.unlock(); }
T get() const { return av.var; }
};
@ -155,16 +154,6 @@ public:
};
private:
/*class FrameWaiter {
AdaptiveSleep asleep;
usec_t base;
public:
FrameWaiter() : base(0) {}
void frameWait(long syncft, SyncVar &waitingForSync);
void syncedFrameWait(long syncft);
};*/
class PauseVar {
CallQueue<> callq;
mutable QMutex mut;
@ -231,28 +220,20 @@ private:
struct SetSamplesPerFrame;
struct SetFastForward;
std::auto_ptr<Callback> callback;
// SyncVar syncVar_;
const std::auto_ptr<Callback> callback;
SyncVar waitingForSync_;
// FrameWaiter frameWaiter;
MeanQueue meanQueue;
PauseVar pauseVar;
AtomicVar<long> frameTimeEst;
AtomicVar<bool> doneVar;
SkipSched skipSched;
TurboSkip turboSkip;
SampleBuffer sampleBuffer;
Array<qint16> sndOutBuffer;
AudioEngine *ae;
long usecft;
long estsrate;
usec_t base;
// unsigned turbo;
unsigned aelatency;
int aerate;
// QMutex pbmut;
// PixelBuffer pxbuf;
bool audioBufLow;
long adaptToRateEstimation(long estft);
void adjustResamplerRate(long outRate);
@ -263,11 +244,9 @@ protected:
void run();
public:
MediaWorker(MediaSource *source, std::auto_ptr<Callback> callback, QObject *parent = NULL);
MediaWorker(MediaSource *source, std::auto_ptr<Callback> callback, QObject *parent = 0);
MediaSource* source() /*const */{ return sampleBuffer.source(); }
// SyncVar& syncVar() /*const */{ return syncVar_; }
SyncVar& waitingForSync() /*const */{ return waitingForSync_; }
// void syncedUpdate(BlitterWidget *blitter);
void start();
void stop();
void pause();
@ -294,11 +273,6 @@ public:
void updateJoysticks();
// void lockVideoBuffer() { pbmut.lock(); }
// void unlockVideoBuffer() { pbmut.unlock(); }
// void setVideoBuffer(const PixelBuffer &pb) { pxbuf = pb; }
// const PixelBuffer& videoBuffer() const { return pxbuf; }
template<class T> void pushCall(const T &t) { pauseVar.pushCall(t, AtomicVar<bool>::ConstLocked(doneVar).get()); }
};

View File

@ -0,0 +1,41 @@
/***************************************************************************
* Copyright (C) 2011 by Sindre Aamås *
* aamas@stud.ntnu.no *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License version 2 as *
* published by the Free Software Foundation. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License version 2 for more details. *
* *
* You should have received a copy of the GNU General Public License *
* version 2 along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "../persistcheckbox.h"
#include <QCheckBox>
#include <QSettings>
PersistCheckBox::PersistCheckBox(QCheckBox *const checkBox, const QString &key, const bool defaultValue)
: checkBox_(checkBox), key_(key), value_(defaultValue)
{
value_ = QSettings().value(key, defaultValue).toBool();
reject();
}
PersistCheckBox::~PersistCheckBox() {
QSettings settings;
settings.setValue(key_, value_);
}
void PersistCheckBox::accept() {
value_ = checkBox_->isChecked();
}
void PersistCheckBox::reject() const {
checkBox_->setChecked(value_);
}

View File

@ -42,7 +42,7 @@ class SampleBuffer {
void reset();
public:
SampleBuffer(MediaSource *source) : source_(source), spf_(0), ft_(1, 0), outsrate(0), resamplerNo_(1) { reset(); }
explicit SampleBuffer(MediaSource *source) : source_(source), spf_(0), ft_(1, 0), outsrate(0), resamplerNo_(1) { reset(); }
long update(const PixelBuffer &pb);
long read(long insamples, qint16 *out);
long samplesBuffered() const { return samplesBuffered_; }

View File

@ -1,5 +1,5 @@
/***************************************************************************
* Copyright (C) 2007 by Sindre Aam<EFBFBD>s *
* Copyright (C) 2007 by Sindre Aamås *
* aamas@stud.ntnu.no *
* *
* This program is free software; you can redistribute it and/or modify *
@ -29,6 +29,7 @@
#include <QGroupBox>
#include <QApplication>
#include <QDesktopWidget>
#include <functional>
static int filterValue(const int value, const int upper, const int lower = 0, const int fallback = 0) {
if (value >= upper || value < lower)
@ -37,385 +38,505 @@ static int filterValue(const int value, const int upper, const int lower = 0, co
return value;
}
VideoDialog::PersistInt::PersistInt(const QString &key, const int upper, const int lower, const int defaultVal)
: key_(key), i_(filterValue(QSettings().value(key, defaultVal).toInt(), upper, lower, defaultVal))
{
}
VideoDialog::PersistInt::~PersistInt() {
QSettings settings;
settings.setValue(key_, i_);
}
VideoDialog::EngineSelector::EngineSelector(const MainWindow *const mw)
: comboBox_(new QComboBox), index_("video/engineIndex", mw->numBlitters())
{
for (std::size_t i = 0; i < mw->numBlitters(); ++i)
comboBox_->addItem(mw->blitterConf(i).nameString());
restore();
}
void VideoDialog::EngineSelector::addToLayout(QBoxLayout *const topLayout) {
QHBoxLayout *const hLayout = new QHBoxLayout;
hLayout->addWidget(new QLabel(tr("Video engine:")));
hLayout->addWidget(comboBox_);
topLayout->addLayout(hLayout);
}
void VideoDialog::EngineSelector::store() {
index_ = comboBox_->currentIndex();
}
void VideoDialog::EngineSelector::restore() {
comboBox_->setCurrentIndex(index_);
}
VideoDialog::ScalingMethodSelector::ScalingMethodSelector()
: unrestrictedScalingButton_(new QRadioButton(QString("None"))),
keepRatioButton_(new QRadioButton(QString("Keep aspect ratio"))),
integerScalingButton_(new QRadioButton(QString("Only scale by integer factors"))),
scaling_("video/scalingType", NUM_SCALING_METHODS, 0, KEEP_RATIO)
{
restore();
}
void VideoDialog::ScalingMethodSelector::addToLayout(QLayout *const containingLayout) {
QGroupBox *const groupBox = new QGroupBox("Scaling restrictions");
groupBox->setLayout(new QVBoxLayout);
groupBox->layout()->addWidget(unrestrictedScalingButton_);
groupBox->layout()->addWidget(keepRatioButton_);
groupBox->layout()->addWidget(integerScalingButton_);
containingLayout->addWidget(groupBox);
}
void VideoDialog::ScalingMethodSelector::store() {
if (integerScalingButton_->isChecked()) {
scaling_ = INTEGER;
} else if (keepRatioButton_->isChecked()) {
scaling_ = KEEP_RATIO;
} else
scaling_ = UNRESTRICTED;
}
void VideoDialog::ScalingMethodSelector::restore() {
switch (scaling_) {
case UNRESTRICTED: unrestrictedScalingButton_->click(); break;
case KEEP_RATIO: keepRatioButton_->click(); break;
case INTEGER: integerScalingButton_->click(); break;
}
}
const QAbstractButton * VideoDialog::ScalingMethodSelector::integerScalingButton() const {
return integerScalingButton_;
}
VideoDialog::SourceSelector::SourceSelector(const QString &sourcesLabel, const std::vector<VideoSourceInfo> &sourceInfos)
: label_(new QLabel(sourcesLabel)), comboBox_(new QComboBox), index_("video/sourceIndexStore", sourceInfos.size())
{
setVideoSources(sourceInfos);
restore();
}
void VideoDialog::SourceSelector::addToLayout(QBoxLayout *const containingLayout) {
QHBoxLayout *const hLayout = new QHBoxLayout;
hLayout->addWidget(label_);
hLayout->addWidget(comboBox_);
containingLayout->addLayout(hLayout);
}
void VideoDialog::SourceSelector::store() {
index_ = comboBox_->currentIndex();
}
void VideoDialog::SourceSelector::restore() {
comboBox_->setCurrentIndex(index_);
}
void VideoDialog::SourceSelector::setVideoSources(const std::vector<VideoSourceInfo> &sourceInfos) {
comboBox_->clear();
for (std::size_t i = 0; i < sourceInfos.size(); ++i)
comboBox_->addItem(sourceInfos[i].label, QSize(sourceInfos[i].width, sourceInfos[i].height));
if (comboBox_->count() < 2) {
comboBox_->hide();
label_->hide();
} else if (comboBox_->parentWidget()) {
comboBox_->show();
label_->show();
}
}
VideoDialog::WinResSelector::WinResSelector(const QSize &aspectRatio, const QSize &sourceSize, const bool integerScaling)
: comboBox_(new QComboBox),
defaultRes_(QApplication::desktop()->screen()->size()),
aspectRatio_(aspectRatio),
index_(0)
{
fillComboBox(sourceSize, integerScaling);
index_ = filterValue(QSettings().value("video/winIndex", comboBox_->count() - 1).toInt(),
comboBox_->count(), 0, comboBox_->count() - 1);
restore();
}
VideoDialog::WinResSelector::~WinResSelector() {
QSettings settings;
settings.setValue("video/winIndex", index_);
}
void VideoDialog::WinResSelector::addToLayout(QBoxLayout *const containingLayout) {
QHBoxLayout *const hLayout = new QHBoxLayout;
hLayout->addWidget(new QLabel(QString(tr("Window size:"))));
hLayout->addWidget(comboBox_);
containingLayout->addLayout(hLayout);
}
void VideoDialog::WinResSelector::store() {
index_ = comboBox_->currentIndex();
}
void VideoDialog::WinResSelector::restore() {
comboBox_->setCurrentIndex(index_);
}
void VideoDialog::WinResSelector::setAspectRatio(const QSize &aspectRatio, const QSize &sourceSize, const bool integerScaling) {
aspectRatio_ = aspectRatio;
setBaseSize(sourceSize, integerScaling);
}
void VideoDialog::WinResSelector::setBaseSize(const QSize &sourceSize, const bool integerScaling) {
const QString oldtext(comboBox_->itemText(comboBox_->currentIndex()));
comboBox_->clear();
fillComboBox(sourceSize, integerScaling);
const int newIndex = comboBox_->findText(oldtext);
if (newIndex >= 0)
comboBox_->setCurrentIndex(newIndex);
}
void VideoDialog::WinResSelector::fillComboBox(const QSize &sourceSize, const bool integerScaling) {
const QSize basesz(integerScaling ? sourceSize : aspectRatio_);
/*if (!integerScaling) {
const unsigned scale = std::max(sourceSize.width() / aspectRatio_.width(), sourceSize.height() / aspectRatio_.height());
basesz = QSize(aspectRatio_.width() * scale, aspectRatio_.height() * scale);
if (basesz.width() < sourceSize.width() || basesz.height() < sourceSize.height())
basesz += aspectRatio_;
}*/
QSize sz(basesz);
while (sz.width() <= defaultRes_.width() && sz.height() <= defaultRes_.height()) {
if (sz.width() >= sourceSize.width() && sz.height() >= sourceSize.height())
comboBox_->addItem(QString::number(sz.width()) + "x" + QString::number(sz.height()), sz);
sz += basesz;
}
comboBox_->addItem(QString(tr("Variable")), QVariant(QSize(-1, -1)));
}
VideoDialog::FullResSelector::FullResSelector(
const QString &key, const int defaultIndex,
const QSize &sourceSize, const std::vector<ResInfo> &resVector)
: comboBox_(new QComboBox), key_(key), index_(defaultIndex)
{
fillComboBox(sourceSize, resVector);
index_ = filterValue(comboBox_->findText(QSettings().value(key).toString()),
comboBox_->count(), 0, index_);
restore();
}
VideoDialog::FullResSelector::~FullResSelector() {
QSettings settings;
settings.setValue(key_, comboBox_->itemText(index_));
}
QWidget* VideoDialog::FullResSelector::widget() {
return comboBox_;
}
void VideoDialog::FullResSelector::store() {
index_ = comboBox_->currentIndex();
}
void VideoDialog::FullResSelector::restore() {
comboBox_->setCurrentIndex(index_);
}
void VideoDialog::FullResSelector::setSourceSize(const QSize &sourceSize, const std::vector<ResInfo> &resVector) {
const QString oldtext(comboBox_->itemText(comboBox_->currentIndex()));
comboBox_->clear();
fillComboBox(sourceSize, resVector);
const int newIndex = comboBox_->findText(oldtext);
if (newIndex >= 0)
comboBox_->setCurrentIndex(newIndex);
}
void VideoDialog::FullResSelector::fillComboBox(const QSize &sourceSize, const std::vector<ResInfo> &resVector) {
long maxArea = 0;
std::size_t maxAreaI = 0;
for (std::size_t i = 0; i < resVector.size(); ++i) {
const int hres = resVector[i].w;
const int vres = resVector[i].h;
if (hres >= sourceSize.width() && vres >= sourceSize.height()) {
comboBox_->addItem(QString::number(hres) + QString("x") + QString::number(vres), i);
} else {
const long area = static_cast<long>(std::min(hres, sourceSize.width())) * std::min(vres, sourceSize.height());
if (area > maxArea) {
maxArea = area;
maxAreaI = i;
}
}
}
//add resolution giving maximal area if all resolutions are too small.
if (comboBox_->count() < 1 && maxArea)
comboBox_->addItem(QString::number(resVector[maxAreaI].w) + "x" + QString::number(resVector[maxAreaI].h), maxAreaI);
}
VideoDialog::FullHzSelector::FullHzSelector(const QString &key, const std::vector<short> &rates, const int defaultIndex)
: comboBox_(new QComboBox), key_(key), index_(0)
{
setRates(rates);
index_ = filterValue(
comboBox_->findText(QSettings().value(key).toString()),
comboBox_->count(),
0,
defaultIndex);
restore();
}
VideoDialog::FullHzSelector::~FullHzSelector() {
QSettings settings;
settings.setValue(key_, comboBox_->itemText(index_));
}
QWidget* VideoDialog::FullHzSelector::widget() {
return comboBox_;
}
void VideoDialog::FullHzSelector::store() {
index_ = comboBox_->currentIndex();
}
void VideoDialog::FullHzSelector::restore() {
comboBox_->setCurrentIndex(index_);
}
void VideoDialog::FullHzSelector::setRates(const std::vector<short> &rates) {
comboBox_->clear();
for (std::size_t i = 0; i < rates.size(); ++i)
comboBox_->addItem(QString::number(rates[i] / 10.0) + QString(" Hz"), i);
}
const std::vector<VideoDialog::FullResSelector*> VideoDialog::makeFullResSelectors(
const QSize &sourceSize, const MainWindow *const mw)
{
std::vector<FullResSelector*> v(mw->screens(), 0);
for (std::size_t i = 0; i < v.size(); ++i) {
v[i] = new FullResSelector("video/fullRes" + QString::number(i),
mw->currentResIndex(i), sourceSize, mw->modeVector(i));
}
return v;
}
const std::vector<VideoDialog::FullHzSelector*> VideoDialog::makeFullHzSelectors(
const auto_vector<FullResSelector> &fullResSelectors, const MainWindow *const mw)
{
std::vector<FullHzSelector*> v(fullResSelectors.size(), 0);
for (std::size_t i = 0; i < v.size(); ++i) {
const int index = fullResSelectors[i]->comboBox()->currentIndex();
v[i] = new FullHzSelector("video/hz" + QString::number(i),
index >= 0 ? mw->modeVector(i)[index].rates : std::vector<short>(),
index == static_cast<int>(mw->currentResIndex(i)) ? mw->currentRateIndex(i) : 0);
}
return v;
}
VideoDialog::VideoDialog(const MainWindow *const mw,
const std::vector<VideoSourceInfo> &sourceInfos,
const QString &sourcesLabel,
const QSize &aspectRatio,
QWidget *parent) :
QDialog(parent),
mw(mw),
topLayout(new QVBoxLayout),
engineWidget(NULL),
engineSelector(new QComboBox),
winResSelector(new QComboBox),
unrestrictedScalingButton(new QRadioButton(QString("None"))),
keepRatioButton(new QRadioButton(QString("Keep aspect ratio"))),
integerScalingButton(new QRadioButton(QString("Only scale by integer factors"))),
sourceSelector(new QComboBox),
sourceSelectorLabel(new QLabel(sourcesLabel)),
scaling(KEEP_RATIO),
aspRatio(aspectRatio),
defaultRes(QApplication::desktop()->screen()->size()),
engineIndex(0),
winIndex(0),
sourceIndexStore(0)
QWidget *parent)
: QDialog(parent),
mw(mw),
topLayout(new QVBoxLayout),
engineWidget(0),
engineSelector(mw),
sourceSelector(sourcesLabel, sourceInfos),
winResSelector(aspectRatio,
sourceSelector.comboBox()->itemData(sourceSelector.comboBox()->currentIndex()).toSize(),
scalingMethodSelector.integerScalingButton()->isChecked()),
fullResSelectors(makeFullResSelectors(sourceSelector.comboBox()->itemData(sourceSelector.comboBox()->currentIndex()).toSize(), mw)),
fullHzSelectors(makeFullHzSelectors(fullResSelectors, mw))
{
fullIndex.resize(mw->screens());
hzIndex.resize(fullIndex.size());
fullResSelector.resize(fullIndex.size());
hzSelector.resize(fullIndex.size());
QVBoxLayout *mainLayout = new QVBoxLayout;
setLayout(mainLayout);
QHBoxLayout *hLayout = new QHBoxLayout;
hLayout->addWidget(new QLabel(tr("Video engine:")));
hLayout->addWidget(engineSelector);
topLayout->addLayout(hLayout);
engineSelector.addToLayout(topLayout);
if ((engineWidget = mw->blitterConf(engineSelector.comboBox()->currentIndex()).settingsWidget()))
topLayout->addWidget(engineWidget);
hLayout = new QHBoxLayout;
hLayout->addWidget(new QLabel(QString(tr("Windowed resolution:"))));
hLayout->addWidget(winResSelector);
topLayout->addLayout(hLayout);
winResSelector.addToLayout(topLayout);
for (unsigned i = 0; i < hzSelector.size(); ++i) {
hLayout = new QHBoxLayout;
hLayout->addWidget(new QLabel("Full screen mode (screen " + QString::number(i) + "):"));
QHBoxLayout *hhLayout = new QHBoxLayout;
hhLayout->addWidget((fullResSelector[i] = new QComboBox));
hhLayout->addWidget((hzSelector[i] = new QComboBox));
for (std::size_t i = 0; i < fullResSelectors.size(); ++i) {
QHBoxLayout *const hLayout = new QHBoxLayout;
QLabel *const label = new QLabel("Full screen mode (" + mw->screenName(i) + "):");
hLayout->addWidget(label);
QHBoxLayout *const hhLayout = new QHBoxLayout;
hhLayout->addWidget(fullResSelectors[i]->widget());
hhLayout->addWidget(fullHzSelectors[i]->widget());
hLayout->addLayout(hhLayout);
topLayout->addLayout(hLayout);
if (mw->modeVector(i).empty()) {
label->hide();
fullResSelectors[i]->widget()->hide();
fullHzSelectors[i]->widget()->hide();
}
}
{
QGroupBox *f = new QGroupBox("Scaling restrictions");
f->setLayout(new QVBoxLayout);
f->layout()->addWidget(unrestrictedScalingButton);
f->layout()->addWidget(keepRatioButton);
f->layout()->addWidget(integerScalingButton);
topLayout->addWidget(f);
}
hLayout = new QHBoxLayout;
hLayout->addWidget(sourceSelectorLabel);
hLayout->addWidget(sourceSelector);
topLayout->addLayout(hLayout);
scalingMethodSelector.addToLayout(topLayout);
sourceSelector.addToLayout(topLayout);
mainLayout->addLayout(topLayout);
mainLayout->setAlignment(topLayout, Qt::AlignTop);
hLayout = new QHBoxLayout;
QPushButton *okButton = new QPushButton(tr("OK"));
QHBoxLayout *const hLayout = new QHBoxLayout;
QPushButton *const okButton = new QPushButton(tr("OK"));
hLayout->addWidget(okButton);
QPushButton *cancelButton = new QPushButton(tr("Cancel"));
QPushButton *const cancelButton = new QPushButton(tr("Cancel"));
hLayout->addWidget(cancelButton);
mainLayout->addLayout(hLayout);
mainLayout->setAlignment(hLayout, Qt::AlignBottom | Qt::AlignRight);
okButton->setDefault(true);
connect(engineSelector, SIGNAL(currentIndexChanged(int)), this, SLOT(engineChange(int)));
connect(engineSelector.comboBox(), SIGNAL(currentIndexChanged(int)), this, SLOT(engineChange(int)));
for (unsigned i = 0; i < fullResSelector.size(); ++i) {
connect(fullResSelector[i], SIGNAL(currentIndexChanged(int)), this, SLOT(fullresChange(int)));
for (std::size_t i = 0; i < fullResSelectors.size(); ++i) {
connect(fullResSelectors[i]->comboBox(), SIGNAL(currentIndexChanged(int)), this, SLOT(fullresChange(int)));
}
connect(integerScalingButton, SIGNAL(toggled(bool)), this, SLOT(integerScalingChange(bool)));
connect(sourceSelector, SIGNAL(currentIndexChanged(int)), this, SLOT(sourceChange(int)));
connect(scalingMethodSelector.integerScalingButton(), SIGNAL(toggled(bool)), this, SLOT(integerScalingChange(bool)));
connect(sourceSelector.comboBox(), SIGNAL(currentIndexChanged(int)), this, SLOT(sourceChange(int)));
connect(okButton, SIGNAL(clicked()), this, SLOT(accept()));
connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject()));
fillSourceSelector(sourceInfos);
for (std::size_t i = 0; i < mw->numBlitters(); ++i) {
engineSelector->addItem(mw->blitterConf(i).nameString());
}
fillWinResSelector();
fillFullResSelector();
keepRatioButton->click();
QSettings settings;
settings.beginGroup("video");
engineIndex = filterValue(settings.value("engineIndex", 0).toInt(), engineSelector->count());
sourceIndexStore = filterValue(settings.value("sourceIndexStore", 0).toInt(), sourceSelector->count());
switch (settings.value("scalingType", KEEP_RATIO).toInt()) {
case UNRESTRICTED: scaling = UNRESTRICTED; break;
case INTEGER: scaling = INTEGER; break;
default: scaling = KEEP_RATIO; break;
}
restore();
for (unsigned i = 0; i < fullIndex.size(); ++i) {
fullIndex[i] = filterValue(fullResSelector[i]->findText(settings.value("fullRes" + QString::number(i)).toString()),
fullResSelector[i]->count(),
0,
mw->currentResIndex(i));
}
winIndex = filterValue(settings.value("winIndex", winResSelector->count() - 1).toInt(), winResSelector->count(), 0, winResSelector->count() - 1);
restore();
for (unsigned i = 0; i < hzIndex.size(); ++i) {
hzIndex[i] = filterValue(hzSelector[i]->findText(settings.value("hz" + QString::number(i)).toString()),
hzSelector[i]->count(),
0,
mw->currentRateIndex(i));
}
restore();
store();
settings.endGroup();
setWindowTitle(tr("Video Settings"));
}
VideoDialog::~VideoDialog() {
// delete fullResSelectorBackup;
void VideoDialog::fillFullResSelectors() {
const QSize &sourceSize = sourceSelector.comboBox()->itemData(sourceSelector.comboBox()->currentIndex()).toSize();
QSettings settings;
settings.beginGroup("video");
for (unsigned i = 0; i < fullIndex.size(); ++i) {
settings.setValue("fullRes" + QString::number(i), fullResSelector[i]->itemText(fullIndex[i]));
}
settings.setValue("winIndex", winIndex);
for (unsigned i = 0; i < hzIndex.size(); ++i) {
settings.setValue("hz" + QString::number(i), hzSelector[i]->itemText(hzIndex[i]));
}
settings.setValue("scalingType", (int)scaling);
settings.setValue("sourceIndexStore", sourceIndexStore);
settings.setValue("engineIndex", engineIndex);
settings.endGroup();
}
void VideoDialog::fillWinResSelector() {
const QString oldtext(winResSelector->itemText(winResSelector->currentIndex()));
winResSelector->clear();
const QSize &sourceSize = sourceSelector->itemData(sourceSelector->currentIndex()).toSize();
QSize basesz(integerScalingButton->isChecked() ? sourceSize : aspRatio);
/*if (!integerScalingButton->isChecked()) {
const unsigned scale = std::max(sourceSize.width() / aspRatio.width(), sourceSize.height() / aspRatio.height());
for (std::size_t i = 0; i < fullResSelectors.size(); ++i) {
const int oldResIndex = fullResSelectors[i]->comboBox()->currentIndex();
basesz = QSize(aspRatio.width() * scale, aspRatio.height() * scale);
disconnect(fullResSelectors[i]->comboBox(), SIGNAL(currentIndexChanged(int)), this, SLOT(fullresChange(int)));
fullResSelectors[i]->setSourceSize(sourceSize, mw->modeVector(i));
connect(fullResSelectors[i]->comboBox(), SIGNAL(currentIndexChanged(int)), this, SLOT(fullresChange(int)));
if (basesz.width() < sourceSize.width() || basesz.height() < sourceSize.height())
basesz += aspRatio;
}*/
QSize sz(basesz);
while (sz.width() <= defaultRes.width() && sz.height() <= defaultRes.height()) {
if (sz.width() >= sourceSize.width() && sz.height() >= sourceSize.height())
winResSelector->addItem(QString::number(sz.width()) + "x" + QString::number(sz.height()), sz);
const int newResIndex = fullResSelectors[i]->comboBox()->currentIndex();
sz += basesz;
}
winResSelector->addItem(QString(tr("Variable")), QVariant(QSize(-1, -1)));
const int newIndex = winResSelector->findText(oldtext);
if (newIndex >= 0)
winResSelector->setCurrentIndex(newIndex);
}
void VideoDialog::fillFullResSelector() {
for (unsigned j = 0; j < fullResSelector.size(); ++j) {
const QString oldtext(fullResSelector[j]->itemText(fullResSelector[j]->currentIndex()));
const int oldHzIndex = hzSelector[j]->currentIndex();
fullResSelector[j]->clear();
const QSize &sourceSize = sourceSelector->itemData(sourceSelector->currentIndex()).toSize();
unsigned maxArea = 0;
unsigned maxAreaI = 0;
const std::vector<ResInfo> &resVector = mw->modeVector(j);
for (unsigned i = 0; i < resVector.size(); ++i) {
const int hres = resVector[i].w;
const int vres = resVector[i].h;
if (hres >= sourceSize.width() && vres >= sourceSize.height()) {
fullResSelector[j]->addItem(QString::number(hres) + QString("x") + QString::number(vres), i);
} else {
const unsigned area = std::min(hres, sourceSize.width()) * std::min(vres, sourceSize.height());
if (area > maxArea) {
maxArea = area;
maxAreaI = i;
}
}
}
//add resolution giving maximal area if all resolutions are too small.
if (fullResSelector[j]->count() < 1 && maxArea)
fullResSelector[j]->addItem(QString::number(resVector[maxAreaI].w) + "x" + QString::number(resVector[maxAreaI].h), maxAreaI);
const int newIndex = fullResSelector[j]->findText(oldtext);
if (newIndex >= 0) {
fullResSelector[j]->setCurrentIndex(newIndex);
hzSelector[j]->setCurrentIndex(oldHzIndex);
}
if (newResIndex != oldResIndex)
fullHzSelectors[i]->setRates(newResIndex >= 0 ? mw->modeVector(i)[newResIndex].rates : std::vector<short>());
}
}
void VideoDialog::store() {
// for (std::size_t i = 0; i < mw->numBlitters(); ++i)
// mw->blitterConf(i).acceptSettings();
engineIndex = engineSelector->currentIndex();
if (unrestrictedScalingButton->isChecked())
scaling = UNRESTRICTED;
else if (keepRatioButton->isChecked())
scaling = KEEP_RATIO;
else
scaling = INTEGER;
sourceIndexStore = sourceSelector->currentIndex();
winIndex = winResSelector->currentIndex();
for (unsigned i = 0; i < fullResSelector.size(); ++i) {
fullIndex[i] = fullResSelector[i]->currentIndex();
hzIndex[i] = hzSelector[i]->currentIndex();
}
engineSelector.store();
scalingMethodSelector.store();
sourceSelector.store();
winResSelector.store();
std::for_each(fullResSelectors.begin(), fullResSelectors.end(), std::mem_fun(&FullResSelector::store));
std::for_each(fullHzSelectors.begin(), fullHzSelectors.end(), std::mem_fun(&FullHzSelector::store));
}
void VideoDialog::restore() {
for (std::size_t i = 0; i < mw->numBlitters(); ++i)
mw->blitterConf(i).rejectSettings();
engineSelector->setCurrentIndex(engineIndex);
switch (scaling) {
case UNRESTRICTED: unrestrictedScalingButton->click(); break;
case KEEP_RATIO: keepRatioButton->click(); break;
case INTEGER: integerScalingButton->click(); break;
}
sourceSelector->setCurrentIndex(sourceIndexStore);
winResSelector->setCurrentIndex(winIndex);
for (unsigned i = 0; i < fullResSelector.size(); ++i) {
fullResSelector[i]->setCurrentIndex(fullIndex[i]);
hzSelector[i]->setCurrentIndex(hzIndex[i]);
}
engineSelector.restore();
scalingMethodSelector.restore();
sourceSelector.restore();
winResSelector.restore();
std::for_each(fullResSelectors.begin(), fullResSelectors.end(), std::mem_fun(&FullResSelector::restore));
std::for_each(fullHzSelectors.begin(), fullHzSelectors.end(), std::mem_fun(&FullHzSelector::restore));
}
void VideoDialog::engineChange(int index) {
if (engineWidget) {
topLayout->removeWidget(engineWidget);
engineWidget->setParent(NULL);
engineWidget->setParent(0);
}
engineWidget = mw->blitterConf(index).settingsWidget();
if (engineWidget)
if ((engineWidget = mw->blitterConf(index).settingsWidget()))
topLayout->insertWidget(1, engineWidget);
/*if (mw->blitterConf(index)->integerOnlyScaler) {
integerScalingButton->click();
keepRatioButton->setEnabled(false);
integerScalingButton->setEnabled(false);
unrestrictedScalingButton->setEnabled(false);
} else */{
keepRatioButton->setEnabled(true);
integerScalingButton->setEnabled(true);
unrestrictedScalingButton->setEnabled(true);
}
}
void VideoDialog::fullresChange(int index) {
for (unsigned i = 0; i < fullResSelector.size(); ++i) {
if (sender() == fullResSelector[i]) {
hzSelector[i]->clear();
if (index >= 0) {
const std::vector<short> &v = mw->modeVector(i)[index].rates;
for (unsigned int j = 0; j < v.size(); ++j)
hzSelector[i]->addItem(QString::number(v[j]) + QString(" Hz"), j);
}
void VideoDialog::fullresChange(const int index) {
for (std::size_t i = 0; i < fullResSelectors.size(); ++i) {
if (sender() == fullResSelectors[i]->comboBox()) {
fullHzSelectors[i]->setRates(index >= 0 ? mw->modeVector(i)[index].rates : std::vector<short>());
break;
}
}
}
void VideoDialog::sourceChange(int /*index*/) {
fillWinResSelector();
fillFullResSelector();
winResSelector.setBaseSize(
sourceSelector.comboBox()->itemData(sourceSelector.comboBox()->currentIndex()).toSize(),
scalingMethodSelector.integerScalingButton()->isChecked());
fillFullResSelectors();
}
void VideoDialog::integerScalingChange(bool /*checked*/) {
sourceChange(sourceSelector->currentIndex());
void VideoDialog::integerScalingChange(const bool checked) {
winResSelector.setBaseSize(
sourceSelector.comboBox()->itemData(sourceSelector.comboBox()->currentIndex()).toSize(), checked);
}
int VideoDialog::blitterNo() const {
return engineIndex;
return engineSelector.index();
}
const QSize VideoDialog::windowSize() const {
return winResSelector->itemData(winIndex).toSize();
return winResSelector.comboBox()->itemData(winResSelector.index()).toSize();
}
unsigned VideoDialog::fullResIndex(unsigned screen) const {
//return fullResSelector->currentIndex();
// return fullResSelectorBackup->findText(fullResSelector->itemText(fullResSelector->currentIndex()));
return fullResSelector[screen]->itemData(fullIndex[screen]).toUInt();
return fullResSelectors[screen]->comboBox()->itemData(fullResSelectors[screen]->index()).toUInt();
}
unsigned VideoDialog::fullRateIndex(unsigned screen) const {
return hzSelector[screen]->itemData(hzIndex[screen]).toUInt();
return fullHzSelectors[screen]->comboBox()->itemData(fullHzSelectors[screen]->index()).toUInt();
}
const QSize VideoDialog::sourceSize() const {
return sourceSelector->itemData(sourceIndex()).toSize();
return sourceSelector.comboBox()->itemData(sourceIndex()).toSize();
}
void VideoDialog::setAspectRatio(const QSize &aspectRatio) {
restore();
aspRatio = aspectRatio;
fillWinResSelector();
winResSelector.setAspectRatio(aspectRatio,
sourceSelector.comboBox()->itemData(sourceSelector.comboBox()->currentIndex()).toSize(),
scalingMethodSelector.integerScalingButton()->isChecked());
store();
emit accepted();
}
void VideoDialog::fillSourceSelector(const std::vector<VideoSourceInfo> &sourceInfos) {
for (std::size_t i = 0; i < sourceInfos.size(); ++i)
sourceSelector->addItem(sourceInfos[i].label, QSize(sourceInfos[i].width, sourceInfos[i].height));
if (sourceSelector->count() < 2) {
sourceSelector->hide();
sourceSelectorLabel->hide();
} else {
sourceSelector->show();
sourceSelectorLabel->show();
}
}
void VideoDialog::setVideoSources(const std::vector<VideoSourceInfo> &sourceInfos) {
restore();
disconnect(sourceSelector, SIGNAL(currentIndexChanged(int)), this, SLOT(sourceChange(int)));
sourceSelector->clear();
fillSourceSelector(sourceInfos);
connect(sourceSelector, SIGNAL(currentIndexChanged(int)), this, SLOT(sourceChange(int)));
sourceChange(sourceSelector->currentIndex());
disconnect(sourceSelector.comboBox(), SIGNAL(currentIndexChanged(int)), this, SLOT(sourceChange(int)));
sourceSelector.setVideoSources(sourceInfos);
connect(sourceSelector.comboBox(), SIGNAL(currentIndexChanged(int)), this, SLOT(sourceChange(int)));
sourceChange(sourceSelector.comboBox()->currentIndex());
store();
emit accepted();
}
@ -434,9 +555,10 @@ void applySettings(MainWindow *const mw, const VideoDialog *const vd) {
{
const BlitterConf curBlitter = mw->currentBlitterConf();
for (std::size_t i = 0; i < mw->numBlitters(); ++i)
for (std::size_t i = 0; i < mw->numBlitters(); ++i) {
if (mw->blitterConf(i) != curBlitter)
mw->blitterConf(i).acceptSettings();
}
const QSize &srcSz = vd->sourceSize();
mw->setVideoFormatAndBlitter(srcSz.width(), srcSz.height(), vd->blitterNo());
@ -447,6 +569,6 @@ void applySettings(MainWindow *const mw, const VideoDialog *const vd) {
mw->setScalingMethod(vd->scalingMethod());
mw->setWindowSize(vd->windowSize());
for (unsigned i = 0; i < mw->screens(); ++i)
for (std::size_t i = 0; i < mw->screens(); ++i)
mw->setFullScreenMode(i, vd->fullResIndex(i), vd->fullRateIndex(i));
}

View File

@ -1,5 +1,5 @@
/***************************************************************************
* Copyright (C) 2007 by Sindre Aam<EFBFBD>s *
* Copyright (C) 2007 by Sindre Aamås *
* aamas@stud.ntnu.no *
* *
* This program is free software; you can redistribute it and/or modify *
@ -27,10 +27,11 @@
class QVBoxLayout;
class QHBoxLayout;
class QComboBox;
class QAbstractButton;
class QRadioButton;
class QLabel;
class QBoxLayout;
// #include "resinfo.h"
#include "mainwindow.h"
/** A utility class that can optionally be used to provide a GUI for
@ -49,31 +50,128 @@ public:
};
private:
class PersistInt {
const QString key_;
int i_;
public:
PersistInt(const QString &key, int upper, int lower = 0, int defaultVal = 0);
~PersistInt();
PersistInt & operator=(int i) { i_ = i; return *this; }
operator int() const { return i_; }
};
class EngineSelector {
QComboBox *const comboBox_;
PersistInt index_;
public:
explicit EngineSelector(const MainWindow *mw);
void addToLayout(QBoxLayout *topLayout);
const QComboBox * comboBox() const { return comboBox_; }
void store();
void restore();
int index() const { return index_; }
};
class ScalingMethodSelector {
QRadioButton *const unrestrictedScalingButton_;
QRadioButton *const keepRatioButton_;
QRadioButton *const integerScalingButton_;
PersistInt scaling_;
public:
ScalingMethodSelector();
void addToLayout(QLayout *layout);
const QAbstractButton * integerScalingButton() const;
void store();
void restore();
ScalingMethod scalingMethod() const { return static_cast<ScalingMethod>(static_cast<int>(scaling_)); }
};
class SourceSelector {
QLabel *const label_;
QComboBox *const comboBox_;
PersistInt index_;
public:
SourceSelector(const QString &sourcesLabel, const std::vector<VideoSourceInfo> &sourceInfos);
void addToLayout(QBoxLayout *layout);
const QComboBox * comboBox() const { return comboBox_; }
void setVideoSources(const std::vector<VideoSourceInfo> &sourceInfos);
void store();
void restore();
int index() const { return index_; }
};
class WinResSelector {
QComboBox *const comboBox_;
const QSize defaultRes_;
QSize aspectRatio_;
int index_;
void fillComboBox(const QSize &sourceSize, bool integerScaling);
public:
WinResSelector(const QSize &aspectRatio, const QSize &sourceSize, bool integerScaling);
~WinResSelector();
void addToLayout(QBoxLayout *layout);
const QComboBox * comboBox() const { return comboBox_; }
void store();
void restore();
void setAspectRatio(const QSize &aspectRatio, const QSize &sourceSize, bool integerScaling);
void setBaseSize(const QSize &sourceSize, bool integerScaling);
const QSize & aspectRatio() const { return aspectRatio_; }
int index() const { return index_; }
};
class FullResSelector {
QComboBox *const comboBox_;
const QString key_;
int index_;
void fillComboBox(const QSize &sourceSize, const std::vector<ResInfo> &resVector);
public:
FullResSelector(const QString &key, int defaultIndex,
const QSize &sourceSize, const std::vector<ResInfo> &resVector);
~FullResSelector();
QWidget * widget();
const QComboBox * comboBox() const { return comboBox_; }
void store();
void restore();
void setSourceSize(const QSize &sourceSize, const std::vector<ResInfo> &resVector);
int index() const { return index_; }
};
class FullHzSelector {
QComboBox *const comboBox_;
const QString key_;
int index_;
public:
FullHzSelector(const QString &key, const std::vector<short> &rates, int defaultIndex);
~FullHzSelector();
QWidget * widget();
const QComboBox * comboBox() const { return comboBox_; }
void store();
void restore();
void setRates(const std::vector<short> &rates);
int index() const { return index_; }
};
const MainWindow *const mw;
QVBoxLayout *const topLayout;
QWidget *engineWidget;
QComboBox *const engineSelector;
QComboBox *const winResSelector;
// const std::auto_ptr<QComboBox> winResSelectorBackup;
std::vector<QComboBox*> fullResSelector;
std::vector<QComboBox*> hzSelector;
QRadioButton *const unrestrictedScalingButton;
QRadioButton *const keepRatioButton;
QRadioButton *const integerScalingButton;
QComboBox *const sourceSelector;
QLabel *const sourceSelectorLabel;
ScalingMethod scaling;
QSize aspRatio;
const QSize defaultRes;
std::vector<int> fullIndex;
std::vector<int> hzIndex;
int engineIndex;
int winIndex;
int sourceIndexStore;
EngineSelector engineSelector;
ScalingMethodSelector scalingMethodSelector;
SourceSelector sourceSelector;
WinResSelector winResSelector;
const auto_vector<FullResSelector> fullResSelectors;
const auto_vector<FullHzSelector> fullHzSelectors;
static const std::vector<FullResSelector*> makeFullResSelectors(const QSize &sourceSize, const MainWindow *mw);
static const std::vector<FullHzSelector*> makeFullHzSelectors(
const auto_vector<FullResSelector> &fullResSelectors, const MainWindow *mw);
void fillWinResSelector();
void fillFullResSelector();
void fillSourceSelector(const std::vector<VideoSourceInfo> &sourceInfos);
void fillFullResSelectors();
void store();
void restore();
@ -89,17 +187,16 @@ public:
const QString &sourcesLabel,
const QSize &aspectRatio,
QWidget *parent = 0);
~VideoDialog();
int blitterNo() const;
const QSize windowSize() const;
unsigned fullResIndex(unsigned screen) const;
unsigned fullRateIndex(unsigned screen) const;
unsigned sourceIndex() const { return sourceIndexStore; }
unsigned sourceIndex() const { return sourceSelector.index(); }
const QSize sourceSize() const;
void setVideoSources(const std::vector<VideoSourceInfo> &sourceInfos);
void setSourceSize(const QSize &sourceSize);
ScalingMethod scalingMethod() const { return scaling; }
const QSize& aspectRatio() const { return aspRatio; }
ScalingMethod scalingMethod() const { return scalingMethodSelector.scalingMethod(); }
const QSize& aspectRatio() const { return winResSelector.aspectRatio(); }
void setAspectRatio(const QSize &aspectRatio);
public slots:

View File

@ -1,5 +1,5 @@
/***************************************************************************
* Copyright (C) 2007 by Sindre Aam<EFBFBD>s *
* Copyright (C) 2007 by Sindre Aamås *
* aamas@stud.ntnu.no *
* *
* This program is free software; you can redistribute it and/or modify *
@ -38,7 +38,7 @@ struct TmpPauser {
MainWindow *const mw;
const unsigned inc;
TmpPauser(MainWindow *const mw, const unsigned inc = 4) : mw(mw), inc(inc) {
explicit TmpPauser(MainWindow *const mw, const unsigned inc = 4) : mw(mw), inc(inc) {
mw->incPause(inc);
}
@ -48,7 +48,7 @@ struct TmpPauser {
};
}
GambatteMenuHandler::FrameTime::FrameTime(unsigned baseNum, unsigned baseDenom) : index(STEPS) {
FrameRateAdjuster::FrameTime::FrameTime(unsigned baseNum, unsigned baseDenom) : index(STEPS) {
frameTimes[index] = Rational(baseNum, baseDenom);
for (unsigned i = index; i < STEPS * 2; ++i) {
@ -60,15 +60,79 @@ GambatteMenuHandler::FrameTime::FrameTime(unsigned baseNum, unsigned baseDenom)
}
}
GambatteMenuHandler::GambatteMenuHandler(MainWindow *const mw, GambatteSource *const source,
const int argc, const char *const argv[]) :
mw(mw),
source(source),
soundDialog(new SoundDialog(mw, mw)),
videoDialog(new VideoDialog(mw, source->generateVideoSourceInfos(), QString("Video filter:"), QSize(160, 144), mw)),
miscDialog(new MiscDialog(mw)),
frameTime(4389, 262144),
pauseInc(4)
FrameRateAdjuster::FrameRateAdjuster(const unsigned baseNum, const unsigned baseDenom, MainWindow *const mw, QObject *const parent)
: QObject(parent),
frameTime_(baseNum, baseDenom),
decFrameRateAction_(new QAction(tr("&Decrease Frame Rate"), mw)),
incFrameRateAction_(new QAction(tr("&Increase Frame Rate"), mw)),
resetFrameRateAction_(new QAction(tr("&Reset Frame Rate"), mw)),
mw_(mw),
enabled_(true)
{
decFrameRateAction_->setShortcut(QString("Ctrl+D"));
incFrameRateAction_->setShortcut(QString("Ctrl+I"));
resetFrameRateAction_->setShortcut(QString("Ctrl+U"));
connect(decFrameRateAction_, SIGNAL(triggered()), this, SLOT(decFrameRate()));
connect(incFrameRateAction_, SIGNAL(triggered()), this, SLOT(incFrameRate()));
connect(resetFrameRateAction_, SIGNAL(triggered()), this, SLOT(resetFrameRate()));
changed();
}
const QList<QAction*> FrameRateAdjuster::actions() {
QList<QAction*> l;
l.append(decFrameRateAction_);
l.append(incFrameRateAction_);
l.append(resetFrameRateAction_);
return l;
}
void FrameRateAdjuster::setDisabled(const bool disabled) {
enabled_ = !disabled;
changed();
}
void FrameRateAdjuster::decFrameRate() {
if (enabled_) {
frameTime_.inc();
changed();
}
}
void FrameRateAdjuster::incFrameRate() {
if (enabled_) {
frameTime_.dec();
changed();
}
}
void FrameRateAdjuster::resetFrameRate() {
if (enabled_) {
frameTime_.reset();
changed();
}
}
void FrameRateAdjuster::changed() {
incFrameRateAction_->setEnabled(enabled_ && frameTime_.decPossible());
decFrameRateAction_->setEnabled(enabled_ && frameTime_.incPossible());
resetFrameRateAction_->setEnabled(enabled_ && frameTime_.resetPossible());
const FrameTime::Rational &ft = enabled_ ? frameTime_.get() : frameTime_.base();
mw_->setFrameTime(ft.num, ft.denom);
}
GambatteMenuHandler::GambatteMenuHandler(MainWindow *const mw,
GambatteSource *const source, const int argc, const char *const argv[])
: mw(mw),
source(source),
soundDialog(new SoundDialog(mw, mw)),
videoDialog(new VideoDialog(mw, source->generateVideoSourceInfos(), QString("Video filter:"), QSize(160, 144), mw)),
miscDialog(new MiscDialog(mw)),
stateSlotGroup(new QActionGroup(mw)),
frameRateAdjuster(4389, 262144, mw),
pauseInc(4)
{
mw->setWindowTitle("Gambatte");
source->inputDialog()->setParent(mw, source->inputDialog()->windowFlags());
@ -79,7 +143,7 @@ pauseInc(4)
savepath.truncate(iniSettings.fileName().lastIndexOf("/") + 1);
{
QString palpath = savepath + "palettes";
const QString &palpath = savepath + "palettes";
QDir::root().mkpath(palpath);
globalPaletteDialog = new PaletteDialog(palpath, 0, mw);
romPaletteDialog = new PaletteDialog(palpath, globalPaletteDialog, mw);
@ -92,6 +156,9 @@ pauseInc(4)
source->setSavedir(savepath.toLocal8Bit().constData());
}
QActionGroup *const romLoadedActions = new QActionGroup(mw);
romLoadedActions->setExclusive(false);
{
for (int i = 0; i < MaxRecentFiles; ++i) {
recentFileActs[i] = new QAction(mw);
@ -102,42 +169,39 @@ pauseInc(4)
QMenu *fileMenu = mw->menuBar()->addMenu(tr("&File"));
fileMenu->addAction(tr("&Open..."), this, SLOT(open()), tr("Ctrl+O"));
{
recentMenu = fileMenu->addMenu(tr("Open Re&cent"));
recentMenu = fileMenu->addMenu(tr("Open Re&cent"));
for (int i = 0; i < MaxRecentFiles; ++i)
recentMenu->addAction(recentFileActs[i]);
}
for (int i = 0; i < MaxRecentFiles; ++i)
recentMenu->addAction(recentFileActs[i]);
fileMenu->addSeparator();
romLoadedActions.append(fileMenu->addAction(tr("&Reset"), recentFileActs[0], SLOT(trigger()), tr("Ctrl+R")));
romLoadedActions->addAction(fileMenu->addAction(tr("&Reset"), recentFileActs[0], SLOT(trigger()), tr("Ctrl+R")));
fileMenu->addSeparator();
romLoadedActions.append(fileMenu->addAction(tr("Save State &As..."), this, SLOT(saveStateAs())));
romLoadedActions.append(fileMenu->addAction(tr("Load State &From..."), this, SLOT(loadStateFrom())));
romLoadedActions->addAction(fileMenu->addAction(tr("Save State &As..."), this, SLOT(saveStateAs())));
romLoadedActions->addAction(fileMenu->addAction(tr("Load State &From..."), this, SLOT(loadStateFrom())));
fileMenu->addSeparator();
romLoadedActions.append(fileMenu->addAction(tr("&Save State"), this, SLOT(saveState()), QString("Ctrl+S")));
romLoadedActions.append(fileMenu->addAction(tr("&Load State"), this, SLOT(loadState()), QString("Ctrl+L")));
romLoadedActions->addAction(fileMenu->addAction(tr("&Save State"), this, SLOT(saveState()), QString("Ctrl+S")));
romLoadedActions->addAction(fileMenu->addAction(tr("&Load State"), this, SLOT(loadState()), QString("Ctrl+L")));
{
stateSlotMenu = fileMenu->addMenu(tr("S&elect State Slot"));
QMenu *const stateSlotMenu = fileMenu->addMenu(tr("S&elect State Slot"));
stateSlotMenu->setEnabled(false);
stateSlotMenu->addAction(tr("&Previous"), this, SLOT(prevStateSlot()), QString("Ctrl+Z"));
stateSlotMenu->addAction(tr("&Next"), this, SLOT(nextStateSlot()), QString("Ctrl+X"));
stateSlotMenu->addSeparator();
stateSlotGroup = new QActionGroup(mw);
for (int i = 0; i < 10; ++i) {
const int no = i == 9 ? 0 : i + 1;
const QString &strno = QString::number(no);
QAction *action = stateSlotMenu->addAction("Slot &" + strno, this, SLOT(selectStateSlot()), strno);
QAction *const action = stateSlotMenu->addAction("Slot &" + strno, this, SLOT(selectStateSlot()), strno);
action->setCheckable(true);
action->setData(no);
stateSlotGroup->addAction(action);
}
connect(this, SIGNAL(romLoaded(bool)), stateSlotMenu, SLOT(setEnabled(bool)));
}
fileMenu->addSeparator();
@ -149,18 +213,20 @@ pauseInc(4)
{
QMenu *const playm = mw->menuBar()->addMenu(tr("&Play"));
romLoadedActions.append(pauseAction = playm->addAction(tr("&Pause"), this, SLOT(pauseChange()), QString("Ctrl+P")));
romLoadedActions->addAction(pauseAction = playm->addAction(tr("&Pause"), this, SLOT(pauseChange()), QString("Ctrl+P")));
pauseAction->setCheckable(true);
romLoadedActions.append(playm->addAction(tr("Frame &Step"), this, SLOT(frameStep()), QString("Ctrl+.")));
romLoadedActions->addAction(playm->addAction(tr("Frame &Step"), this, SLOT(frameStep()), QString("Ctrl+.")));
playm->addSeparator();
/*romLoadedActions.append(*/syncFrameRateAction = playm->addAction(tr("&Sync Frame Rate to Refresh Rate"), this, SLOT(syncFrameRate()))/*)*/;
syncFrameRateAction = playm->addAction(tr("&Sync Frame Rate to Refresh Rate"));
syncFrameRateAction->setCheckable(true);
romLoadedActions.append(decFrameRateAction = playm->addAction(tr("&Decrease Frame Rate"), this, SLOT(decFrameRate()), QString("Ctrl+D")));
romLoadedActions.append(incFrameRateAction = playm->addAction(tr("&Increase Frame Rate"), this, SLOT(incFrameRate()), QString("Ctrl+I")));
romLoadedActions.append(resetFrameRateAction = playm->addAction(tr("&Reset Frame Rate"), this, SLOT(resetFrameRate()), QString("Ctrl+U")));
connect(syncFrameRateAction, SIGNAL(triggered(bool)), &frameRateAdjuster, SLOT(setDisabled(bool)));
connect(syncFrameRateAction, SIGNAL(triggered(bool)), mw , SLOT(setSyncToRefreshRate(bool)));
foreach (QAction *const action, frameRateAdjuster.actions())
playm->addAction(romLoadedActions->addAction(action));
}
QMenu *settingsm = mw->menuBar()->addMenu(tr("&Settings"));
QMenu *const settingsm = mw->menuBar()->addMenu(tr("&Settings"));
settingsm->addAction(tr("&Input..."), this, SLOT(execInputDialog()));
settingsm->addAction(tr("&Miscellaneous..."), this, SLOT(execMiscDialog()));
@ -177,8 +243,9 @@ pauseInc(4)
palm->addAction(tr("&Global..."), this, SLOT(execGlobalPaletteDialog()));
romPaletteAct = palm->addAction(tr("Current &ROM..."), this, SLOT(execRomPaletteDialog()));
QAction *const romPaletteAct = palm->addAction(tr("Current &ROM..."), this, SLOT(execRomPaletteDialog()));
romPaletteAct->setEnabled(false);
connect(this, SIGNAL(dmgRomLoaded(bool)), romPaletteAct, SLOT(setEnabled(bool)));
}
settingsm->addSeparator();
@ -191,15 +258,13 @@ pauseInc(4)
fsAct->setCheckable(true);
}
foreach (QAction *a, romLoadedActions) {
a->setEnabled(false);
}
romLoadedActions->setEnabled(false);
// settingsm->addAction(hideMenuAct);
mw->menuBar()->addSeparator();
QMenu *helpMenu = mw->menuBar()->addMenu(tr("&Help"));
QMenu *const helpMenu = mw->menuBar()->addMenu(tr("&Help"));
helpMenu->addAction(tr("&About"), this, SLOT(about()));
mw->addActions(mw->menuBar()->actions());
@ -211,14 +276,13 @@ pauseInc(4)
mw->addAction(escAct);
}
mw->setFrameTime(frameTime.get().num, frameTime.get().denom);
mw->setSamplesPerFrame(35112);
connect(source, SIGNAL(setTurbo(bool)), mw, SLOT(setFastForward(bool)));
connect(source, SIGNAL(togglePause()), pauseAction, SLOT(trigger()));
connect(source, SIGNAL(frameStep()), this, SLOT(frameStep()));
connect(source, SIGNAL(decFrameRate()), this, SLOT(decFrameRate()));
connect(source, SIGNAL(incFrameRate()), this, SLOT(incFrameRate()));
connect(source, SIGNAL(resetFrameRate()), this, SLOT(resetFrameRate()));
connect(source, SIGNAL(decFrameRate()), &frameRateAdjuster, SLOT(decFrameRate()));
connect(source, SIGNAL(incFrameRate()), &frameRateAdjuster, SLOT(incFrameRate()));
connect(source, SIGNAL(resetFrameRate()), &frameRateAdjuster, SLOT(resetFrameRate()));
connect(source, SIGNAL(prevStateSlot()), this, SLOT(prevStateSlot()));
connect(source, SIGNAL(nextStateSlot()), this, SLOT(nextStateSlot()));
connect(source, SIGNAL(saveStateSignal()), this, SLOT(saveState()));
@ -229,17 +293,14 @@ pauseInc(4)
connect(mw, SIGNAL(videoBlitterFailure()), this, SLOT(videoBlitterFailure()));
connect(mw, SIGNAL(audioEngineFailure()), this, SLOT(audioEngineFailure()));
connect(mw, SIGNAL(closing()), this, SLOT(saveWindowSize()));
connect(this, SIGNAL(romLoaded(bool)), romLoadedActions, SLOT(setEnabled(bool)));
connect(this, SIGNAL(romLoaded(bool)), stateSlotGroup->actions().at(0), SLOT(setChecked(bool)));
videoDialogChange();
soundDialogChange();
miscDialogChange();
{
QSettings settings;
settings.beginGroup("mainwindow");
mw->resize(settings.value("size", QSize(160, 144)).toSize());
settings.endGroup();
}
mw->resize(QSettings().value("mainwindow/size", QSize(160, 144)).toSize());
for (int i = 1; i < argc; ++i) {
if (argv[i][0] != '-') {
@ -253,10 +314,10 @@ void GambatteMenuHandler::updateRecentFileActions() {
QSettings settings;
QStringList files = settings.value("recentFileList").toStringList();
int numRecentFiles = qMin(files.size(), (int)MaxRecentFiles);
const int numRecentFiles = qMin(files.size(), static_cast<int>(MaxRecentFiles));
for (int i = 0; i < numRecentFiles; ++i) {
QString text = tr("&%1 %2").arg(i + 1).arg(strippedName(files[i]));
const QString &text = tr("&%1 %2").arg(i + 1).arg(strippedName(files[i]));
recentFileActs[i]->setText(text);
recentFileActs[i]->setData(files[i]);
recentFileActs[i]->setVisible(true);
@ -269,12 +330,7 @@ void GambatteMenuHandler::updateRecentFileActions() {
}
void GambatteMenuHandler::setCurrentFile(const QString &fileName) {
QString curFile = fileName;
if (curFile.isEmpty())
mw->setWindowTitle(tr("Gambatte"));
else
mw->setWindowTitle(tr("%1 - %2").arg(strippedName(curFile)).arg(tr("Gambatte")));
mw->setWindowTitle(fileName.isEmpty() ? tr("Gambatte") : tr("%1 - %2").arg(strippedName(fileName)).arg(tr("Gambatte")));
QSettings settings;
QStringList files = settings.value("recentFileList").toStringList();
@ -310,37 +366,28 @@ void GambatteMenuHandler::loadFile(const QString &fileName) {
setDmgPaletteColors();
}
romPaletteAct->setEnabled(!source->isCgb());
setCurrentFile(fileName);
foreach (QAction *a, romLoadedActions) {
a->setEnabled(true);
}
stateSlotMenu->setEnabled(true);
stateSlotGroup->actions().at(0)->setChecked(true);
resetFrameRate();
emit romLoaded(true);
emit dmgRomLoaded(!source->isCgb());
mw->run();
}
void GambatteMenuHandler::open() {
TmpPauser tmpPauser(mw, pauseInc);
const QString &fileName = QFileDialog::getOpenFileName(mw, tr("Open"), recentFileActs[0]->data().toString(),
tr("Game Boy ROM Images (*.dmg *.gb *.gbc *.sgb *.zip);;All Files (*)"));
tr("Game Boy ROM Images (*.dmg *.gb *.gbc *.sgb *.zip);;All Files (*)"));
if (!fileName.isEmpty())
loadFile(fileName);
mw->setFocus(); // giving back focus after getOpenFileName seems to fail at times, which can be problematic with current exclusive mode handling.
// giving back focus after getOpenFileName seems to fail at times, which can be problematic with current exclusive mode handling.
mw->setFocus();
}
void GambatteMenuHandler::openRecentFile() {
QAction *action = qobject_cast<QAction *>(sender());
if (action)
if (const QAction *const action = qobject_cast<QAction *>(sender()))
loadFile(action->data().toString());
}
@ -349,10 +396,10 @@ void GambatteMenuHandler::about() {
QMessageBox::about(
mw,
tr("About Gambatte"),
tr("<h3>Gambatte Qt SVN</h3>\
<p><b>Author:</b> Sindre Aam<EFBFBD>s (<a href=\"mailto:aamas@stud.ntnu.no\">aamas@stud.ntnu.no</a>).<br>\
<b>Homepage:</b> <a href=\"http://sourceforge.net/projects/gambatte\">http://sourceforge.net/projects/gambatte</a>.</p>\
"About Gambatte",
QString::fromUtf8("<h3>Gambatte Qt SVN</h3>\
<p><b>Author:</b> Sindre Aamås (<a href=\"mailto:sinamas@users.sourceforge.net\">sinamas@users.sourceforge.net</a>)<br>\
<b>Homepage:</b> <a href=\"http://sourceforge.net/projects/gambatte\">http://sourceforge.net/projects/gambatte</a></p>\
<p>Gambatte is an accuracy-focused, open-source, cross-platform Game Boy Color emulator written in C++. It is based on hundreds of corner case hardware tests, as well as previous documentation and reverse engineering efforts.</p>")
);
}
@ -370,22 +417,22 @@ void GambatteMenuHandler::romPaletteChange() {
namespace {
struct SetDmgPaletteColorFun {
GambatteSource *source; unsigned palnum; unsigned colornum; unsigned rgb32;
void operator()() { source->setDmgPaletteColor(palnum, colornum, rgb32); }
void operator()() const { source->setDmgPaletteColor(palnum, colornum, rgb32); }
};
}
void GambatteMenuHandler::setDmgPaletteColors() {
for (unsigned palnum = 0; palnum < 3; ++palnum)
for (unsigned colornum = 0; colornum < 4; ++colornum) {
const SetDmgPaletteColorFun fun = { source, palnum, colornum, romPaletteDialog->getColor(palnum, colornum) };
mw->callInWorkerThread(fun);
}
for (unsigned colornum = 0; colornum < 4; ++colornum) {
const SetDmgPaletteColorFun fun = { source, palnum, colornum, romPaletteDialog->getColor(palnum, colornum) };
mw->callInWorkerThread(fun);
}
}
namespace {
struct SetVideoSourceFun {
GambatteSource *source; unsigned sourceIndex;
void operator()() { source->setVideoSource(sourceIndex); }
void operator()() const { source->setVideoSource(sourceIndex); }
};
}
@ -458,7 +505,7 @@ void GambatteMenuHandler::nextStateSlot() {
namespace {
struct SelectStateFun {
GambatteSource *source; int i;
void operator()() { source->selectState(i); }
void operator()() const { source->selectState(i); }
};
}
@ -473,7 +520,7 @@ namespace {
struct SaveStateFun {
GambatteSource *source;
MainWindow::FrameBuffer fb;
void operator()() {
void operator()() const {
source->saveState(MainWindow::FrameBuffer::Locked(fb).get());
}
};
@ -487,7 +534,7 @@ void GambatteMenuHandler::saveState() {
namespace {
struct LoadStateFun {
GambatteSource *source;
void operator()() { source->loadState(); }
void operator()() const { source->loadState(); }
};
}
@ -501,7 +548,7 @@ struct SaveStateAsFun {
GambatteSource *source;
MainWindow::FrameBuffer fb;
QString fileName;
void operator()() {
void operator()() const {
source->saveState(MainWindow::FrameBuffer::Locked(fb).get(), fileName.toLocal8Bit().constData());
}
};
@ -509,8 +556,8 @@ struct SaveStateAsFun {
void GambatteMenuHandler::saveStateAs() {
TmpPauser tmpPauser(mw, pauseInc);
const QString &fileName = QFileDialog::getSaveFileName(mw, tr("Save State"), QString(), tr("Gambatte Quick Save Files (*.gqs);;All Files (*)"));
const QString &fileName = QFileDialog::getSaveFileName(mw, tr("Save State"),
QString(), tr("Gambatte Quick Save Files (*.gqs);;All Files (*)"));
if (!fileName.isEmpty()) {
const SaveStateAsFun fun = { source, MainWindow::FrameBuffer(mw), fileName };
@ -522,7 +569,7 @@ namespace {
struct LoadStateFromFun {
GambatteSource *source;
QString fileName;
void operator()() {
void operator()() const {
source->loadState(fileName.toLocal8Bit().constData());
}
};
@ -530,7 +577,8 @@ struct LoadStateFromFun {
void GambatteMenuHandler::loadStateFrom() {
TmpPauser tmpPauser(mw, pauseInc);
const QString &fileName = QFileDialog::getOpenFileName(mw, tr("Load State"), QString(), tr("Gambatte Quick Save Files (*.gqs);;All Files (*)"));
const QString &fileName = QFileDialog::getOpenFileName(mw, tr("Load State"),
QString(), tr("Gambatte Quick Save Files (*.gqs);;All Files (*)"));
if (!fileName.isEmpty()) {
const LoadStateFromFun fun = { source, fileName };
@ -552,39 +600,6 @@ void GambatteMenuHandler::frameStep() {
pauseAction->trigger();
}
void GambatteMenuHandler::frameRateChange() {
incFrameRateAction->setEnabled(frameTime.decPossible());
decFrameRateAction->setEnabled(frameTime.incPossible());
resetFrameRateAction->setEnabled(frameTime.resetPossible());
mw->setFrameTime(frameTime.get().num, frameTime.get().denom);
}
void GambatteMenuHandler::syncFrameRate() {
const bool checked = syncFrameRateAction->isChecked();
mw->setSyncToRefreshRate(checked);
if (mw->isRunning()) {
incFrameRateAction->setEnabled(!checked & frameTime.decPossible());
decFrameRateAction->setEnabled(!checked & frameTime.incPossible());
resetFrameRateAction->setEnabled(!checked & frameTime.resetPossible());
}
}
void GambatteMenuHandler::decFrameRate() {
frameTime.inc();
frameRateChange();
}
void GambatteMenuHandler::incFrameRate() {
frameTime.dec();
frameRateChange();
}
void GambatteMenuHandler::resetFrameRate() {
frameTime.reset();
frameRateChange();
}
void GambatteMenuHandler::escPressed() {
#ifdef Q_WS_MAC
if (fsAct->isChecked())
@ -599,13 +614,15 @@ void GambatteMenuHandler::escPressed() {
void GambatteMenuHandler::videoBlitterFailure() {
TmpPauser tmpPauser(mw, pauseInc);
QMessageBox::critical(mw, tr("Video engine failure"), tr("Failed to update video output. This may be fixed by changing the video engine settings."));
QMessageBox::critical(mw, tr("Video engine failure"),
tr("Failed to update video output. This may be fixed by changing the video engine settings."));
videoDialog->exec();
}
void GambatteMenuHandler::audioEngineFailure() {
TmpPauser tmpPauser(mw, pauseInc);
QMessageBox::critical(mw, tr("Sound engine failure"), tr("Failed to output audio. This may be fixed by changing the sound settings."));
QMessageBox::critical(mw, tr("Sound engine failure"),
tr("Failed to output audio. This may be fixed by changing the sound settings."));
soundDialog->exec();
}
@ -618,7 +635,5 @@ void GambatteMenuHandler::toggleFullScreen() {
void GambatteMenuHandler::saveWindowSize() {
QSettings settings;
settings.beginGroup("mainwindow");
settings.setValue("size", mw->isFullScreen() ? wsz : mw->size());
settings.endGroup();
settings.setValue("mainwindow/size", mw->isFullScreen() ? wsz : mw->size());
}

View File

@ -34,17 +34,15 @@ class SoundDialog;
class VideoDialog;
class MiscDialog;
class GambatteMenuHandler : public QObject {
class FrameRateAdjuster : public QObject {
Q_OBJECT
enum { MaxRecentFiles = 9 };
class FrameTime {
public:
struct Rational {
unsigned num;
unsigned denom;
Rational(unsigned num = 0, unsigned denom = 0) : num(num), denom(denom) {}
Rational(unsigned num = 0, unsigned denom = 1) : num(num), denom(denom) {}
};
private:
@ -71,11 +69,33 @@ class GambatteMenuHandler : public QObject {
}
void reset() { index = STEPS; }
const Rational& get() const { return frameTimes[index]; }
const Rational& base() const { return frameTimes[STEPS]; }
} frameTime_;
QAction *const decFrameRateAction_;
QAction *const incFrameRateAction_;
QAction *const resetFrameRateAction_;
MainWindow *const mw_;
bool enabled_;
void changed();
public:
FrameRateAdjuster(unsigned baseNum, unsigned baseDenom, MainWindow *mw, QObject *parent = 0);
const QList<QAction*> actions();
public slots:
void setDisabled(bool disabled);
void decFrameRate();
void incFrameRate();
void resetFrameRate();
};
class GambatteMenuHandler : public QObject {
Q_OBJECT
const Rational& get() const {
return frameTimes[index];
}
};
enum { MaxRecentFiles = 9 };
MainWindow *const mw;
GambatteSource *const source;
@ -83,23 +103,17 @@ class GambatteMenuHandler : public QObject {
VideoDialog *const videoDialog;
MiscDialog *const miscDialog;
QAction *recentFileActs[MaxRecentFiles];
QAction *romPaletteAct;
QAction *pauseAction;
QAction *syncFrameRateAction;
QAction *decFrameRateAction;
QAction *incFrameRateAction;
QAction *resetFrameRateAction;
QAction *forceDmgAction;
#ifdef Q_WS_MAC
QAction *fsAct;
#endif
QMenu *recentMenu;
QMenu *stateSlotMenu;
PaletteDialog *globalPaletteDialog;
PaletteDialog *romPaletteDialog;
QActionGroup *stateSlotGroup;
QList<QAction*> romLoadedActions;
FrameTime frameTime;
QActionGroup *const stateSlotGroup;
FrameRateAdjuster frameRateAdjuster;
QSize wsz;
unsigned pauseInc;
@ -107,7 +121,10 @@ class GambatteMenuHandler : public QObject {
void setCurrentFile(const QString &fileName);
void setDmgPaletteColors();
void updateRecentFileActions();
void frameRateChange();
signals:
void romLoaded(bool);
void dmgRomLoaded(bool);
private slots:
void open();
@ -133,10 +150,6 @@ private slots:
void loadStateFrom();
void pauseChange();
void frameStep();
void syncFrameRate();
void decFrameRate();
void incFrameRate();
void resetFrameRate();
void escPressed();
void videoBlitterFailure();
void audioEngineFailure();

View File

@ -171,7 +171,7 @@ static void* getpbdata(const PixelBuffer &pb, const unsigned vsrci) {
return pb.width == VfilterInfo::get(vsrci).outWidth && pb.height == VfilterInfo::get(vsrci).outHeight ? pb.data : 0;
}
long GambatteSource::update(const PixelBuffer &pb, qint16 *soundBuf, long &samples) {
long GambatteSource::update(const PixelBuffer &pb, qint16 *const soundBuf, long &samples) {
setPixelBuffer(getpbdata(pb, vsrci), pb.pixelFormat, pb.pitch);
samples -= overupdate;
@ -184,9 +184,9 @@ long GambatteSource::update(const PixelBuffer &pb, qint16 *soundBuf, long &sampl
setGbDir(inputState[LEFT_BUT], inputState[RIGHT_BUT], dpadLeft, dpadRight, dpadLeftLast);
inputGetter.is = packedInputState(inputState);
unsigned isamples = samples;
const int retval = gb.runFor(gbpixels, gbpitch, reinterpret_cast<uint_least32_t*>(soundBuf), isamples);
samples = isamples;
unsigned usamples = samples;
const long retval = gb.runFor(gbpixels, gbpitch, reinterpret_cast<uint_least32_t*>(soundBuf), usamples);
samples = usamples;
return retval;
}

View File

@ -25,45 +25,45 @@
#include <QPushButton>
#include <QSettings>
template<class Parent, class ChildLayout>
static ChildLayout * addLayout(Parent *const parent, ChildLayout *const child) {
parent->addLayout(child);
return child;
}
template<class Parent, class ChildLayout>
static ChildLayout * addLayout(Parent *const parent, ChildLayout *const child, const Qt::Alignment alignment) {
parent->addLayout(child);
parent->setAlignment(child, alignment);
return child;
}
MiscDialog::MiscDialog(QWidget *const parent) :
QDialog(parent),
turboSpeedBox(new QSpinBox(this)),
pauseOnDialogsBox(new QCheckBox(tr("Pause when displaying dialogs"), this)),
pauseOnFocusOutBox(new QCheckBox(tr("Pause on focus out"), this)),
turboSpeed_(4),
pauseOnDialogs_(true),
pauseOnFocusOut_(false) {
pauseOnDialogs_(new QCheckBox(tr("Pause when displaying dialogs"), this), "misc/pauseOnDialogs", true),
pauseOnFocusOut_(new QCheckBox(tr("Pause on focus out"), this), "misc/pauseOnFocusOut", false),
turboSpeed_(4) {
setWindowTitle(tr("Miscellaneous Settings"));
QVBoxLayout *const mainLayout = new QVBoxLayout;
QVBoxLayout *const topLayout = new QVBoxLayout;
turboSpeedBox->setRange(2, 16);
turboSpeedBox->setSuffix("x");
QVBoxLayout *const mainLayout = new QVBoxLayout(this);
QVBoxLayout *const topLayout = addLayout(mainLayout, new QVBoxLayout);
{
QHBoxLayout *const hLayout = new QHBoxLayout;
QHBoxLayout *const hLayout = addLayout(topLayout, new QHBoxLayout);
hLayout->addWidget(new QLabel(tr("Fast-forward speed:")));
turboSpeedBox->setRange(2, 16);
turboSpeedBox->setSuffix("x");
hLayout->addWidget(turboSpeedBox);
topLayout->addLayout(hLayout);
}
{
QHBoxLayout *const hLayout = new QHBoxLayout;
hLayout->addWidget(pauseOnDialogsBox);
topLayout->addLayout(hLayout);
}
{
QHBoxLayout *const hLayout = new QHBoxLayout;
hLayout->addWidget(pauseOnFocusOutBox);
topLayout->addLayout(hLayout);
}
mainLayout->addLayout(topLayout);
addLayout(topLayout, new QHBoxLayout)->addWidget(pauseOnDialogs_.checkBox());
addLayout(topLayout, new QHBoxLayout)->addWidget(pauseOnFocusOut_.checkBox());
{
QPushButton *const okButton = new QPushButton(tr("OK"), this);
QPushButton *const cancelButton = new QPushButton(tr("Cancel"), this);
QHBoxLayout *const hLayout = new QHBoxLayout;
QHBoxLayout *const hLayout = addLayout(mainLayout, new QHBoxLayout, Qt::AlignBottom | Qt::AlignRight);
hLayout->addWidget(okButton);
hLayout->addWidget(cancelButton);
@ -72,42 +72,27 @@ pauseOnFocusOut_(false) {
connect(okButton, SIGNAL(clicked()), this, SLOT(accept()));
connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject()));
mainLayout->addLayout(hLayout);
mainLayout->setAlignment(hLayout, Qt::AlignBottom | Qt::AlignRight);
}
setLayout(mainLayout);
QSettings settings;
settings.beginGroup("misc");
turboSpeed_ = std::min(std::max(settings.value("turboSpeed", turboSpeed_).toInt(), 2), 16);
pauseOnDialogs_ = settings.value("pauseOnDialogs", pauseOnDialogs_).toBool();
pauseOnFocusOut_ = settings.value("pauseOnFocusOut", pauseOnFocusOut_).toBool();
settings.endGroup();
turboSpeed_ = std::min(std::max(QSettings().value("misc/turboSpeed", turboSpeed_).toInt(), 2), 16);
restore();
}
MiscDialog::~MiscDialog() {
QSettings settings;
settings.beginGroup("misc");
settings.setValue("turboSpeed", turboSpeed_);
settings.setValue("pauseOnDialogs", pauseOnDialogs_);
settings.setValue("pauseOnFocusOut", pauseOnFocusOut_);
settings.endGroup();
settings.setValue("misc/turboSpeed", turboSpeed_);
}
void MiscDialog::store() {
turboSpeed_ = turboSpeedBox->value();
pauseOnDialogs_ = pauseOnDialogsBox->isChecked();
pauseOnFocusOut_ = pauseOnFocusOutBox->isChecked();
pauseOnDialogs_.accept();
pauseOnFocusOut_.accept();
}
void MiscDialog::restore() {
turboSpeedBox->setValue(turboSpeed_);
pauseOnDialogsBox->setChecked(pauseOnDialogs_);
pauseOnFocusOutBox->setChecked(pauseOnFocusOut_);
pauseOnDialogs_.reject();
pauseOnFocusOut_.reject();
}
void MiscDialog::accept() {

View File

@ -20,26 +20,24 @@
#define MISCDIALOG_H
class QSpinBox;
class QCheckBox;
#include "framework/persistcheckbox.h"
#include <QDialog>
class MiscDialog : public QDialog {
QSpinBox *const turboSpeedBox;
QCheckBox *const pauseOnDialogsBox;
QCheckBox *const pauseOnFocusOutBox;
PersistCheckBox pauseOnDialogs_;
PersistCheckBox pauseOnFocusOut_;
int turboSpeed_;
bool pauseOnDialogs_;
bool pauseOnFocusOut_;
void store();
void restore();
public:
MiscDialog(QWidget *parent = 0);
explicit MiscDialog(QWidget *parent = 0);
~MiscDialog();
int turboSpeed() const { return turboSpeed_; }
bool pauseOnDialogs() const { return pauseOnDialogs_ | pauseOnFocusOut_; }
bool pauseOnFocusOut() const { return pauseOnFocusOut_; }
bool pauseOnDialogs() const { return pauseOnDialogs_.value() | pauseOnFocusOut_.value(); }
bool pauseOnFocusOut() const { return pauseOnFocusOut_.value(); }
public slots:
void accept();