Update to v094r09 release.

byuu says:

This will easily be the biggest diff in the history of higan. And not in
a good way.

* target-higan and target-loki have been blown away completely
* nall and ruby massively updated
* phoenix replaced with hiro (pretty near a total rewrite)
* target-higan restarted using hiro (just a window for now)
* all emulation cores updated to compile again
* installation changed to not require root privileges (installs locally)

For the foreseeable future (maybe even permanently?), the new higan UI
will only build under Linux/BSD with GTK+ 2.20+. Probably the most
likely route for Windows/OS X will be to try and figure out how to build
hiro/GTK on those platforms, as awful as that would be. The other
alternative would be to produce new UIs for those platforms ... which
would actually be a good opportunity to make something much more user
friendly.

Being that I just started on this a few hours ago, that means that for
at least a few weeks, don't expect to be able to actually play any
games. Right now, you can pretty much just compile the binary and that's
it. It's quite possible that some nall changes didn't produce
compilation errors, but will produce runtime errors. So until the UI can
actually load games, we won't know if anything is broken. But we should
mostly be okay. It was mostly just trim<1> -> trim changes, moving to
Hash::SHA256 (much cleaner), and patching some reckless memory copy
functions enough to compile.

Progress isn't going to be like it was before: I'm now dividing my time
much thinner between studying and other hobbies.

My aim this time is not to produce a binary for everyone to play games
on. Rather, it's to keep the emulator alive. I want to be able to apply
critical patches again. And I would also like the base of the emulator
to live on, for use in other emulator frontends that utilize higan.
This commit is contained in:
Tim Allen
2015-02-26 21:10:46 +11:00
parent 1a7bc6bb87
commit a512d14628
793 changed files with 20182 additions and 19416 deletions

358
hiro/windows/utility.cpp Normal file
View File

