Update to v106r39 release.

byuu says:

Changelog:

  - ruby/video: implement onUpdate() callback to signal when redraws are
    necessary
  - ruby/video/GLX,GLX2,XVideo,XShm: implement onUpdate() support
  - bsnes: implement Video::onUpdate() support to redraw Viewport icon
    as needed
  - bsnes: save RAM before ruby driver changes
  - sfc/sa1: clip signed multiplication to 32-bit [Jonas Quinn]
  - sfc/sa1: handle negative dividends in division [Jonas Quinn]
  - hiro/gtk3: a few improvements
  - bsnes: added empty stub video and audio settings panels
  - bsnes: restructured advanced settings panel
  - bsnes: experiment: input/hotkeys name column bolded and colored for
    increased visual distinction
  - bsnes: added save button to state manager
This commit is contained in:
Tim Allen 2018-06-10 18:07:19 +10:00
parent 15b67922b3
commit 91bb781b73
24 changed files with 183 additions and 58 deletions

View File

@ -13,7 +13,7 @@ using namespace nall;
namespace Emulator { namespace Emulator {
static const string Name = "higan"; static const string Name = "higan";
static const string Version = "106.38"; static const string Version = "106.39";
static const string Author = "byuu"; static const string Author = "byuu";
static const string License = "GPLv3"; static const string License = "GPLv3";
static const string Website = "https://byuu.org/"; static const string Website = "https://byuu.org/";

View File

@ -415,19 +415,19 @@ auto SA1::writeIO(uint24 addr, uint8 data) -> void {
//(MAL) multiplicand / dividend low //(MAL) multiplicand / dividend low
case 0x2251: { case 0x2251: {
mmio.ma = (mmio.ma & 0xff00) | data; mmio.ma.byte(0) = data;
return; return;
} }
//(MAH) multiplicand / dividend high //(MAH) multiplicand / dividend high
case 0x2252: { case 0x2252: {
mmio.ma = (data << 8) | (mmio.ma & 0x00ff); mmio.ma.byte(1) = data;
return; return;
} }
//(MBL) multiplier / divisor low //(MBL) multiplier / divisor low
case 0x2253: { case 0x2253: {
mmio.mb = (mmio.mb & 0xff00) | data; mmio.mb.byte(0) = data;
return; return;
} }
@ -435,21 +435,23 @@ auto SA1::writeIO(uint24 addr, uint8 data) -> void {
//multiplication / cumulative sum only resets MB //multiplication / cumulative sum only resets MB
//division resets both MA and MB //division resets both MA and MB
case 0x2254: { case 0x2254: {
mmio.mb = (data << 8) | (mmio.mb & 0x00ff); mmio.mb.byte(1) = data;
if(mmio.acm == 0) { if(mmio.acm == 0) {
if(mmio.md == 0) { if(mmio.md == 0) {
//signed multiplication //signed multiplication
mmio.mr = (int16)mmio.ma * (int16)mmio.mb; mmio.mr = (uint32)((int16)mmio.ma * (int16)mmio.mb);
mmio.mb = 0; mmio.mb = 0;
} else { } else {
//unsigned division //unsigned division
if(mmio.mb == 0) { if(mmio.mb == 0) {
mmio.mr = 0; mmio.mr = 0;
} else { } else {
int16 quotient = (int16)mmio.ma / (uint16)mmio.mb; int16 dividend = mmio.ma;
uint16 remainder = (int16)mmio.ma % (uint16)mmio.mb; uint16 divisor = mmio.mb;
mmio.mr = (remainder << 16) | quotient; uint16 remainder = dividend >= 0 ? dividend % divisor : (dividend % divisor + divisor) % divisor;
uint16 quotient = (dividend - remainder) / divisor;
mmio.mr = remainder << 16 | quotient;
} }
mmio.ma = 0; mmio.ma = 0;
mmio.mb = 0; mmio.mb = 0;
@ -457,8 +459,8 @@ auto SA1::writeIO(uint24 addr, uint8 data) -> void {
} else { } else {
//sigma (accumulative multiplication) //sigma (accumulative multiplication)
mmio.mr += (int16)mmio.ma * (int16)mmio.mb; mmio.mr += (int16)mmio.ma * (int16)mmio.mb;
mmio.overflow = (mmio.mr >= (1ULL << 40)); mmio.overflow = mmio.mr >> 40;
mmio.mr &= (1ULL << 40) - 1; mmio.mr = (uint40)mmio.mr;
mmio.mb = 0; mmio.mb = 0;
} }
return; return;

View File

@ -99,10 +99,12 @@ Presentation::Presentation() {
statusBar.setVisible(showStatusBar.checked()); statusBar.setVisible(showStatusBar.checked());
if(visible()) resizeWindow(); if(visible()) resizeWindow();
}); });
inputSettings.setText("Input ...").onActivate([&] { settingsWindow->show(0); }); videoSettings.setText("Video ...").onActivate([&] { settingsWindow->show(0); });
hotkeySettings.setText("Hotkeys ...").onActivate([&] { settingsWindow->show(1); }); audioSettings.setText("Audio ...").onActivate([&] { settingsWindow->show(1); });
pathSettings.setText("Paths ...").onActivate([&] { settingsWindow->show(2); }); inputSettings.setText("Input ...").onActivate([&] { settingsWindow->show(2); });
advancedSettings.setText("Advanced ...").onActivate([&] { settingsWindow->show(3); }); hotkeySettings.setText("Hotkeys ...").onActivate([&] { settingsWindow->show(3); });
pathSettings.setText("Paths ...").onActivate([&] { settingsWindow->show(4); });
advancedSettings.setText("Advanced ...").onActivate([&] { settingsWindow->show(5); });
toolsMenu.setText("Tools").setVisible(false); toolsMenu.setText("Tools").setVisible(false);
saveState.setText("Save State"); saveState.setText("Save State");
@ -171,7 +173,7 @@ Presentation::Presentation() {
#if defined(PLATFORM_MACOS) #if defined(PLATFORM_MACOS)
Application::Cocoa::onAbout([&] { about.doActivate(); }); Application::Cocoa::onAbout([&] { about.doActivate(); });
Application::Cocoa::onActivate([&] { setFocused(); }); Application::Cocoa::onActivate([&] { setFocused(); });
Application::Cocoa::onPreferences([&] { settingsWindow->show(0); }); Application::Cocoa::onPreferences([&] { settingsWindow->show(2); });
Application::Cocoa::onQuit([&] { doClose(); }); Application::Cocoa::onQuit([&] { doClose(); });
#endif #endif
} }

View File

@ -49,6 +49,8 @@ struct Presentation : Window {
MenuCheckItem muteAudio{&settingsMenu}; MenuCheckItem muteAudio{&settingsMenu};
MenuCheckItem showStatusBar{&settingsMenu}; MenuCheckItem showStatusBar{&settingsMenu};
MenuSeparator settingsSeparator{&settingsMenu}; MenuSeparator settingsSeparator{&settingsMenu};
MenuItem videoSettings{&settingsMenu};
MenuItem audioSettings{&settingsMenu};
MenuItem inputSettings{&settingsMenu}; MenuItem inputSettings{&settingsMenu};
MenuItem hotkeySettings{&settingsMenu}; MenuItem hotkeySettings{&settingsMenu};
MenuItem pathSettings{&settingsMenu}; MenuItem pathSettings{&settingsMenu};

View File

@ -77,6 +77,7 @@ Program::Program(string_vector arguments) {
auto Program::main() -> void { auto Program::main() -> void {
updateMessage(); updateMessage();
video->poll();
inputManager->poll(); inputManager->poll();
inputManager->pollHotkeys(); inputManager->pollHotkeys();

View File

@ -8,6 +8,10 @@ auto Program::initializeVideoDriver() -> void {
presentation->clearViewport(); presentation->clearViewport();
updateVideoShader(); updateVideoShader();
} }
video->onUpdate([&](uint width, uint height) {
if(!emulator->loaded()) presentation->clearViewport();
});
} }
auto Program::initializeAudioDriver() -> void { auto Program::initializeAudioDriver() -> void {

View File

@ -3,8 +3,9 @@ AdvancedSettings::AdvancedSettings(TabFrame* parent) : TabFrameItem(parent) {
setText("Advanced"); setText("Advanced");
layout.setMargin(5); layout.setMargin(5);
driversLabel.setText("Drivers").setFont(Font().setBold());
videoDriverLabel.setText("Video Driver:"); videoDriverLabel.setText("Video:");
for(auto& driver : Video::availableDrivers()) { for(auto& driver : Video::availableDrivers()) {
ComboButtonItem item; ComboButtonItem item;
item.setText(driver); item.setText(driver);
@ -12,10 +13,6 @@ AdvancedSettings::AdvancedSettings(TabFrame* parent) : TabFrameItem(parent) {
if(video->driver() == driver) item.setSelected(); if(video->driver() == driver) item.setSelected();
} }
videoDriverOption.onChange([&] { videoDriverOption.onChange([&] {
auto item = videoDriverOption.selected();
videoDriverChange.setEnabled(video->driver() != item.text());
});
videoDriverChange.setText("Change").setEnabled(false).onActivate([&] {
auto item = videoDriverOption.selected(); auto item = videoDriverOption.selected();
settings["Video/Driver"].setValue(item.text()); settings["Video/Driver"].setValue(item.text());
if(!emulator->loaded() || item.text() == "None" || MessageDialog( if(!emulator->loaded() || item.text() == "None" || MessageDialog(
@ -23,6 +20,7 @@ AdvancedSettings::AdvancedSettings(TabFrame* parent) : TabFrameItem(parent) {
"It is highly recommended you unload your game first to avoid data loss.\n" "It is highly recommended you unload your game first to avoid data loss.\n"
"Do you wish to proceed with the video driver change now anyway?" "Do you wish to proceed with the video driver change now anyway?"
).setParent(*settingsWindow).question() == "Yes") { ).setParent(*settingsWindow).question() == "Yes") {
program->save();
program->saveRecoveryState(); program->saveRecoveryState();
settings["Crashed"].setValue(true); settings["Crashed"].setValue(true);
settings.save(); settings.save();
@ -39,11 +37,10 @@ AdvancedSettings::AdvancedSettings(TabFrame* parent) : TabFrameItem(parent) {
} }
settings["Crashed"].setValue(false); settings["Crashed"].setValue(false);
settings.save(); settings.save();
videoDriverChange.setEnabled(false);
} }
}); });
audioDriverLabel.setText("Audio Driver:"); audioDriverLabel.setText("Audio:");
for(auto& driver : Audio::availableDrivers()) { for(auto& driver : Audio::availableDrivers()) {
ComboButtonItem item; ComboButtonItem item;
item.setText(driver); item.setText(driver);
@ -51,10 +48,6 @@ AdvancedSettings::AdvancedSettings(TabFrame* parent) : TabFrameItem(parent) {
if(audio->driver() == driver) item.setSelected(); if(audio->driver() == driver) item.setSelected();
} }
audioDriverOption.onChange([&] { audioDriverOption.onChange([&] {
auto item = audioDriverOption.selected();
audioDriverChange.setEnabled(audio->driver() != item.text());
});
audioDriverChange.setText("Change").setEnabled(false).onActivate([&] {
auto item = audioDriverOption.selected(); auto item = audioDriverOption.selected();
settings["Audio/Driver"].setValue(item.text()); settings["Audio/Driver"].setValue(item.text());
if(!emulator->loaded() || item.text() == "None" || MessageDialog( if(!emulator->loaded() || item.text() == "None" || MessageDialog(
@ -62,6 +55,7 @@ AdvancedSettings::AdvancedSettings(TabFrame* parent) : TabFrameItem(parent) {
"It is highly recommended you unload your game first to avoid data loss.\n" "It is highly recommended you unload your game first to avoid data loss.\n"
"Do you wish to proceed with the audio driver change now anyway?" "Do you wish to proceed with the audio driver change now anyway?"
).setParent(*settingsWindow).question() == "Yes") { ).setParent(*settingsWindow).question() == "Yes") {
program->save();
program->saveRecoveryState(); program->saveRecoveryState();
settings["Crashed"].setValue(true); settings["Crashed"].setValue(true);
settings.save(); settings.save();
@ -78,11 +72,10 @@ AdvancedSettings::AdvancedSettings(TabFrame* parent) : TabFrameItem(parent) {
} }
settings["Crashed"].setValue(false); settings["Crashed"].setValue(false);
settings.save(); settings.save();
audioDriverChange.setEnabled(false);
} }
}); });
inputDriverLabel.setText("Input Driver:"); inputDriverLabel.setText("Input:");
for(auto& driver : Input::availableDrivers()) { for(auto& driver : Input::availableDrivers()) {
ComboButtonItem item; ComboButtonItem item;
item.setText(driver); item.setText(driver);
@ -90,10 +83,6 @@ AdvancedSettings::AdvancedSettings(TabFrame* parent) : TabFrameItem(parent) {
if(input->driver() == driver) item.setSelected(); if(input->driver() == driver) item.setSelected();
} }
inputDriverOption.onChange([&] { inputDriverOption.onChange([&] {
auto item = inputDriverOption.selected();
inputDriverChange.setEnabled(input->driver() != item.text());
});
inputDriverChange.setText("Change").setEnabled(false).onActivate([&] {
auto item = inputDriverOption.selected(); auto item = inputDriverOption.selected();
settings["Input/Driver"].setValue(item.text()); settings["Input/Driver"].setValue(item.text());
if(!emulator->loaded() || item.text() == "None" || MessageDialog( if(!emulator->loaded() || item.text() == "None" || MessageDialog(
@ -101,6 +90,7 @@ AdvancedSettings::AdvancedSettings(TabFrame* parent) : TabFrameItem(parent) {
"It is highly recommended you unload your game first to avoid data loss.\n" "It is highly recommended you unload your game first to avoid data loss.\n"
"Do you wish to proceed with the input driver change now anyway?" "Do you wish to proceed with the input driver change now anyway?"
).setParent(*settingsWindow).question() == "Yes") { ).setParent(*settingsWindow).question() == "Yes") {
program->save();
program->saveRecoveryState(); program->saveRecoveryState();
settings["Crashed"].setValue(true); settings["Crashed"].setValue(true);
settings.save(); settings.save();
@ -117,7 +107,6 @@ AdvancedSettings::AdvancedSettings(TabFrame* parent) : TabFrameItem(parent) {
} }
settings["Crashed"].setValue(false); settings["Crashed"].setValue(false);
settings.save(); settings.save();
inputDriverChange.setEnabled(false);
} }
}); });
} }

View File

@ -0,0 +1,4 @@
AudioSettings::AudioSettings(TabFrame* parent) : TabFrameItem(parent) {
setIcon(Icon::Device::Speaker);
setText("Audio");
}

View File

@ -34,7 +34,7 @@ auto HotkeySettings::reloadMappings() -> void {
); );
for(auto& hotkey : inputManager->hotkeys) { for(auto& hotkey : inputManager->hotkeys) {
mappingList.append(TableViewItem() mappingList.append(TableViewItem()
.append(TableViewCell().setText(hotkey.name)) .append(TableViewCell().setText(hotkey.name).setFont(Font().setBold()).setBackgroundColor({240, 240, 255}))
.append(TableViewCell()) .append(TableViewCell())
); );
} }

View File

@ -98,7 +98,7 @@ auto InputSettings::reloadMappings() -> void {
); );
for(auto& mapping : activeDevice().mappings) { for(auto& mapping : activeDevice().mappings) {
mappingList.append(TableViewItem() mappingList.append(TableViewItem()
.append(TableViewCell().setText(mapping.name)) .append(TableViewCell().setText(mapping.name).setFont(Font().setBold()).setBackgroundColor({240, 240, 255}))
.append(TableViewCell()) .append(TableViewCell())
); );
} }
@ -111,6 +111,7 @@ auto InputSettings::refreshMappings() -> void {
for(auto& mapping : activeDevice().mappings) { for(auto& mapping : activeDevice().mappings) {
mappingList.item(index++).cell(1).setText(mapping.displayName()); mappingList.item(index++).cell(1).setText(mapping.displayName());
} }
Application::processEvents();
mappingList.resizeColumns(); mappingList.resizeColumns();
} }

View File

@ -1,4 +1,6 @@
#include "../bsnes.hpp" #include "../bsnes.hpp"
#include "video.cpp"
#include "audio.cpp"
#include "input.cpp" #include "input.cpp"
#include "hotkeys.cpp" #include "hotkeys.cpp"
#include "paths.cpp" #include "paths.cpp"

View File

@ -3,6 +3,14 @@ struct Settings : Markup::Node {
auto save() -> void; auto save() -> void;
}; };
struct VideoSettings : TabFrameItem {
VideoSettings(TabFrame*);
};
struct AudioSettings : TabFrameItem {
AudioSettings(TabFrame*);
};
struct InputSettings : TabFrameItem { struct InputSettings : TabFrameItem {
InputSettings(TabFrame*); InputSettings(TabFrame*);
auto updateControls() -> void; auto updateControls() -> void;
@ -99,18 +107,14 @@ struct AdvancedSettings : TabFrameItem {
public: public:
VerticalLayout layout{this}; VerticalLayout layout{this};
HorizontalLayout videoDriverLayout{&layout, Size{~0, 0}}; Label driversLabel{&layout, Size{~0, 0}, 2};
Label videoDriverLabel{&videoDriverLayout, Size{75, 0}}; HorizontalLayout driverLayout{&layout, Size{~0, 0}};
ComboButton videoDriverOption{&videoDriverLayout, Size{~0, 0}}; Label videoDriverLabel{&driverLayout, Size{0, 0}};
Button videoDriverChange{&videoDriverLayout, Size{80, 0}}; ComboButton videoDriverOption{&driverLayout, Size{~0, 0}};
HorizontalLayout audioDriverLayout{&layout, Size{~0, 0}}; Label audioDriverLabel{&driverLayout, Size{0, 0}};
Label audioDriverLabel{&audioDriverLayout, Size{75, 0}}; ComboButton audioDriverOption{&driverLayout, Size{~0, 0}};
ComboButton audioDriverOption{&audioDriverLayout, Size{~0, 0}}; Label inputDriverLabel{&driverLayout, Size{0, 0}};
Button audioDriverChange{&audioDriverLayout, Size{80, 0}}; ComboButton inputDriverOption{&driverLayout, Size{~0, 0}};
HorizontalLayout inputDriverLayout{&layout, Size{~0, 0}};
Label inputDriverLabel{&inputDriverLayout, Size{75, 0}};
ComboButton inputDriverOption{&inputDriverLayout, Size{~0, 0}};
Button inputDriverChange{&inputDriverLayout, Size{80, 0}};
}; };
struct SettingsWindow : Window { struct SettingsWindow : Window {
@ -121,6 +125,8 @@ struct SettingsWindow : Window {
public: public:
VerticalLayout layout{this}; VerticalLayout layout{this};
TabFrame panel{&layout, Size{~0, ~0}}; TabFrame panel{&layout, Size{~0, ~0}};
VideoSettings video{&panel};
AudioSettings audio{&panel};
InputSettings input{&panel}; InputSettings input{&panel};
HotkeySettings hotkeys{&panel}; HotkeySettings hotkeys{&panel};
PathSettings paths{&panel}; PathSettings paths{&panel};

View File

@ -0,0 +1,4 @@
VideoSettings::VideoSettings(TabFrame* parent) : TabFrameItem(parent) {
setIcon(Icon::Device::Display);
setText("Video");
}

View File

@ -75,6 +75,7 @@ StateManager::StateManager(TabFrame* parent) : TabFrameItem(parent) {
stateList.onChange([&] { stateList.onChange([&] {
auto batched = stateList.batched(); auto batched = stateList.batched();
loadButton.setEnabled(batched.size() == 1); loadButton.setEnabled(batched.size() == 1);
saveButton.setEnabled(batched.size() == 1);
editButton.setEnabled(batched.size() == 1); editButton.setEnabled(batched.size() == 1);
removeButton.setEnabled(batched.size() >= 1); removeButton.setEnabled(batched.size() >= 1);
}); });
@ -84,6 +85,11 @@ StateManager::StateManager(TabFrame* parent) : TabFrameItem(parent) {
} }
}); });
saveButton.setText("Save").onActivate([&] { saveButton.setText("Save").onActivate([&] {
if(auto item = stateList.selected()) {
program->saveState(item.cell(0).text());
}
});
addButton.setText("Add").onActivate([&] {
stateWindow->show(); stateWindow->show();
}); });
editButton.setText("Edit").onActivate([&] { editButton.setText("Edit").onActivate([&] {

View File

@ -100,8 +100,9 @@ public:
TableView stateList{&layout, Size{~0, ~0}}; TableView stateList{&layout, Size{~0, ~0}};
HorizontalLayout controlLayout{&layout, Size{~0, 0}}; HorizontalLayout controlLayout{&layout, Size{~0, 0}};
Button loadButton{&controlLayout, Size{80, 0}}; Button loadButton{&controlLayout, Size{80, 0}};
Widget spacer{&controlLayout, Size{~0, 0}};
Button saveButton{&controlLayout, Size{80, 0}}; Button saveButton{&controlLayout, Size{80, 0}};
Widget spacer{&controlLayout, Size{~0, 0}};
Button addButton{&controlLayout, Size{80, 0}};
Button editButton{&controlLayout, Size{80, 0}}; Button editButton{&controlLayout, Size{80, 0}};
Button removeButton{&controlLayout, Size{80, 0}}; Button removeButton{&controlLayout, Size{80, 0}};
}; };

View File

@ -10,6 +10,11 @@ GtkSelectionData* data, unsigned type, unsigned timestamp, pCanvas* p) -> void {
p->self().doDrop(paths); p->self().doDrop(paths);
} }
static auto Canvas_draw(GtkWidget* widget, cairo_t* context, pCanvas* p) -> signed {
p->_onDraw(context);
return true;
}
static auto Canvas_expose(GtkWidget* widget, GdkEventExpose* event, pCanvas* p) -> signed { static auto Canvas_expose(GtkWidget* widget, GdkEventExpose* event, pCanvas* p) -> signed {
p->_onExpose(event); p->_onExpose(event);
return true; return true;
@ -59,7 +64,11 @@ auto pCanvas::construct() -> void {
g_signal_connect(G_OBJECT(gtkWidget), "button-press-event", G_CALLBACK(Canvas_mousePress), (gpointer)this); g_signal_connect(G_OBJECT(gtkWidget), "button-press-event", G_CALLBACK(Canvas_mousePress), (gpointer)this);
g_signal_connect(G_OBJECT(gtkWidget), "button-release-event", G_CALLBACK(Canvas_mouseRelease), (gpointer)this); g_signal_connect(G_OBJECT(gtkWidget), "button-release-event", G_CALLBACK(Canvas_mouseRelease), (gpointer)this);
g_signal_connect(G_OBJECT(gtkWidget), "drag-data-received", G_CALLBACK(Canvas_drop), (gpointer)this); g_signal_connect(G_OBJECT(gtkWidget), "drag-data-received", G_CALLBACK(Canvas_drop), (gpointer)this);
#if HIRO_GTK==2
g_signal_connect(G_OBJECT(gtkWidget), "expose-event", G_CALLBACK(Canvas_expose), (gpointer)this); g_signal_connect(G_OBJECT(gtkWidget), "expose-event", G_CALLBACK(Canvas_expose), (gpointer)this);
#elif HIRO_GTK==3
g_signal_connect(G_OBJECT(gtkWidget), "draw", G_CALLBACK(Canvas_draw), (gpointer)this);
#endif
g_signal_connect(G_OBJECT(gtkWidget), "leave-notify-event", G_CALLBACK(Canvas_mouseLeave), (gpointer)this); g_signal_connect(G_OBJECT(gtkWidget), "leave-notify-event", G_CALLBACK(Canvas_mouseLeave), (gpointer)this);
g_signal_connect(G_OBJECT(gtkWidget), "motion-notify-event", G_CALLBACK(Canvas_mouseMove), (gpointer)this); g_signal_connect(G_OBJECT(gtkWidget), "motion-notify-event", G_CALLBACK(Canvas_mouseMove), (gpointer)this);
@ -106,7 +115,36 @@ auto pCanvas::update() -> void {
_redraw(); _redraw();
} }
auto pCanvas::_onDraw(cairo_t* context) -> void {
#if HIRO_GTK==3
int sx = 0, sy = 0, dx = 0, dy = 0;
int width = surfaceWidth, height = surfaceHeight;
auto geometry = pSizable::state().geometry;
if(width <= geometry.width()) {
sx = 0;
dx = (geometry.width() - width) / 2;
} else {
sx = (width - geometry.width()) / 2;
dx = 0;
}
if(height <= geometry.height()) {
sy = 0;
dy = (geometry.height() - height) / 2;
} else {
sy = (height - geometry.height()) / 2;
dy = 0;
}
//TODO: support non-zero sx,sy
gdk_cairo_set_source_pixbuf(context, surface, dx, dy);
cairo_paint(context);
#endif
}
auto pCanvas::_onExpose(GdkEventExpose* expose) -> void { auto pCanvas::_onExpose(GdkEventExpose* expose) -> void {
#if HIRO_GTK==2
if(surface == nullptr) return; if(surface == nullptr) return;
int sx = 0, sy = 0, dx = 0, dy = 0; int sx = 0, sy = 0, dx = 0, dy = 0;
@ -132,10 +170,7 @@ auto pCanvas::_onExpose(GdkEventExpose* expose) -> void {
height = geometry.height(); height = geometry.height();
} }
#if HIRO_GTK==2
gdk_draw_pixbuf(gtk_widget_get_window(gtkWidget), nullptr, surface, sx, sy, dx, dy, width, height, GDK_RGB_DITHER_NONE, 0, 0); gdk_draw_pixbuf(gtk_widget_get_window(gtkWidget), nullptr, surface, sx, sy, dx, dy, width, height, GDK_RGB_DITHER_NONE, 0, 0);
#elif HIRO_GTK==3
//TODO: use cairo here, but how? no examples show to use sx, sy
#endif #endif
} }

View File

@ -13,6 +13,7 @@ struct pCanvas : pWidget {
auto setIcon(const image& icon) -> void; auto setIcon(const image& icon) -> void;
auto update() -> void; auto update() -> void;
auto _onDraw(cairo_t* context) -> void;
auto _onExpose(GdkEventExpose* event) -> void; auto _onExpose(GdkEventExpose* event) -> void;
auto _rasterize() -> void; auto _rasterize() -> void;
auto _redraw() -> void; auto _redraw() -> void;

View File

@ -10,6 +10,10 @@ GtkSelectionData* data, unsigned type, unsigned timestamp, pViewport* p) -> void
p->self().doDrop(paths); p->self().doDrop(paths);
} }
static auto Viewport_draw(GtkWidget* widget, cairo_t* context, pViewport* p) -> signed {
return true;
}
static auto Viewport_expose(GtkWidget* widget, GdkEventExpose* event) -> signed { static auto Viewport_expose(GtkWidget* widget, GdkEventExpose* event) -> signed {
return true; return true;
} }
@ -59,7 +63,11 @@ auto pViewport::construct() -> void {
g_signal_connect(G_OBJECT(gtkWidget), "button-press-event", G_CALLBACK(Viewport_mousePress), (gpointer)this); g_signal_connect(G_OBJECT(gtkWidget), "button-press-event", G_CALLBACK(Viewport_mousePress), (gpointer)this);
g_signal_connect(G_OBJECT(gtkWidget), "button-release-event", G_CALLBACK(Viewport_mouseRelease), (gpointer)this); g_signal_connect(G_OBJECT(gtkWidget), "button-release-event", G_CALLBACK(Viewport_mouseRelease), (gpointer)this);
g_signal_connect(G_OBJECT(gtkWidget), "drag-data-received", G_CALLBACK(Viewport_dropEvent), (gpointer)this); g_signal_connect(G_OBJECT(gtkWidget), "drag-data-received", G_CALLBACK(Viewport_dropEvent), (gpointer)this);
#if HIRO_GTK==2
g_signal_connect(G_OBJECT(gtkWidget), "expose-event", G_CALLBACK(Viewport_expose), (gpointer)this); g_signal_connect(G_OBJECT(gtkWidget), "expose-event", G_CALLBACK(Viewport_expose), (gpointer)this);
#elif HIRO_GTK==3
g_signal_connect(G_OBJECT(gtkWidget), "draw", G_CALLBACK(Viewport_draw), (gpointer)this);
#endif
g_signal_connect(G_OBJECT(gtkWidget), "leave-notify-event", G_CALLBACK(Viewport_mouseLeave), (gpointer)this); g_signal_connect(G_OBJECT(gtkWidget), "leave-notify-event", G_CALLBACK(Viewport_mouseLeave), (gpointer)this);
g_signal_connect(G_OBJECT(gtkWidget), "motion-notify-event", G_CALLBACK(Viewport_mouseMove), (gpointer)this); g_signal_connect(G_OBJECT(gtkWidget), "motion-notify-event", G_CALLBACK(Viewport_mouseMove), (gpointer)this);

View File

@ -30,7 +30,6 @@ static auto Window_draw(GtkWidget* widget, cairo_t* context, pWindow* p) -> sign
cairo_set_operator(context, CAIRO_OPERATOR_SOURCE); cairo_set_operator(context, CAIRO_OPERATOR_SOURCE);
cairo_paint(context); cairo_paint(context);
cairo_destroy(context);
} }
return false; return false;
} }
@ -39,7 +38,8 @@ static auto Window_draw(GtkWidget* widget, cairo_t* context, pWindow* p) -> sign
static auto Window_expose(GtkWidget* widget, GdkEvent* event, pWindow* p) -> signed { static auto Window_expose(GtkWidget* widget, GdkEvent* event, pWindow* p) -> signed {
if(auto color = p->state().backgroundColor) { if(auto color = p->state().backgroundColor) {
cairo_t* context = gdk_cairo_create(gtk_widget_get_window(widget)); cairo_t* context = gdk_cairo_create(gtk_widget_get_window(widget));
return Window_draw(widget, context, p); Window_draw(widget, context, p);
cairo_destroy(context);
} }
return false; return false;
} }

View File

@ -33,9 +33,16 @@ struct Video {
virtual auto lock(uint32_t*& data, uint& pitch, uint width, uint height) -> bool { return false; } virtual auto lock(uint32_t*& data, uint& pitch, uint width, uint height) -> bool { return false; }
virtual auto unlock() -> void {} virtual auto unlock() -> void {}
virtual auto output() -> void {} virtual auto output() -> void {}
virtual auto poll() -> void {}
auto onUpdate(const nall::function<void (uint, uint)>& callback) { _onUpdate = callback; }
auto doUpdate(uint width, uint height) -> void {
if(_onUpdate) return _onUpdate(width, height);
}
private: private:
nall::string _driver; nall::string _driver;
nall::function<void (uint, uint)> _onUpdate;
}; };
struct Audio { struct Audio {
@ -100,7 +107,7 @@ struct Input {
auto onChange(const nall::function<void (nall::shared_pointer<nall::HID::Device>, uint, uint, int16_t, int16_t)>& callback) { _onChange = callback; } auto onChange(const nall::function<void (nall::shared_pointer<nall::HID::Device>, uint, uint, int16_t, int16_t)>& callback) { _onChange = callback; }
auto doChange(nall::shared_pointer<nall::HID::Device> device, uint group, uint input, int16_t oldValue, int16_t newValue) -> void { auto doChange(nall::shared_pointer<nall::HID::Device> device, uint group, uint input, int16_t oldValue, int16_t newValue) -> void {
if(_onChange) _onChange(device, group, input, oldValue, newValue); if(_onChange) return _onChange(device, group, input, oldValue, newValue);
} }
private: private:

View File

@ -91,6 +91,18 @@ struct VideoGLX : Video, OpenGL {
if(_doubleBuffer) glXSwapBuffers(_display, _glXWindow); if(_doubleBuffer) glXSwapBuffers(_display, _glXWindow);
} }
auto poll() -> void {
while(XPending(_display)) {
XEvent event;
XNextEvent(_display, &event);
if(event.type == Expose) {
XWindowAttributes attributes;
XGetWindowAttributes(_display, _window, &attributes);
doUpdate(attributes.width, attributes.height);
}
}
}
private: private:
auto initialize() -> bool { auto initialize() -> bool {
terminate(); terminate();
@ -136,6 +148,7 @@ private:
/* x = */ 0, /* y = */ 0, windowAttributes.width, windowAttributes.height, /* x = */ 0, /* y = */ 0, windowAttributes.width, windowAttributes.height,
/* border_width = */ 0, vi->depth, InputOutput, vi->visual, /* border_width = */ 0, vi->depth, InputOutput, vi->visual,
CWColormap | CWBorderPixel, &attributes); CWColormap | CWBorderPixel, &attributes);
XSelectInput(_display, _window, ExposureMask);
XSetWindowBackground(_display, _window, /* color = */ 0); XSetWindowBackground(_display, _window, /* color = */ 0);
XMapWindow(_display, _window); XMapWindow(_display, _window);
XFlush(_display); XFlush(_display);

View File

@ -111,6 +111,18 @@ struct VideoGLX2 : Video {
if(_isDoubleBuffered) glXSwapBuffers(_display, _glXWindow); if(_isDoubleBuffered) glXSwapBuffers(_display, _glXWindow);
} }
auto poll() -> void {
while(XPending(_display)) {
XEvent event;
XNextEvent(_display, &event);
if(event.type == Expose) {
XWindowAttributes attributes;
XGetWindowAttributes(_display, _window, &attributes);
doUpdate(attributes.width, attributes.height);
}
}
}
private: private:
auto initialize() -> bool { auto initialize() -> bool {
terminate(); terminate();
@ -147,6 +159,7 @@ private:
attributes.border_pixel = 0; attributes.border_pixel = 0;
_window = XCreateWindow(_display, (Window)_context, 0, 0, windowAttributes.width, windowAttributes.height, _window = XCreateWindow(_display, (Window)_context, 0, 0, windowAttributes.width, windowAttributes.height,
0, vi->depth, InputOutput, vi->visual, CWColormap | CWBorderPixel, &attributes); 0, vi->depth, InputOutput, vi->visual, CWColormap | CWBorderPixel, &attributes);
XSelectInput(_display, _window, ExposureMask);
XSetWindowBackground(_display, _window, 0); XSetWindowBackground(_display, _window, 0);
XMapWindow(_display, _window); XMapWindow(_display, _window);
XFlush(_display); XFlush(_display);

View File

@ -88,12 +88,24 @@ struct VideoXShm : Video {
XFlush(_display); XFlush(_display);
} }
auto poll() -> void override {
while(XPending(_display)) {
XEvent event;
XNextEvent(_display, &event);
if(event.type == Expose) {
XWindowAttributes attributes;
XGetWindowAttributes(_display, _window, &attributes);
doUpdate(attributes.width, attributes.height);
}
}
}
private: private:
auto initialize() -> bool { auto initialize() -> bool {
terminate(); terminate();
if(!_context) return false; if(!_context) return false;
_display = XOpenDisplay(0); _display = XOpenDisplay(nullptr);
_screen = DefaultScreen(_display); _screen = DefaultScreen(_display);
XWindowAttributes getAttributes; XWindowAttributes getAttributes;
@ -109,12 +121,12 @@ private:
XSetWindowAttributes setAttributes = {}; XSetWindowAttributes setAttributes = {};
setAttributes.border_pixel = 0; setAttributes.border_pixel = 0;
setAttributes.event_mask = ExposureMask;
_window = XCreateWindow(_display, (Window)_context, _window = XCreateWindow(_display, (Window)_context,
0, 0, 256, 256, 0, 0, 0, 256, 256, 0,
getAttributes.depth, InputOutput, getAttributes.visual, getAttributes.depth, InputOutput, getAttributes.visual,
CWBorderPixel, &setAttributes CWBorderPixel, &setAttributes
); );
XSelectInput(_display, _window, ExposureMask);
XSetWindowBackground(_display, _window, 0); XSetWindowBackground(_display, _window, 0);
XMapWindow(_display, _window); XMapWindow(_display, _window);
XFlush(_display); XFlush(_display);

View File

@ -91,6 +91,18 @@ struct VideoXVideo : Video {
true); true);
} }
auto poll() -> void {
while(XPending(_display)) {
XEvent event;
XNextEvent(_display, &event);
if(event.type == Expose) {
XWindowAttributes attributes;
XGetWindowAttributes(_display, _window, &attributes);
doUpdate(attributes.width, attributes.height);
}
}
}
private: private:
auto initialize() -> bool { auto initialize() -> bool {
terminate(); terminate();
@ -148,11 +160,11 @@ private:
XSetWindowAttributes attributes; XSetWindowAttributes attributes;
attributes.colormap = _colormap; attributes.colormap = _colormap;
attributes.border_pixel = 0; attributes.border_pixel = 0;
attributes.event_mask = StructureNotifyMask;
_window = XCreateWindow(_display, /* parent = */ (Window)_context, _window = XCreateWindow(_display, /* parent = */ (Window)_context,
/* x = */ 0, /* y = */ 0, window_attributes.width, window_attributes.height, /* x = */ 0, /* y = */ 0, window_attributes.width, window_attributes.height,
/* border_width = */ 0, _depth, InputOutput, visualInfo->visual, /* border_width = */ 0, _depth, InputOutput, visualInfo->visual,
CWColormap | CWBorderPixel | CWEventMask, &attributes); CWColormap | CWBorderPixel | CWEventMask, &attributes);
XSelectInput(_display, _window, ExposureMask);
XFree(visualInfo); XFree(visualInfo);
XSetWindowBackground(_display, _window, /* color = */ 0); XSetWindowBackground(_display, _window, /* color = */ 0);
XMapWindow(_display, _window); XMapWindow(_display, _window);