mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-09-02 14:22:48 +02:00
Update to v094r42 release.
byuu says: I imagine you guys will like this WIP very much. Changelog: - ListView check boxes on Windows - ListView removal of columns on reset (changing input dropdowns) - DirectSound audio duplication on latency change - DirectSound crash on 20ms latency - Fullscreen window sizing in multi-monitor setups - Allow joypad bindings of hotkeys - Allow triggers to be mapped (Xbox 360 / XInput / Windows only) - Support joypad rumble for Game Boy Player - Video scale settings modified from {1x,2x,3x} to {2x,3x,4x} - System menu now renames to active emulation core - Added fast forward hotkey Not changing for v095: - not adding input focus settings yet - not adding shaders yet Not changing at all: - not implementing maximize
This commit is contained in:
@@ -219,8 +219,10 @@ auto mWindow::setFrameSize(Size size) -> type& {
|
||||
}
|
||||
|
||||
auto mWindow::setFullScreen(bool fullScreen) -> type& {
|
||||
state.fullScreen = fullScreen;
|
||||
signal(setFullScreen, fullScreen);
|
||||
if(fullScreen != state.fullScreen) {
|
||||
state.fullScreen = fullScreen;
|
||||
signal(setFullScreen, fullScreen);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@@ -65,8 +65,7 @@ static auto Window_configure(GtkWidget* widget, GdkEvent* event, pWindow* p) ->
|
||||
//move
|
||||
if(geometry.x() != p->state().geometry.x() || geometry.y() != p->state().geometry.y()) {
|
||||
if(!p->state().fullScreen) {
|
||||
p->state().geometry.setX(geometry.x());
|
||||
p->state().geometry.setY(geometry.y());
|
||||
p->state().geometry.setPosition({geometry.x(), geometry.y()});
|
||||
}
|
||||
if(!p->locked()) p->self().doMove();
|
||||
}
|
||||
@@ -106,8 +105,9 @@ static auto Window_sizeAllocate(GtkWidget* widget, GtkAllocation* allocation, pW
|
||||
if(allocation->width == p->lastAllocation.width
|
||||
&& allocation->height == p->lastAllocation.height) return;
|
||||
|
||||
p->state().geometry.setWidth(allocation->width);
|
||||
p->state().geometry.setHeight(allocation->height);
|
||||
if(!p->state().fullScreen) {
|
||||
p->state().geometry.setSize({allocation->width, allocation->height});
|
||||
}
|
||||
|
||||
if(auto& layout = p->state().layout) {
|
||||
layout->setGeometry(p->self().geometry().setPosition(0, 0));
|
||||
@@ -259,10 +259,13 @@ auto pWindow::setFocused() -> void {
|
||||
}
|
||||
|
||||
auto pWindow::setFullScreen(bool fullScreen) -> void {
|
||||
if(fullScreen == false) {
|
||||
gtk_window_unfullscreen(GTK_WINDOW(widget));
|
||||
} else {
|
||||
if(fullScreen) {
|
||||
windowedGeometry = state().geometry;
|
||||
gtk_window_fullscreen(GTK_WINDOW(widget));
|
||||
state().geometry = Monitor::geometry(Monitor::primary());
|
||||
} else {
|
||||
gtk_window_unfullscreen(GTK_WINDOW(widget));
|
||||
state().geometry = windowedGeometry;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -5,15 +5,6 @@ namespace hiro {
|
||||
struct pWindow : pObject {
|
||||
Declare(Window, Object)
|
||||
|
||||
GtkWidget* widget = nullptr;
|
||||
GtkWidget* menuContainer = nullptr;
|
||||
GtkWidget* formContainer = nullptr;
|
||||
GtkWidget* statusContainer = nullptr;
|
||||
GtkWidget* gtkMenu = nullptr;
|
||||
GtkWidget* gtkStatus = nullptr;
|
||||
GtkAllocation lastAllocation = {0};
|
||||
bool onSizePending = false;
|
||||
|
||||
auto append(sLayout layout) -> void;
|
||||
auto append(sMenuBar menuBar) -> void;
|
||||
auto append(sStatusBar statusBar) -> void;
|
||||
@@ -45,6 +36,16 @@ struct pWindow : pObject {
|
||||
auto _setStatusText(const string& text) -> void;
|
||||
auto _setStatusVisible(bool visible) -> void;
|
||||
auto _statusHeight() const -> signed;
|
||||
|
||||
GtkWidget* widget = nullptr;
|
||||
GtkWidget* menuContainer = nullptr;
|
||||
GtkWidget* formContainer = nullptr;
|
||||
GtkWidget* statusContainer = nullptr;
|
||||
GtkWidget* gtkMenu = nullptr;
|
||||
GtkWidget* gtkStatus = nullptr;
|
||||
GtkAllocation lastAllocation = {0};
|
||||
bool onSizePending = false;
|
||||
Geometry windowedGeometry{128, 128, 256, 256};
|
||||
};
|
||||
|
||||
}
|
||||
|
@@ -89,13 +89,6 @@ auto pWindow::remove(sMenuBar menuBar) -> void {
|
||||
auto pWindow::remove(sStatusBar statusBar) -> void {
|
||||
}
|
||||
|
||||
/*
|
||||
//orphan() destroys and recreates widgets (to disassociate them from their parent);
|
||||
//attempting to create widget again after QApplication::quit() crashes libQtGui
|
||||
if(qtApplication) widget.p.orphan();
|
||||
}
|
||||
*/
|
||||
|
||||
auto pWindow::setBackgroundColor(Color color) -> void {
|
||||
if(color) {
|
||||
QPalette palette;
|
||||
@@ -120,15 +113,20 @@ auto pWindow::setFocused() -> void {
|
||||
}
|
||||
|
||||
auto pWindow::setFullScreen(bool fullScreen) -> void {
|
||||
if(!fullScreen) {
|
||||
setResizable(state().resizable);
|
||||
qtWindow->showNormal();
|
||||
qtWindow->adjustSize();
|
||||
} else {
|
||||
lock();
|
||||
if(fullScreen) {
|
||||
windowedGeometry = state().geometry;
|
||||
qtLayout->setSizeConstraint(QLayout::SetDefaultConstraint);
|
||||
qtContainer->setFixedSize(Desktop::size().width() - frameMargin().width(), Desktop::size().height() - frameMargin().height());
|
||||
qtWindow->showFullScreen();
|
||||
state().geometry = Monitor::geometry(Monitor::primary());
|
||||
} else {
|
||||
setResizable(state().resizable);
|
||||
qtWindow->showNormal();
|
||||
qtWindow->adjustSize();
|
||||
self().setGeometry(windowedGeometry);
|
||||
}
|
||||
unlock();
|
||||
}
|
||||
|
||||
auto pWindow::setGeometry(Geometry geometry) -> void {
|
||||
@@ -256,8 +254,10 @@ auto QtWindow::closeEvent(QCloseEvent* event) -> void {
|
||||
|
||||
auto QtWindow::moveEvent(QMoveEvent* event) -> void {
|
||||
if(!p.locked() && !p.state().fullScreen && p.qtWindow->isVisible()) {
|
||||
p.state().geometry.setX(p.state().geometry.x() + event->pos().x() - event->oldPos().x());
|
||||
p.state().geometry.setY(p.state().geometry.y() + event->pos().y() - event->oldPos().y());
|
||||
p.state().geometry.setPosition({
|
||||
p.state().geometry.x() + event->pos().x() - event->oldPos().x(),
|
||||
p.state().geometry.y() + event->pos().y() - event->oldPos().y()
|
||||
});
|
||||
}
|
||||
|
||||
if(!p.locked()) {
|
||||
@@ -287,8 +287,10 @@ auto QtWindow::keyReleaseEvent(QKeyEvent* event) -> void {
|
||||
|
||||
auto QtWindow::resizeEvent(QResizeEvent*) -> void {
|
||||
if(!p.locked() && !p.state().fullScreen && p.qtWindow->isVisible()) {
|
||||
p.state().geometry.setWidth(p.qtContainer->geometry().width());
|
||||
p.state().geometry.setHeight(p.qtContainer->geometry().height());
|
||||
p.state().geometry.setSize({
|
||||
p.qtContainer->geometry().width(),
|
||||
p.qtContainer->geometry().height()
|
||||
});
|
||||
}
|
||||
|
||||
if(auto& layout = p.state().layout) {
|
||||
|
@@ -34,6 +34,7 @@ struct pWindow : pObject {
|
||||
QMenuBar* qtMenuBar = nullptr;
|
||||
QStatusBar* qtStatusBar = nullptr;
|
||||
QWidget* qtContainer = nullptr;
|
||||
Geometry windowedGeometry{128, 128, 256, 256};
|
||||
};
|
||||
|
||||
}
|
||||
|
@@ -6,7 +6,7 @@ static const unsigned WindowsVista = 0x0600;
|
||||
static const unsigned Windows7 = 0x0601;
|
||||
|
||||
static auto OsVersion() -> unsigned {
|
||||
OSVERSIONINFO versionInfo = {0};
|
||||
OSVERSIONINFO versionInfo{0};
|
||||
versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
||||
GetVersionEx(&versionInfo);
|
||||
return (versionInfo.dwMajorVersion << 8) + (versionInfo.dwMajorVersion << 0);
|
||||
@@ -283,6 +283,20 @@ static auto CALLBACK Shared_windowProc(WindowProc windowProc, HWND hwnd, UINT ms
|
||||
}
|
||||
|
||||
case WM_NOTIFY: {
|
||||
//WC_TABCONTROL requires parenting widgets to it; rather than the WINDOW
|
||||
//without doing this; backgrounds on transparent controls (eg STATIC) are painted wrong
|
||||
//this causes some WC_LISTVIEW WM_NOTIFY messages to only go to the WC_TABCONTROL WNDPROC
|
||||
//all other controls also send their messages to the WC_TABCONTROL WNDPROC
|
||||
//to avoid duplicating all message logic, hiro shares a WNDPROC with Window and TabFrame
|
||||
//LVN_ITEM(ACTIVATE,CHANGED) are only sent to the TabFrame, as expected
|
||||
//yet for unknown reasons, LVN_COLUMNCLICK and NM_(CLICK,DBLCLK,RCLICK) are
|
||||
//sent to both the TabFrame, and then again to the Window's WNDPROC
|
||||
//this causes on(Sort,Toggle,Context) to trigger callbacks twice
|
||||
//if we try to block propagation to the Window (via return instead of break); then
|
||||
//this will result in the LVN_ITEM(ACTIVATE,CHANGED) never being invoked (unsure why)
|
||||
//as a workaround; we must detect these message to the Windows' WNDPROC, and block them
|
||||
bool isWindowCallback = (object == window);
|
||||
|
||||
auto header = (LPNMHDR)lparam;
|
||||
auto object = (mObject*)GetWindowLongPtr((HWND)header->hwndFrom, GWLP_USERDATA);
|
||||
if(!object) break;
|
||||
@@ -298,15 +312,16 @@ static auto CALLBACK Shared_windowProc(WindowProc windowProc, HWND hwnd, UINT ms
|
||||
break;
|
||||
}
|
||||
if(header->code == LVN_COLUMNCLICK) {
|
||||
listView->self()->onSort(lparam);
|
||||
if(!isWindowCallback) listView->self()->onSort(lparam);
|
||||
break;
|
||||
}
|
||||
if(header->code == NM_CLICK || header->code == NM_DBLCLK) {
|
||||
listView->self()->onToggle(lparam);
|
||||
//onToggle performs the test to ensure the ListViewItem clicked was checkable
|
||||
if(!isWindowCallback) listView->self()->onToggle(lparam);
|
||||
break;
|
||||
}
|
||||
if(header->code == NM_RCLICK) {
|
||||
listView->self()->onContext(lparam);
|
||||
if(!isWindowCallback) listView->self()->onContext(lparam);
|
||||
break;
|
||||
}
|
||||
if(header->code == NM_CUSTOMDRAW) {
|
||||
|
@@ -52,6 +52,10 @@ auto pListView::append(sListViewItem item) -> void {
|
||||
}
|
||||
|
||||
auto pListView::remove(sListViewHeader header) -> void {
|
||||
LVCOLUMN lvColumn{LVCF_WIDTH};
|
||||
while(ListView_GetColumn(hwnd, 0, &lvColumn)) {
|
||||
ListView_DeleteColumn(hwnd, 0);
|
||||
}
|
||||
}
|
||||
|
||||
auto pListView::remove(sListViewItem item) -> void {
|
||||
|
@@ -91,10 +91,8 @@ auto pWindow::setFont(const string& font) -> void {
|
||||
auto pWindow::setFullScreen(bool fullScreen) -> void {
|
||||
auto style = GetWindowLongPtr(hwnd, GWL_STYLE) & WS_VISIBLE;
|
||||
lock();
|
||||
if(fullScreen == false) {
|
||||
SetWindowLongPtr(hwnd, GWL_STYLE, style | (state().resizable ? ResizableStyle : FixedStyle));
|
||||
setGeometry(state().geometry);
|
||||
} else {
|
||||
if(fullScreen) {
|
||||
windowedGeometry = self().geometry();
|
||||
HMONITOR monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
|
||||
MONITORINFOEX info;
|
||||
memset(&info, 0, sizeof(MONITORINFOEX));
|
||||
@@ -104,10 +102,13 @@ auto pWindow::setFullScreen(bool fullScreen) -> void {
|
||||
Geometry geometry = {rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top};
|
||||
SetWindowLongPtr(hwnd, GWL_STYLE, style | WS_POPUP);
|
||||
Geometry margin = frameMargin();
|
||||
setGeometry({
|
||||
self().setGeometry({
|
||||
geometry.x() + margin.x(), geometry.y() + margin.y(),
|
||||
geometry.width() - margin.width(), geometry.height() - margin.height()
|
||||
});
|
||||
} else {
|
||||
SetWindowLongPtr(hwnd, GWL_STYLE, style | (state().resizable ? ResizableStyle : FixedStyle));
|
||||
self().setGeometry(windowedGeometry);
|
||||
}
|
||||
unlock();
|
||||
}
|
||||
@@ -116,7 +117,7 @@ auto pWindow::setGeometry(Geometry geometry) -> void {
|
||||
lock();
|
||||
Geometry margin = frameMargin();
|
||||
SetWindowPos(
|
||||
hwnd, NULL,
|
||||
hwnd, nullptr,
|
||||
geometry.x() - margin.x(), geometry.y() - margin.y(),
|
||||
geometry.width() + margin.width(), geometry.height() + margin.height(),
|
||||
SWP_NOZORDER | SWP_FRAMECHANGED
|
||||
|
@@ -42,6 +42,7 @@ struct pWindow : pObject {
|
||||
HFONT hstatusfont = nullptr;
|
||||
HBRUSH hbrush = nullptr;
|
||||
COLORREF hbrushColor = 0;
|
||||
Geometry windowedGeometry{128, 128, 256, 256};
|
||||
};
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user