@@ -0,0 +1,358 @@
namespace phoenix {
static const unsigned Windows2000 = 0x0500;
static const unsigned WindowsXP = 0x0501;
static const unsigned WindowsVista = 0x0600;
static const unsigned Windows7 = 0x0601;
static unsigned OsVersion() {
OSVERSIONINFO versionInfo = {0};
versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&versionInfo);
return (versionInfo.dwMajorVersion << 8) + (versionInfo.dwMajorVersion << 0);
}
static HBITMAP CreateBitmap(const image& image) {
HDC hdc = GetDC(0);
BITMAPINFO bitmapInfo;
memset(&bitmapInfo, 0, sizeof(BITMAPINFO));
bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bitmapInfo.bmiHeader.biWidth = image.width;
bitmapInfo.bmiHeader.biHeight = -image.height; //bitmaps are stored upside down unless we negate height
bitmapInfo.bmiHeader.biPlanes = 1;
bitmapInfo.bmiHeader.biBitCount = 32;
bitmapInfo.bmiHeader.biCompression = BI_RGB;
bitmapInfo.bmiHeader.biSizeImage = image.width * image.height * 4;
void* bits = nullptr;
HBITMAP hbitmap = CreateDIBSection(hdc, &bitmapInfo, DIB_RGB_COLORS, &bits, NULL, 0);
if(bits) memcpy(bits, image.data, image.width * image.height * 4);
ReleaseDC(0, hdc);
return hbitmap;
}
static lstring DropPaths(WPARAM wparam) {
auto dropList = HDROP(wparam);
auto fileCount = DragQueryFile(dropList, ~0u, nullptr, 0);
lstring paths;
for(unsigned n = 0; n < fileCount; n++) {
auto length = DragQueryFile(dropList, n, nullptr, 0);
auto buffer = new wchar_t[length + 1];
if(DragQueryFile(dropList, n, buffer, length + 1)) {
string path = (const char*)utf8_t(buffer);
path.transform("\\", "/");
if(directory::exists(path) && !path.endsWith("/")) path.append("/");
paths.append(path);
}
delete[] buffer;
}
return paths;
}
static Layout* GetParentWidgetLayout(Sizable* sizable) {
while(sizable) {
if(sizable->state.parent && dynamic_cast<TabFrame*>(sizable->state.parent)) return (Layout*)sizable;
sizable = sizable->state.parent;
}
return nullptr;
}
static Widget* GetParentWidget(Sizable* sizable) {
while(sizable) {
if(sizable->state.parent && dynamic_cast<TabFrame*>(sizable->state.parent)) return (Widget*)sizable->state.parent;
sizable = sizable->state.parent;
}
return nullptr;
}
static unsigned GetWindowZOrder(HWND hwnd) {
unsigned z = 0;
for(HWND next = hwnd; next != NULL; next = GetWindow(next, GW_HWNDPREV)) z++;
return z;
}
static void ImageList_Append(HIMAGELIST imageList, const nall::image& source, unsigned scale) {
auto image = source;
if(image.empty()) {
image.allocate(scale, scale);
image.fill(GetSysColor(COLOR_WINDOW));
}
image.transform(0, 32, 255u << 24, 255u << 16, 255u << 8, 255u << 0);
image.scale(scale, scale);
HBITMAP bitmap = CreateBitmap(image);
ImageList_Add(imageList, bitmap, NULL);
DeleteObject(bitmap);
}
static Keyboard::Keycode Keysym(unsigned keysym, unsigned keyflags) {
#define pressed(keysym) (GetAsyncKeyState(keysym) & 0x8000)
#define enabled(keysym) (GetKeyState(keysym))
#define shifted() (pressed(VK_LSHIFT) || pressed(VK_RSHIFT))
#define extended() (keyflags & (1 << 24))
switch(keysym) {
case VK_ESCAPE: return Keyboard::Keycode::Escape;
case VK_F1: return Keyboard::Keycode::F1;
case VK_F2: return Keyboard::Keycode::F2;
case VK_F3: return Keyboard::Keycode::F3;
case VK_F4: return Keyboard::Keycode::F4;
case VK_F5: return Keyboard::Keycode::F5;
case VK_F6: return Keyboard::Keycode::F6;
case VK_F7: return Keyboard::Keycode::F7;
case VK_F8: return Keyboard::Keycode::F8;
case VK_F9: return Keyboard::Keycode::F9;
//Keyboard::Keycode::F10 (should be captured under VK_MENU from WM_SYSKEY(UP,DOWN); but this is not working...)
case VK_F11: return Keyboard::Keycode::F11;
case VK_F12: return Keyboard::Keycode::F12;
//Keyboard::Keycode::PrintScreen
//Keyboard::Keycode::SysRq
case VK_SCROLL: return Keyboard::Keycode::ScrollLock;
case VK_PAUSE: return Keyboard::Keycode::Pause;
//Keyboard::Keycode::Break
case VK_INSERT: return extended() ? Keyboard::Keycode::Insert : Keyboard::Keycode::KeypadInsert;
case VK_DELETE: return extended() ? Keyboard::Keycode::Delete : Keyboard::Keycode::KeypadDelete;
case VK_HOME: return extended() ? Keyboard::Keycode::Home : Keyboard::Keycode::KeypadHome;
case VK_END: return extended() ? Keyboard::Keycode::End : Keyboard::Keycode::KeypadEnd;
case VK_PRIOR: return extended() ? Keyboard::Keycode::PageUp : Keyboard::Keycode::KeypadPageUp;
case VK_NEXT: return extended() ? Keyboard::Keycode::PageDown : Keyboard::Keycode::KeypadPageDown;
case VK_UP: return extended() ? Keyboard::Keycode::Up : Keyboard::Keycode::KeypadUp;
case VK_DOWN: return extended() ? Keyboard::Keycode::Down : Keyboard::Keycode::KeypadDown;
case VK_LEFT: return extended() ? Keyboard::Keycode::Left : Keyboard::Keycode::KeypadLeft;
case VK_RIGHT: return extended() ? Keyboard::Keycode::Right : Keyboard::Keycode::KeypadRight;
case VK_OEM_3: return !shifted() ? Keyboard::Keycode::Grave : Keyboard::Keycode::Tilde;
case '1': return !shifted() ? Keyboard::Keycode::Number1 : Keyboard::Keycode::Exclamation;
case '2': return !shifted() ? Keyboard::Keycode::Number2 : Keyboard::Keycode::At;
case '3': return !shifted() ? Keyboard::Keycode::Number3 : Keyboard::Keycode::Pound;
case '4': return !shifted() ? Keyboard::Keycode::Number4 : Keyboard::Keycode::Dollar;
case '5': return !shifted() ? Keyboard::Keycode::Number5 : Keyboard::Keycode::Percent;
case '6': return !shifted() ? Keyboard::Keycode::Number6 : Keyboard::Keycode::Power;
case '7': return !shifted() ? Keyboard::Keycode::Number7 : Keyboard::Keycode::Ampersand;
case '8': return !shifted() ? Keyboard::Keycode::Number8 : Keyboard::Keycode::Asterisk;
case '9': return !shifted() ? Keyboard::Keycode::Number9 : Keyboard::Keycode::ParenthesisLeft;
case '0': return !shifted() ? Keyboard::Keycode::Number0 : Keyboard::Keycode::ParenthesisRight;
case VK_OEM_MINUS: return !shifted() ? Keyboard::Keycode::Minus : Keyboard::Keycode::Underscore;
case VK_OEM_PLUS: return !shifted() ? Keyboard::Keycode::Equal : Keyboard::Keycode::Plus;
case VK_BACK: return Keyboard::Keycode::Backspace;
case VK_OEM_4: return !shifted() ? Keyboard::Keycode::BracketLeft : Keyboard::Keycode::BraceLeft;
case VK_OEM_6: return !shifted() ? Keyboard::Keycode::BracketRight : Keyboard::Keycode::BraceRight;
case VK_OEM_5: return !shifted() ? Keyboard::Keycode::Backslash : Keyboard::Keycode::Pipe;
case VK_OEM_1: return !shifted() ? Keyboard::Keycode::Semicolon : Keyboard::Keycode::Colon;
case VK_OEM_7: return !shifted() ? Keyboard::Keycode::Apostrophe : Keyboard::Keycode::Quote;
case VK_OEM_COMMA: return !shifted() ? Keyboard::Keycode::Comma : Keyboard::Keycode::CaretLeft;
case VK_OEM_PERIOD: return !shifted() ? Keyboard::Keycode::Period : Keyboard::Keycode::CaretRight;
case VK_OEM_2: return !shifted() ? Keyboard::Keycode::Slash : Keyboard::Keycode::Question;
case VK_TAB: return Keyboard::Keycode::Tab;
case VK_CAPITAL: return Keyboard::Keycode::CapsLock;
case VK_RETURN: return !extended() ? Keyboard::Keycode::Return : Keyboard::Keycode::Enter;
case VK_SHIFT: return !pressed(VK_RSHIFT) ? Keyboard::Keycode::ShiftLeft : Keyboard::Keycode::ShiftRight;
case VK_CONTROL: return !pressed(VK_RCONTROL) ? Keyboard::Keycode::ControlLeft : Keyboard::Keycode::ControlRight;
case VK_LWIN: return Keyboard::Keycode::SuperLeft;
case VK_RWIN: return Keyboard::Keycode::SuperRight;
case VK_MENU:
if(keyflags & (1 << 24)) return Keyboard::Keycode::AltRight;
return Keyboard::Keycode::AltLeft;
case VK_SPACE: return Keyboard::Keycode::Space;
case VK_APPS: return Keyboard::Keycode::Menu;
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M':
case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z':
if(enabled(VK_CAPITAL)) {
if(shifted()) {
return (Keyboard::Keycode)((unsigned)Keyboard::Keycode::a + keysym - 'A');
} else {
return (Keyboard::Keycode)((unsigned)Keyboard::Keycode::A + keysym - 'A');
}
} else {
if(shifted()) {
return (Keyboard::Keycode)((unsigned)Keyboard::Keycode::A + keysym - 'A');
} else {
return (Keyboard::Keycode)((unsigned)Keyboard::Keycode::a + keysym - 'A');
}
}
break;
case VK_NUMLOCK: return Keyboard::Keycode::NumLock;
case VK_DIVIDE: return Keyboard::Keycode::Divide;
case VK_MULTIPLY: return Keyboard::Keycode::Multiply;
case VK_SUBTRACT: return Keyboard::Keycode::Subtract;
case VK_ADD: return Keyboard::Keycode::Add;
case VK_DECIMAL: return Keyboard::Keycode::Point;
case VK_NUMPAD1: return Keyboard::Keycode::Keypad1;
case VK_NUMPAD2: return Keyboard::Keycode::Keypad2;
case VK_NUMPAD3: return Keyboard::Keycode::Keypad3;
case VK_NUMPAD4: return Keyboard::Keycode::Keypad4;
case VK_NUMPAD5: return Keyboard::Keycode::Keypad5;
case VK_NUMPAD6: return Keyboard::Keycode::Keypad6;
case VK_NUMPAD7: return Keyboard::Keycode::Keypad7;
case VK_NUMPAD8: return Keyboard::Keycode::Keypad8;
case VK_NUMPAD9: return Keyboard::Keycode::Keypad9;
case VK_NUMPAD0: return Keyboard::Keycode::Keypad0;
case VK_CLEAR: return Keyboard::Keycode::KeypadCenter;
}
return Keyboard::Keycode::None;
#undef pressed
#undef enabled
#undef shifted
#undef extended
}
static unsigned ScrollEvent(HWND hwnd, WPARAM wparam) {
SCROLLINFO info;
memset(&info, 0, sizeof(SCROLLINFO));
info.cbSize = sizeof(SCROLLINFO);
info.fMask = SIF_ALL;
GetScrollInfo(hwnd, SB_CTL, &info);
switch(LOWORD(wparam)) {
case SB_LEFT: info.nPos = info.nMin; break;
case SB_RIGHT: info.nPos = info.nMax; break;
case SB_LINELEFT: info.nPos--; break;
case SB_LINERIGHT: info.nPos++; break;
case SB_PAGELEFT: info.nPos -= info.nMax >> 3; break;
case SB_PAGERIGHT: info.nPos += info.nMax >> 3; break;
case SB_THUMBTRACK: info.nPos = info.nTrackPos; break;
}
info.fMask = SIF_POS;
SetScrollInfo(hwnd, SB_CTL, &info, TRUE);
//Windows may clamp position to scroller range
GetScrollInfo(hwnd, SB_CTL, &info);
return info.nPos;
}
static LRESULT CALLBACK Shared_windowProc(WindowProc windowProc, HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
Object* object = (Object*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
if(object == nullptr) return DefWindowProc(hwnd, msg, wparam, lparam);
Window& window = dynamic_cast<Window*>(object) ? *(Window*)object : *((Widget*)object)->Sizable::state.window;
bool process = true;
if(!pWindow::modal.empty() && !pWindow::modal.find(&window.p)) process = false;
if(applicationState.quit) process = false;
if(process == false) return DefWindowProc(hwnd, msg, wparam, lparam);
switch(msg) {
case WM_CTLCOLORBTN:
case WM_CTLCOLOREDIT:
case WM_CTLCOLORSTATIC: {
Object* object = (Object*)GetWindowLongPtr((HWND)lparam, GWLP_USERDATA);
if(object == nullptr) break;
//allow custom colors for various widgets
//note that this happens always: default colors are black text on a white background, unless overridden
//this intentionally overrides the default behavior of Windows to paint disabled controls with the window background color
if(dynamic_cast<Console*>(object)) {
Console& console = *(Console*)object;
Color& background = console.state.backgroundColor;
Color& foreground = console.state.foregroundColor;
SetTextColor((HDC)wparam, RGB(foreground.red, foreground.green, foreground.blue));
SetBkColor((HDC)wparam, RGB(background.red, background.green, background.blue));
return (LRESULT)console.p.backgroundBrush;
} else if(dynamic_cast<HexEdit*>(object)) {
HexEdit& hexEdit = *(HexEdit*)object;
Color& background = hexEdit.state.backgroundColor;
Color& foreground = hexEdit.state.foregroundColor;
SetTextColor((HDC)wparam, RGB(foreground.red, foreground.green, foreground.blue));
SetBkColor((HDC)wparam, RGB(background.red, background.green, background.blue));
return (LRESULT)hexEdit.p.backgroundBrush;
} else if(dynamic_cast<LineEdit*>(object)) {
LineEdit& lineEdit = *(LineEdit*)object;
Color& background = lineEdit.state.backgroundColor;
Color& foreground = lineEdit.state.foregroundColor;
SetTextColor((HDC)wparam, RGB(foreground.red, foreground.green, foreground.blue));
SetBkColor((HDC)wparam, RGB(background.red, background.green, background.blue));
return (LRESULT)lineEdit.p.backgroundBrush;
} else if(dynamic_cast<TextEdit*>(object)) {
TextEdit& textEdit = *(TextEdit*)object;
Color& background = textEdit.state.backgroundColor;
Color& foreground = textEdit.state.foregroundColor;
SetTextColor((HDC)wparam, RGB(foreground.red, foreground.green, foreground.blue));
SetBkColor((HDC)wparam, RGB(background.red, background.green, background.blue));
return (LRESULT)textEdit.p.backgroundBrush;
} else if(!GetParentWidget((Sizable*)object) && window.p.brush) {
SetBkColor((HDC)wparam, window.p.brushColor);
return (INT_PTR)window.p.brush;
}
break;
}
case WM_DRAWITEM: {
unsigned id = LOWORD(wparam);
HWND control = GetDlgItem(hwnd, id);
Object* object = (Object*)GetWindowLongPtr(control, GWLP_USERDATA);
if(object == nullptr) break;
if(dynamic_cast<TabFrame*>(object)) { ((TabFrame*)object)->p.onDrawItem(lparam); return TRUE; }
break;
}
case WM_COMMAND: {
unsigned id = LOWORD(wparam);
HWND control = GetDlgItem(hwnd, id);
Object* object = control ? (Object*)GetWindowLongPtr(control, GWLP_USERDATA) : pObject::find(id);
if(object == nullptr) break;
if(dynamic_cast<Item*>(object)) { ((Item*)object)->p.onActivate(); return FALSE; }
if(dynamic_cast<CheckItem*>(object)) { ((CheckItem*)object)->p.onToggle(); return FALSE; }
if(dynamic_cast<RadioItem*>(object)) { ((RadioItem*)object)->p.onActivate(); return FALSE; }
if(dynamic_cast<Button*>(object)) { ((Button*)object)->p.onActivate(); return FALSE; }
if(dynamic_cast<CheckButton*>(object)) { ((CheckButton*)object)->p.onToggle(); return FALSE; }
if(dynamic_cast<CheckLabel*>(object)) { ((CheckLabel*)object)->p.onToggle(); return FALSE; }
if(dynamic_cast<ComboButton*>(object) && HIWORD(wparam) == CBN_SELCHANGE) { ((ComboButton*)object)->p.onChange(); return FALSE; }
if(dynamic_cast<LineEdit*>(object) && HIWORD(wparam) == EN_CHANGE) { ((LineEdit*)object)->p.onChange(); return FALSE; }
if(dynamic_cast<RadioButton*>(object)) { ((RadioButton*)object)->p.onActivate(); return FALSE; }
if(dynamic_cast<RadioLabel*>(object)) { ((RadioLabel*)object)->p.onActivate(); return FALSE; }
if(dynamic_cast<TextEdit*>(object) && HIWORD(wparam) == EN_CHANGE) { ((TextEdit*)object)->p.onChange(); return FALSE; }
break;
}
case WM_NOTIFY: {
unsigned id = LOWORD(wparam);
HWND control = GetDlgItem(hwnd, id);
Object* object = (Object*)GetWindowLongPtr(control, GWLP_USERDATA);
if(object == nullptr) break;
if(dynamic_cast<ListView*>(object) && ((LPNMHDR)lparam)->code == LVN_ITEMACTIVATE) { ((ListView*)object)->p.onActivate(lparam); break; }
if(dynamic_cast<ListView*>(object) && ((LPNMHDR)lparam)->code == LVN_ITEMCHANGED) { ((ListView*)object)->p.onChange(lparam); break; }
if(dynamic_cast<ListView*>(object) && ((LPNMHDR)lparam)->code == NM_CUSTOMDRAW) { return ((ListView*)object)->p.onCustomDraw(lparam); }
if(dynamic_cast<TabFrame*>(object) && ((LPNMHDR)lparam)->code == TCN_SELCHANGE) { ((TabFrame*)object)->p.onChange(); break; }
break;
}
case WM_APP + AppMessage::ListView_onActivate: {
ListView* listView = (ListView*)lparam;
if(listView && listView->onActivate) listView->onActivate();
break;
}
case WM_HSCROLL:
case WM_VSCROLL: {
Object* object = nullptr;
if(lparam) {
object = (Object*)GetWindowLongPtr((HWND)lparam, GWLP_USERDATA);
} else {
unsigned id = LOWORD(wparam);
HWND control = GetDlgItem(hwnd, id);
object = (Object*)GetWindowLongPtr(control, GWLP_USERDATA);
}
if(object == nullptr) break;
if(dynamic_cast<HorizontalScroller*>(object)) { ((HorizontalScroller*)object)->p.onChange(wparam); return TRUE; }
if(dynamic_cast<VerticalScroller*>(object)) { ((VerticalScroller*)object)->p.onChange(wparam); return TRUE; }
if(dynamic_cast<HorizontalSlider*>(object)) { ((HorizontalSlider*)object)->p.onChange(); return TRUE; }
if(dynamic_cast<VerticalSlider*>(object)) { ((VerticalSlider*)object)->p.onChange(); return TRUE; }
break;
}
}
return windowProc(hwnd, msg, wparam, lparam);
}
}