diff --git a/src/alloy/runtime/debugger.h b/src/alloy/runtime/debugger.h index ce87efd30..c61381bfe 100644 --- a/src/alloy/runtime/debugger.h +++ b/src/alloy/runtime/debugger.h @@ -52,7 +52,7 @@ private: class DebugEvent { public: DebugEvent(Debugger* debugger) : - debugger_(debugger) {} + debugger_(debugger) {} virtual ~DebugEvent() {} Debugger* debugger() const { return debugger_; } protected: diff --git a/src/xenia/core.h b/src/xenia/core.h index 49ce110d5..5b0d57046 100644 --- a/src/xenia/core.h +++ b/src/xenia/core.h @@ -27,10 +27,5 @@ namespace xe { #include #include #include -#include - -#if XE_PLATFORM_WIN32 -#include -#endif // WIN32 #endif // XENIA_CORE_H_ diff --git a/src/xenia/core/run_loop_win.cc b/src/xenia/core/run_loop_win.cc index bd00b3674..a2f9efaba 100644 --- a/src/xenia/core/run_loop_win.cc +++ b/src/xenia/core/run_loop_win.cc @@ -59,7 +59,7 @@ int xe_run_loop_pump(xe_run_loop_ref run_loop) { } break; case WM_XE_RUN_LOOP_QUIT: - if (msg.lParam == (WPARAM)run_loop) { + if (msg.wParam == (WPARAM)run_loop) { // Done! return 1; } @@ -70,7 +70,7 @@ int xe_run_loop_pump(xe_run_loop_ref run_loop) { } void xe_run_loop_quit(xe_run_loop_ref run_loop) { - PostMessage(NULL, WM_XE_RUN_LOOP_QUIT, 0, (WPARAM)run_loop); + PostMessage(NULL, WM_XE_RUN_LOOP_QUIT, (WPARAM)run_loop, 0); } void xe_run_loop_call(xe_run_loop_ref run_loop, diff --git a/src/xenia/core/sources.gypi b/src/xenia/core/sources.gypi index b7248305b..c4822b89b 100644 --- a/src/xenia/core/sources.gypi +++ b/src/xenia/core/sources.gypi @@ -18,8 +18,6 @@ 'socket.h', 'thread.cc', 'thread.h', - 'window.cc', - 'window.h', ], 'conditions': [ @@ -49,8 +47,6 @@ 'path_win.cc', 'run_loop_win.cc', 'socket_win.cc', - 'win32_window.cc', - 'win32_window.h', ], }], ], diff --git a/src/xenia/core/window.h b/src/xenia/core/window.h deleted file mode 100644 index 535f2d82b..000000000 --- a/src/xenia/core/window.h +++ /dev/null @@ -1,51 +0,0 @@ -/** - ****************************************************************************** - * Xenia : Xbox 360 Emulator Research Project * - ****************************************************************************** - * Copyright 2013 Ben Vanik. All rights reserved. * - * Released under the BSD license - see LICENSE in the root for more details. * - ****************************************************************************** - */ - -#ifndef XENIA_CORE_WINDOW_H_ -#define XENIA_CORE_WINDOW_H_ - -#include -#include -#include -#include - - -namespace xe { -namespace core { - - -class Window { -public: - Window(xe_run_loop_ref run_loop); - virtual ~Window(); - - virtual void set_title(const xechar_t* title) = 0; - - uint32_t width() const { return width_; } - uint32_t height() const { return height_; } - virtual void Resize(uint32_t width, uint32_t height) = 0; - - virtual void ShowError(const xechar_t* message) = 0; - -protected: - virtual void OnResize(uint32_t width, uint32_t height) {} - virtual void OnClose() {} - - xe_run_loop_ref run_loop_; - - uint32_t width_; - uint32_t height_; -}; - - -} // namespace core -} // namespace xe - - -#endif // XENIA_CORE_WINDOW_H_ diff --git a/src/xenia/emulator.cc b/src/xenia/emulator.cc index 1536f1a20..cee4ca853 100644 --- a/src/xenia/emulator.cc +++ b/src/xenia/emulator.cc @@ -19,6 +19,7 @@ #include #include #include +#include using namespace xe; @@ -29,9 +30,11 @@ using namespace xe::gpu; using namespace xe::hid; using namespace xe::kernel; using namespace xe::kernel::fs; +using namespace xe::ui; Emulator::Emulator(const xechar_t* command_line) : + main_window_(0), memory_(0), debug_server_(0), processor_(0), @@ -44,6 +47,10 @@ Emulator::Emulator(const xechar_t* command_line) : Emulator::~Emulator() { // Note that we delete things in the reverse order they were initialized. + if (main_window_) { + main_window_->Close(); + } + // Disconnect all debug clients first. if (debug_server_) { debug_server_->Shutdown(); diff --git a/src/xenia/emulator.h b/src/xenia/emulator.h index 64293212f..7a713651a 100644 --- a/src/xenia/emulator.h +++ b/src/xenia/emulator.h @@ -25,6 +25,7 @@ XEDECLARECLASS2(xe, kernel, KernelState); XEDECLARECLASS2(xe, kernel, XamModule); XEDECLARECLASS2(xe, kernel, XboxkrnlModule); XEDECLARECLASS3(xe, kernel, fs, FileSystem); +XEDECLARECLASS2(xe, ui, Window); namespace xe { @@ -36,6 +37,10 @@ public: ~Emulator(); const xechar_t* command_line() const { return command_line_; } + + ui::Window* main_window() const { return main_window_; } + void set_main_window(ui::Window* window) { main_window_ = window; } + Memory* memory() const { return memory_; } debug::DebugServer* debug_server() const { return debug_server_; } @@ -58,8 +63,11 @@ public: X_STATUS LaunchDiscImage(const xechar_t* path); private: - xechar_t command_line_[XE_MAX_PATH]; - Memory* memory_; + xechar_t command_line_[XE_MAX_PATH]; + + ui::Window* main_window_; + + Memory* memory_; debug::DebugServer* debug_server_; diff --git a/src/xenia/gpu/d3d11/d3d11_graphics_system.cc b/src/xenia/gpu/d3d11/d3d11_graphics_system.cc index 842673c0c..a28c94a41 100644 --- a/src/xenia/gpu/d3d11/d3d11_graphics_system.cc +++ b/src/xenia/gpu/d3d11/d3d11_graphics_system.cc @@ -9,6 +9,7 @@ #include +#include #include #include #include @@ -122,7 +123,12 @@ void D3D11GraphicsSystem::Initialize() { // will take place. XEASSERTNULL(window_); window_ = new D3D11Window(run_loop_, dxgi_factory_, device_); - window_->set_title(XETEXT("Xenia D3D11")); + if (window_->Initialize("Xenia D3D11", 1280, 768)) { + XELOGE("Failed to create D3D11Window"); + exit(1); + return; + } + emulator_->set_main_window(window_); // Listen for alt-enter/etc. dxgi_factory_->MakeWindowAssociation(window_->handle(), 0); diff --git a/src/xenia/gpu/d3d11/d3d11_window.cc b/src/xenia/gpu/d3d11/d3d11_window.cc index 3f88f8fd7..54b98ad75 100644 --- a/src/xenia/gpu/d3d11/d3d11_window.cc +++ b/src/xenia/gpu/d3d11/d3d11_window.cc @@ -11,9 +11,10 @@ using namespace xe; -using namespace xe::core; using namespace xe::gpu; using namespace xe::gpu::d3d11; +using namespace xe::ui; +using namespace xe::ui::win32; D3D11Window::D3D11Window( @@ -29,10 +30,33 @@ D3D11Window::D3D11Window( swap_chain_ = 0; render_target_view_ = 0; + // TODO(benvanik): move to emulator main window setter. + closing.AddListener([](UIEvent& e) { + xe_run_loop_quit(e.window()->run_loop()); + }); +} + +D3D11Window::~D3D11Window() { + if (context_) { + context_->ClearState(); + } + XESAFERELEASE(render_target_view_); + XESAFERELEASE(context_); + XESAFERELEASE(swap_chain_); + XESAFERELEASE(device_); + XESAFERELEASE(dxgi_factory_); +} + +int D3D11Window::Initialize(const char* title, uint32_t width, uint32_t height) { + int result = Win32Window::Initialize(title, width, height); + if (result) { + return result; + } + // Setup swap chain. DXGI_SWAP_CHAIN_DESC desc; xe_zero_struct(&desc, sizeof(desc)); - desc.OutputWindow = handle_; + desc.OutputWindow = handle(); desc.Windowed = TRUE; desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; @@ -40,8 +64,8 @@ D3D11Window::D3D11Window( // Setup buffers. desc.BufferCount = 1; desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - desc.BufferDesc.Width = width_; - desc.BufferDesc.Height = height_; + desc.BufferDesc.Width = width; + desc.BufferDesc.Height = height; desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; desc.BufferDesc.RefreshRate.Numerator = 60; desc.BufferDesc.RefreshRate.Denominator = 1; @@ -57,8 +81,7 @@ D3D11Window::D3D11Window( &swap_chain_); if (FAILED(hr)) { XELOGE("CreateSwapChain failed with %.8X", hr); - exit(1); - return; + return 1; } // Create a render target view to draw into. @@ -67,29 +90,18 @@ D3D11Window::D3D11Window( 0, __uuidof(ID3D11Texture2D), (void**)&back_buffer); if (FAILED(hr)) { XELOGE("GetBuffer (back_buffer) failed with %.8X", hr); - exit(1); - return; + return 1; } hr = device_->CreateRenderTargetView( back_buffer, NULL, &render_target_view_); back_buffer->Release(); if (FAILED(hr)) { XELOGE("CreateRenderTargetView (back_buffer) failed with %.8X", hr); - exit(1); - return; + return 1; } context_->OMSetRenderTargets(1, &render_target_view_, NULL); -} -D3D11Window::~D3D11Window() { - if (context_) { - context_->ClearState(); - } - XESAFERELEASE(render_target_view_); - XESAFERELEASE(context_); - XESAFERELEASE(swap_chain_); - XESAFERELEASE(device_); - XESAFERELEASE(dxgi_factory_); + return 0; } void D3D11Window::Swap() { @@ -102,13 +114,13 @@ void D3D11Window::Swap() { } } -void D3D11Window::OnResize(uint32_t width, uint32_t height) { - Win32Window::OnResize(width, height); +bool D3D11Window::OnResize(uint32_t width, uint32_t height) { + if (!Win32Window::OnResize(width, height)) { + return false; + } // TODO(benvanik): resize swap buffers? + + return true; } -void D3D11Window::OnClose() { - // We are the master window - if they close us, quit! - xe_run_loop_quit(run_loop_); -} diff --git a/src/xenia/gpu/d3d11/d3d11_window.h b/src/xenia/gpu/d3d11/d3d11_window.h index a90f1643e..51a2a6c8e 100644 --- a/src/xenia/gpu/d3d11/d3d11_window.h +++ b/src/xenia/gpu/d3d11/d3d11_window.h @@ -12,6 +12,8 @@ #include +#include + #include @@ -20,18 +22,19 @@ namespace gpu { namespace d3d11 { -class D3D11Window : public xe::core::Win32Window { +class D3D11Window : public xe::ui::win32::Win32Window { public: D3D11Window( xe_run_loop_ref run_loop, IDXGIFactory1* dxgi_factory, ID3D11Device* device); virtual ~D3D11Window(); + virtual int Initialize(const char* title, uint32_t width, uint32_t height); + void Swap(); protected: - virtual void OnResize(uint32_t width, uint32_t height); - virtual void OnClose(); + virtual bool OnResize(uint32_t width, uint32_t height); private: IDXGIFactory1* dxgi_factory_; diff --git a/src/xenia/gpu/graphics_system.cc b/src/xenia/gpu/graphics_system.cc index 90ca71308..53f8b24ca 100644 --- a/src/xenia/gpu/graphics_system.cc +++ b/src/xenia/gpu/graphics_system.cc @@ -93,7 +93,8 @@ void GraphicsSystem::ThreadStart() { xe_run_loop_release(run_loop); - // TODO(benvanik): call module API to kill? + // TODO(benvanik): call module API to kill? this is a bad shutdown. + exit(1); } void GraphicsSystem::Initialize() { diff --git a/src/xenia/sources.gypi b/src/xenia/sources.gypi index 775ff7943..5d2c066b0 100644 --- a/src/xenia/sources.gypi +++ b/src/xenia/sources.gypi @@ -33,5 +33,6 @@ 'gpu/sources.gypi', 'hid/sources.gypi', 'kernel/sources.gypi', + 'ui/sources.gypi', ], } diff --git a/src/xenia/core/window.cc b/src/xenia/ui/menu_item.cc similarity index 61% rename from src/xenia/core/window.cc rename to src/xenia/ui/menu_item.cc index b259ea10e..756e01d84 100644 --- a/src/xenia/core/window.cc +++ b/src/xenia/ui/menu_item.cc @@ -1,23 +1,22 @@ -/** - ****************************************************************************** - * Xenia : Xbox 360 Emulator Research Project * - ****************************************************************************** - * Copyright 2013 Ben Vanik. All rights reserved. * - * Released under the BSD license - see LICENSE in the root for more details. * - ****************************************************************************** - */ - -#include - - -using namespace xe; -using namespace xe::core; - - -Window::Window(xe_run_loop_ref run_loop) { - run_loop_ = xe_run_loop_retain(run_loop); -} - -Window::~Window() { - xe_run_loop_release(run_loop_); -} +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2014 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include + + +using namespace xe; +using namespace xe::ui; + + +MenuItem::MenuItem(Window* window, MenuItem* parent_item) : + window_(window), parent_item_(parent_item) { +} + +MenuItem::~MenuItem() { +} diff --git a/src/xenia/ui/menu_item.h b/src/xenia/ui/menu_item.h new file mode 100644 index 000000000..48af63420 --- /dev/null +++ b/src/xenia/ui/menu_item.h @@ -0,0 +1,41 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2014 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_UI_MENU_ITEM_H_ +#define XENIA_UI_MENU_ITEM_H_ + +#include + + +namespace xe { +namespace ui { + +class Window; + + +class MenuItem { +public: + MenuItem(Window* window, MenuItem* parent_item = NULL); + virtual ~MenuItem(); + + Window* window() const { return window_; } + MenuItem* parent_item() const { return parent_item_; } + +private: + Window* window_; + MenuItem* parent_item_; + // children +}; + + +} // namespace ui +} // namespace xe + + +#endif // XENIA_UI_MENU_ITEM_H_ diff --git a/src/xenia/ui/sources.gypi b/src/xenia/ui/sources.gypi new file mode 100644 index 000000000..b0e8905f6 --- /dev/null +++ b/src/xenia/ui/sources.gypi @@ -0,0 +1,18 @@ +# Copyright 2014 Ben Vanik. All Rights Reserved. +{ + 'sources': [ + 'menu_item.cc', + 'menu_item.h', + 'ui_event.h', + 'window.cc', + 'window.h', + ], + + 'conditions': [ + ['OS == "win"', { + 'includes': [ + 'win32/sources.gypi', + ], + }], + ], +} diff --git a/src/xenia/ui/ui_event.h b/src/xenia/ui/ui_event.h new file mode 100644 index 000000000..0c973b86f --- /dev/null +++ b/src/xenia/ui/ui_event.h @@ -0,0 +1,74 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2014 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_UI_UI_EVENT_H_ +#define XENIA_UI_UI_EVENT_H_ + +#include + + +namespace xe { +namespace ui { + +class App; +class Window; + + +class UIEvent { +public: + UIEvent(Window* window = NULL) : + window_(window) {} + virtual ~UIEvent() {} + + Window* window() const { return window_; } + +private: + Window* window_; +}; + + +class MouseEvent : public UIEvent { +public: + enum Button { + MOUSE_BUTTON_NONE = 0, + MOUSE_BUTTON_LEFT, + MOUSE_BUTTON_RIGHT, + MOUSE_BUTTON_MIDDLE, + MOUSE_BUTTON_X1, + MOUSE_BUTTON_X2, + }; + +public: + MouseEvent(Window* window, + Button button, int32_t x, int32_t y, + int32_t dx = 0, int32_t dy = 0) : + button_(button), x_(x), y_(y), dx_(dx), dy_(dy), + UIEvent(window) {} + virtual ~MouseEvent() {} + + Button button() const { return button_; } + int32_t x() const { return x_; } + int32_t y() const { return y_; } + int32_t dx() const { return dx_; } + int32_t dy() const { return dy_; } + +private: + Button button_; + int32_t x_; + int32_t y_; + int32_t dx_; + int32_t dy_; +}; + + +} // namespace ui +} // namespace xe + + +#endif // XENIA_UI_UI_EVENT_H_ diff --git a/src/xenia/ui/win32/sources.gypi b/src/xenia/ui/win32/sources.gypi new file mode 100644 index 000000000..45f5a2845 --- /dev/null +++ b/src/xenia/ui/win32/sources.gypi @@ -0,0 +1,9 @@ +# Copyright 2014 Ben Vanik. All Rights Reserved. +{ + 'sources': [ + 'win32_menu_item.cc', + 'win32_menu_item.h', + 'win32_window.cc', + 'win32_window.h', + ], +} diff --git a/src/xenia/ui/win32/win32_menu_item.cc b/src/xenia/ui/win32/win32_menu_item.cc new file mode 100644 index 000000000..5d66c3237 --- /dev/null +++ b/src/xenia/ui/win32/win32_menu_item.cc @@ -0,0 +1,23 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2014 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include + + +using namespace xe; +using namespace xe::ui; +using namespace xe::ui::win32; + + +Win32MenuItem::Win32MenuItem(Window* window, MenuItem* parent_item) : + MenuItem(window, parent_item) { +} + +Win32MenuItem::~Win32MenuItem() { +} diff --git a/src/xenia/ui/win32/win32_menu_item.h b/src/xenia/ui/win32/win32_menu_item.h new file mode 100644 index 000000000..7f43109bb --- /dev/null +++ b/src/xenia/ui/win32/win32_menu_item.h @@ -0,0 +1,37 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2014 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_UI_WIN32_WIN32_MENU_ITEM_H_ +#define XENIA_UI_WIN32_WIN32_MENU_ITEM_H_ + +#include + +#include + + +namespace xe { +namespace ui { +namespace win32 { + + +class Win32MenuItem : public MenuItem { +public: + Win32MenuItem(Window* window, MenuItem* parent_item = NULL); + virtual ~Win32MenuItem(); + +private: +}; + + +} // namespace win32 +} // namespace ui +} // namespace xe + + +#endif // XENIA_UI_WIN32_WIN32_MENU_ITEM_H_ diff --git a/src/xenia/core/win32_window.cc b/src/xenia/ui/win32/win32_window.cc similarity index 61% rename from src/xenia/core/win32_window.cc rename to src/xenia/ui/win32/win32_window.cc index 41210c1c2..4bf5cc0cc 100644 --- a/src/xenia/core/win32_window.cc +++ b/src/xenia/ui/win32/win32_window.cc @@ -1,244 +1,371 @@ -/** - ****************************************************************************** - * Xenia : Xbox 360 Emulator Research Project * - ****************************************************************************** - * Copyright 2013 Ben Vanik. All rights reserved. * - * Released under the BSD license - see LICENSE in the root for more details. * - ****************************************************************************** - */ - -#include - -#include -#include - - -using namespace xe; -using namespace xe::core; - - -namespace { - -static LRESULT CALLBACK Win32WindowWndProc( - HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { - Win32Window* window = 0; - if (message == WM_NCCREATE) { - LPCREATESTRUCT create_struct = (LPCREATESTRUCT)lParam; - window = (Win32Window*)create_struct->lpCreateParams; - SetWindowLongPtr(hWnd, GWLP_USERDATA, (__int3264)(LONG_PTR)window); - } else { - window = (Win32Window*)GetWindowLongPtr(hWnd, GWLP_USERDATA); - } - if (window) { - return window->WndProc(hWnd, message, wParam, lParam); - } else { - return DefWindowProc(hWnd, message, wParam, lParam); - } -} - -} - - -Win32Window::Win32Window(xe_run_loop_ref run_loop) : - handle_(0), - Window(run_loop) { - Create(); -} - -Win32Window::~Win32Window() { - if (handle_) { - CloseWindow(handle_); - } -} - -void Win32Window::Create() { - HINSTANCE hInstance = GetModuleHandle(NULL); - - width_ = 1280; - height_ = 720; - - WNDCLASSEX wcex; - wcex.cbSize = sizeof(WNDCLASSEX); - wcex.style = CS_HREDRAW | CS_VREDRAW; - wcex.lpfnWndProc = Win32WindowWndProc; - wcex.cbClsExtra = 0; - wcex.cbWndExtra = 0; - wcex.hInstance = hInstance; - wcex.hIcon = NULL; // LoadIcon(hInstance, (LPCTSTR)IDI_TUTORIAL1); - wcex.hIconSm = NULL; // LoadIcon(hInstance, (LPCTSTR)IDI_TUTORIAL1); - wcex.hCursor = LoadCursor(NULL, IDC_ARROW); - wcex.hbrBackground = ( HBRUSH )( COLOR_WINDOW + 1 ); - wcex.lpszMenuName = NULL; - wcex.lpszClassName = L"XeniaWindowClass"; - if (!RegisterClassEx(&wcex)) { - XELOGE("RegisterClassEx failed"); - exit(1); - return; - } - - // Setup initial size. - DWORD window_style = WS_OVERLAPPEDWINDOW; - DWORD window_ex_style = WS_EX_APPWINDOW; - RECT rc = { - 0, 0, - width_, height_ - }; - AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE); - - // Create window. - handle_ = CreateWindowEx( - window_ex_style, - L"XeniaWindowClass", - L"Xenia", - window_style, - CW_USEDEFAULT, CW_USEDEFAULT, - rc.right - rc.left, rc.bottom - rc.top, - NULL, - NULL, - hInstance, - this); - if (!handle_) { - XELOGE("CreateWindow failed"); - exit(1); - return; - } - - // Disable flicks. - ATOM atom = GlobalAddAtom(L"MicrosoftTabletPenServiceProperty"); - const DWORD_PTR dwHwndTabletProperty = - TABLET_DISABLE_PRESSANDHOLD | // disables press and hold (right-click) gesture - TABLET_DISABLE_PENTAPFEEDBACK | // disables UI feedback on pen up (waves) - TABLET_DISABLE_PENBARRELFEEDBACK | // disables UI feedback on pen button down (circle) - TABLET_DISABLE_FLICKS | // disables pen flicks (back, forward, drag down, drag up) - TABLET_DISABLE_TOUCHSWITCH | - TABLET_DISABLE_SMOOTHSCROLLING | - TABLET_DISABLE_TOUCHUIFORCEON | - TABLET_ENABLE_MULTITOUCHDATA; - SetProp( - handle_, - L"MicrosoftTabletPenServiceProperty", - reinterpret_cast(dwHwndTabletProperty)); - GlobalDeleteAtom(atom); - - // Enable DWM elevation. - EnableMMCSS(); - - ShowWindow(handle_, SW_SHOWNORMAL); - UpdateWindow(handle_); -} - -void Win32Window::EnableMMCSS() { - HMODULE hLibrary = LoadLibrary(L"DWMAPI.DLL"); - if (!hLibrary) { - return; - } - - typedef HRESULT (__stdcall *PDwmEnableMMCSS)(BOOL); - PDwmEnableMMCSS pDwmEnableMMCSS = - (PDwmEnableMMCSS)GetProcAddress( - hLibrary, "DwmEnableMMCSS"); - if (pDwmEnableMMCSS) { - pDwmEnableMMCSS(TRUE); - } - - typedef HRESULT (__stdcall *PDwmSetPresentParameters)(HWND, DWM_PRESENT_PARAMETERS*); - PDwmSetPresentParameters pDwmSetPresentParameters = - (PDwmSetPresentParameters)GetProcAddress( - hLibrary, "DwmSetPresentParameters"); - if (pDwmSetPresentParameters) { - DWM_PRESENT_PARAMETERS pp; - memset(&pp, 0, sizeof(DWM_PRESENT_PARAMETERS)); - pp.cbSize = sizeof(DWM_PRESENT_PARAMETERS); - pp.fQueue = FALSE; - pp.cBuffer = 2; - pp.fUseSourceRate = FALSE; - pp.cRefreshesPerFrame = 1; - pp.eSampling = DWM_SOURCE_FRAME_SAMPLING_POINT; - pDwmSetPresentParameters(handle_, &pp); - } - - FreeLibrary( hLibrary ); -} - -void Win32Window::set_title(const xechar_t* title) { - XEIGNORE(SetWindowText(handle_, title)); -} - -void Win32Window::Resize(uint32_t width, uint32_t height) { - if (width == width_ && height == height_) { - return; - } - width_ = width; - height_ = height; - - RECT rc = { - 0, 0, - width_, height_ - }; - AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE); - // TODO(benvanik): center. - MoveWindow(handle_, 0, 0, rc.right - rc.left, rc.bottom - rc.top, TRUE); - - OnResize(width_, height_); -} - -void Win32Window::ShowError(const xechar_t* message) { - XEIGNORE(MessageBox(handle_, message, L"Xenia Error", MB_ICONERROR | MB_OK)); -} - -LRESULT Win32Window::WndProc(HWND hWnd, UINT message, - WPARAM wParam, LPARAM lParam) { - switch (message) { - case WM_NCCREATE: - handle_ = hWnd; - return DefWindowProc(hWnd, message, wParam, lParam); - case WM_ACTIVATEAPP: - if (wParam) { - // Made active. - } else { - // Made inactive. - } - return DefWindowProc(hWnd, message, wParam, lParam); - case WM_CLOSE: - OnClose(); - return DefWindowProc(hWnd, message, wParam, lParam); - case WM_DESTROY: - PostQuitMessage(0); - return 0; - - case WM_PAINT: - { - PAINTSTRUCT ps; - HDC hdc = BeginPaint(hWnd, &ps); - EndPaint(hWnd, &ps); - } - return 0; - case WM_ERASEBKGND: - return 0; // ignore - case WM_DISPLAYCHANGE: - return DefWindowProc(hWnd, message, wParam, lParam); - - case WM_MOVE: - return DefWindowProc(hWnd, message, wParam, lParam); - case WM_SIZE: - { - RECT frame; - GetClientRect(handle_, &frame); - OnResize(frame.right - frame.left, frame.bottom - frame.top); - } - return DefWindowProc(hWnd, message, wParam, lParam); - - case WM_TABLET_QUERYSYSTEMGESTURESTATUS: - return - TABLET_DISABLE_PRESSANDHOLD | // disables press and hold (right-click) gesture - TABLET_DISABLE_PENTAPFEEDBACK | // disables UI feedback on pen up (waves) - TABLET_DISABLE_PENBARRELFEEDBACK | // disables UI feedback on pen button down (circle) - TABLET_DISABLE_FLICKS | // disables pen flicks (back, forward, drag down, drag up) - TABLET_DISABLE_TOUCHSWITCH | - TABLET_DISABLE_SMOOTHSCROLLING | - TABLET_DISABLE_TOUCHUIFORCEON | - TABLET_ENABLE_MULTITOUCHDATA; - default: - return DefWindowProc(hWnd, message, wParam, lParam); - } -} +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2014 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include + +#include +#include +#include + + +using namespace xe; +using namespace xe::ui; +using namespace xe::ui::win32; + + +namespace { + +static LRESULT CALLBACK Win32WindowWndProc( + HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { + Win32Window* window = 0; + if (message == WM_NCCREATE) { + LPCREATESTRUCT create_struct = (LPCREATESTRUCT)lParam; + window = (Win32Window*)create_struct->lpCreateParams; + SetWindowLongPtr(hWnd, GWLP_USERDATA, (__int3264)(LONG_PTR)window); + } else { + window = (Win32Window*)GetWindowLongPtr(hWnd, GWLP_USERDATA); + } + if (window) { + return window->WndProc(hWnd, message, wParam, lParam); + } else { + return DefWindowProc(hWnd, message, wParam, lParam); + } +} + +} // namespace + + +Win32Window::Win32Window(xe_run_loop_ref run_loop) : + handle_(0), closing_(false), + Window(run_loop) { +} + +Win32Window::~Win32Window() { + if (handle_) { + CloseWindow(handle_); + handle_ = NULL; + } +} + +int Win32Window::Initialize(const char* title, uint32_t width, uint32_t height) { + int result = Window::Initialize(title, width, height); + if (result) { + return result; + } + + HINSTANCE hInstance = GetModuleHandle(NULL); + + WNDCLASSEX wcex; + wcex.cbSize = sizeof(WNDCLASSEX); + wcex.style = 0; + wcex.lpfnWndProc = Win32WindowWndProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = hInstance; + wcex.hIcon = NULL; // LoadIcon(hInstance, (LPCTSTR)IDI_TUTORIAL1); + wcex.hIconSm = NULL; // LoadIcon(hInstance, (LPCTSTR)IDI_TUTORIAL1); + wcex.hCursor = LoadCursor(NULL, IDC_ARROW); + wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); + wcex.lpszMenuName = NULL; + wcex.lpszClassName = L"XeniaWindowClass"; + if (!RegisterClassEx(&wcex)) { + XELOGE("RegisterClassEx failed"); + return 1; + } + + // Setup initial size. + DWORD window_style = WS_OVERLAPPEDWINDOW; + DWORD window_ex_style = WS_EX_APPWINDOW; + RECT rc = { + 0, 0, + width, height + }; + AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE); + + // Create window. + handle_ = CreateWindowEx( + window_ex_style, + L"XeniaWindowClass", + L"Xenia", + window_style, + CW_USEDEFAULT, CW_USEDEFAULT, + rc.right - rc.left, rc.bottom - rc.top, + NULL, + NULL, + hInstance, + this); + if (!handle_) { + XELOGE("CreateWindow failed"); + return 1; + } + + // Disable flicks. + ATOM atom = GlobalAddAtom(L"MicrosoftTabletPenServiceProperty"); + const DWORD_PTR dwHwndTabletProperty = + TABLET_DISABLE_PRESSANDHOLD | // disables press and hold (right-click) gesture + TABLET_DISABLE_PENTAPFEEDBACK | // disables UI feedback on pen up (waves) + TABLET_DISABLE_PENBARRELFEEDBACK | // disables UI feedback on pen button down (circle) + TABLET_DISABLE_FLICKS | // disables pen flicks (back, forward, drag down, drag up) + TABLET_DISABLE_TOUCHSWITCH | + TABLET_DISABLE_SMOOTHSCROLLING | + TABLET_DISABLE_TOUCHUIFORCEON | + TABLET_ENABLE_MULTITOUCHDATA; + SetProp( + handle_, + L"MicrosoftTabletPenServiceProperty", + reinterpret_cast(dwHwndTabletProperty)); + GlobalDeleteAtom(atom); + + // Enable DWM elevation. + EnableMMCSS(); + + ShowWindow(handle_, SW_SHOWNORMAL); + UpdateWindow(handle_); + + return 0; +} + +void Win32Window::EnableMMCSS() { + HMODULE hLibrary = LoadLibrary(L"DWMAPI.DLL"); + if (!hLibrary) { + return; + } + + typedef HRESULT (__stdcall *PDwmEnableMMCSS)(BOOL); + PDwmEnableMMCSS pDwmEnableMMCSS = + (PDwmEnableMMCSS)GetProcAddress( + hLibrary, "DwmEnableMMCSS"); + if (pDwmEnableMMCSS) { + pDwmEnableMMCSS(TRUE); + } + + typedef HRESULT (__stdcall *PDwmSetPresentParameters)(HWND, DWM_PRESENT_PARAMETERS*); + PDwmSetPresentParameters pDwmSetPresentParameters = + (PDwmSetPresentParameters)GetProcAddress( + hLibrary, "DwmSetPresentParameters"); + if (pDwmSetPresentParameters) { + DWM_PRESENT_PARAMETERS pp; + memset(&pp, 0, sizeof(DWM_PRESENT_PARAMETERS)); + pp.cbSize = sizeof(DWM_PRESENT_PARAMETERS); + pp.fQueue = FALSE; + pp.cBuffer = 2; + pp.fUseSourceRate = FALSE; + pp.cRefreshesPerFrame = 1; + pp.eSampling = DWM_SOURCE_FRAME_SAMPLING_POINT; + pDwmSetPresentParameters(handle_, &pp); + } + + FreeLibrary(hLibrary); +} + +bool Win32Window::set_title(const char* title) { + if (!Window::set_title(title)) { + return false; + } + XEIGNORE(SetWindowTextA(handle_, title)); + return true; +} + +bool Win32Window::set_cursor_visible(bool value) { + if (!Window::set_cursor_visible(value)) { + return false; + } + if (value) { + ShowCursor(TRUE); + SetCursor(NULL); + } else { + ShowCursor(FALSE); + } + return true; +} + +bool Win32Window::SetSize(uint32_t width, uint32_t height) { + RECT rc = { + 0, 0, + width, height + }; + AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE); + // TODO(benvanik): center? + MoveWindow(handle_, 0, 0, rc.right - rc.left, rc.bottom - rc.top, TRUE); + return true; +} + +void Win32Window::OnClose() { + if (!closing_ && handle_) { + closing_ = true; + CloseWindow(handle_); + handle_ = NULL; + } +} + +bool Win32Window::HandleMouse(UINT message, WPARAM wParam, LPARAM lParam) { + int32_t x = GET_X_LPARAM(lParam); + int32_t y = GET_Y_LPARAM(lParam); + if (message == WM_MOUSEWHEEL) { + POINT pt = { x, y }; + ScreenToClient(handle_, &pt); + x = pt.x; + y = pt.y; + } + + MouseEvent::Button button = MouseEvent::MOUSE_BUTTON_NONE; + int32_t dx = 0; + int32_t dy = 0; + switch (message) { + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + button = MouseEvent::MOUSE_BUTTON_LEFT; + break; + case WM_RBUTTONDOWN: + case WM_RBUTTONUP: + button = MouseEvent::MOUSE_BUTTON_RIGHT; + break; + case WM_MBUTTONDOWN: + case WM_MBUTTONUP: + button = MouseEvent::MOUSE_BUTTON_MIDDLE; + break; + case WM_XBUTTONDOWN: + case WM_XBUTTONUP: + switch (GET_XBUTTON_WPARAM(wParam)) { + case XBUTTON1: + button = MouseEvent::MOUSE_BUTTON_X1; + break; + case XBUTTON2: + button = MouseEvent::MOUSE_BUTTON_X2; + break; + default: + return false; + } + break; + case WM_MOUSEMOVE: + button = MouseEvent::MOUSE_BUTTON_NONE; + break; + case WM_MOUSEWHEEL: + button = MouseEvent::MOUSE_BUTTON_NONE; + dx = 0; // ? + dy = GET_WHEEL_DELTA_WPARAM(wParam); + break; + default: + // Double click/etc? + return true; + } + + auto e = MouseEvent(this, button, x, y, dx, dy); + switch (message) { + case WM_LBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_XBUTTONDOWN: + mouse_down(e); + break; + case WM_LBUTTONUP: + case WM_RBUTTONUP: + case WM_MBUTTONUP: + case WM_XBUTTONUP: + mouse_up(e); + break; + case WM_MOUSEMOVE: + mouse_move(e); + break; + case WM_MOUSEWHEEL: + mouse_wheel(e); + break; + } + return true; +} + +bool Win32Window::HandleKeyboard(UINT message, WPARAM wParam, LPARAM lParam) { + switch (message) { + case WM_KEYDOWN: + (byte)wParam; + return true; + case WM_KEYUP: + (byte)wParam; + return true; + default: + return false; + } +} + +LRESULT Win32Window::WndProc(HWND hWnd, UINT message, + WPARAM wParam, LPARAM lParam) { + if (message >= WM_MOUSEFIRST && message <= WM_MOUSELAST) { + if (HandleMouse(message, wParam, lParam)) { + return 0; + } else { + return DefWindowProc(hWnd, message, wParam, lParam); + } + } else if (message >= WM_KEYFIRST && message <= WM_KEYLAST) { + if (HandleKeyboard(message, wParam, lParam)) { + return 0; + } else { + return DefWindowProc(hWnd, message, wParam, lParam); + } + } + + switch (message) { + case WM_NCCREATE: + handle_ = hWnd; + return DefWindowProc(hWnd, message, wParam, lParam); + case WM_ACTIVATEAPP: + if (wParam) { + // Made active. + OnShow(); + } else { + // Made inactive. + OnHide(); + } + return DefWindowProc(hWnd, message, wParam, lParam); + case WM_CLOSE: + closing_ = true; + Close(); + return DefWindowProc(hWnd, message, wParam, lParam); + case WM_DESTROY: + return 0; + + case WM_PAINT: + { + PAINTSTRUCT ps; + HDC hdc = BeginPaint(hWnd, &ps); + EndPaint(hWnd, &ps); + } + return 0; + case WM_ERASEBKGND: + return 0; // ignore + case WM_DISPLAYCHANGE: + return DefWindowProc(hWnd, message, wParam, lParam); + + case WM_MOVE: + return DefWindowProc(hWnd, message, wParam, lParam); + case WM_SIZING: + BeginResizing(); + return DefWindowProc(hWnd, message, wParam, lParam); + case WM_SIZE: + { + RECT frame; + GetClientRect(handle_, &frame); + OnResize(frame.right - frame.left, frame.bottom - frame.top); + EndResizing(); + } + return DefWindowProc(hWnd, message, wParam, lParam); + + case WM_TABLET_QUERYSYSTEMGESTURESTATUS: + return + TABLET_DISABLE_PRESSANDHOLD | // disables press and hold (right-click) gesture + TABLET_DISABLE_PENTAPFEEDBACK | // disables UI feedback on pen up (waves) + TABLET_DISABLE_PENBARRELFEEDBACK | // disables UI feedback on pen button down (circle) + TABLET_DISABLE_FLICKS | // disables pen flicks (back, forward, drag down, drag up) + TABLET_DISABLE_TOUCHSWITCH | + TABLET_DISABLE_SMOOTHSCROLLING | + TABLET_DISABLE_TOUCHUIFORCEON | + TABLET_ENABLE_MULTITOUCHDATA; + default: + return DefWindowProc(hWnd, message, wParam, lParam); + } +} diff --git a/src/xenia/core/win32_window.h b/src/xenia/ui/win32/win32_window.h similarity index 51% rename from src/xenia/core/win32_window.h rename to src/xenia/ui/win32/win32_window.h index a5b038ee0..20be6dafe 100644 --- a/src/xenia/core/win32_window.h +++ b/src/xenia/ui/win32/win32_window.h @@ -1,49 +1,55 @@ -/** - ****************************************************************************** - * Xenia : Xbox 360 Emulator Research Project * - ****************************************************************************** - * Copyright 2013 Ben Vanik. All rights reserved. * - * Released under the BSD license - see LICENSE in the root for more details. * - ****************************************************************************** - */ - -#ifndef XENIA_CORE_WIN32_WINDOW_H_ -#define XENIA_CORE_WIN32_WINDOW_H_ - -#include -#include - - -namespace xe { -namespace core { - - -class Win32Window : public Window { -public: - Win32Window(xe_run_loop_ref run_loop); - virtual ~Win32Window(); - - HWND handle() const { return handle_; } - - virtual void set_title(const xechar_t* title); - - virtual void Resize(uint32_t width, uint32_t height); - - virtual void ShowError(const xechar_t* message); - - LRESULT WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); - -protected: - HWND handle_; - -private: - void Create(); - void EnableMMCSS(); -}; - - -} // namespace core -} // namespace xe - - -#endif // XENIA_CORE_WIN32_WINDOW_H_ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2014 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_UI_WIN32_WIN32_WINDOW_H_ +#define XENIA_UI_WIN32_WIN32_WINDOW_H_ + +#include + +#include + + +namespace xe { +namespace ui { +namespace win32 { + + +class Win32Window : public Window { +public: + Win32Window(xe_run_loop_ref run_loop); + virtual ~Win32Window(); + + virtual int Initialize(const char* title, uint32_t width, uint32_t height); + + virtual bool set_title(const char* title); + virtual bool set_cursor_visible(bool value); + HWND handle() const { return handle_; } + + LRESULT WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); + +protected: + virtual bool SetSize(uint32_t width, uint32_t height); + virtual void OnClose(); + +private: + void EnableMMCSS(); + bool HandleMouse(UINT message, WPARAM wParam, LPARAM lParam); + bool HandleKeyboard(UINT message, WPARAM wParam, LPARAM lParam); + + HWND handle_; + bool closing_; +}; + + +} // namespace win32 +} // namespace ui +} // namespace xe + + +#endif // XENIA_UI_WIN32_WIN32_WINDOW_H_ diff --git a/src/xenia/ui/window.cc b/src/xenia/ui/window.cc new file mode 100644 index 000000000..651423b74 --- /dev/null +++ b/src/xenia/ui/window.cc @@ -0,0 +1,120 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2014 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include + + +using namespace xe; +using namespace xe::ui; + + +Window::Window(xe_run_loop_ref run_loop) : + title_(0), is_visible_(true), is_cursor_visible_(true), + width_(0), height_(0) { + run_loop_ = xe_run_loop_retain(run_loop); +} + +Window::~Window() { + if (title_) { + xe_free(title_); + } + xe_run_loop_release(run_loop_); +} + +int Window::Initialize(const char* title, uint32_t width, uint32_t height) { + title_ = xestrdupa(title); + width_ = width; + height_ = height; + return 0; +} + +bool Window::set_title(const char* title) { + if (title == title_) { + return false; + } + if (title_) { + xe_free(title_); + } + title_ = xestrdupa(title); + return true; +} + +bool Window::set_cursor_visible(bool value) { + if (value == is_cursor_visible_) { + return false; + } + is_cursor_visible_ = value; + return true; +} + +void Window::OnShow() { + if (is_visible_) { + return; + } + is_visible_ = true; + auto e = UIEvent(this); + shown(e); +} + +void Window::OnHide() { + if (!is_visible_) { + return; + } + is_visible_ = false; + auto e = UIEvent(this); + hidden(e); +} + +void Window::Resize(uint32_t width, uint32_t height) { + BeginResizing(); + SetSize(width, height); + OnResize(width, height); // redundant? + EndResizing(); +} + +void Window::BeginResizing() { + if (resizing_) { + return; + } + resizing_ = true; + auto e = UIEvent(this); + resizing(e); +} + +bool Window::OnResize(uint32_t width, uint32_t height) { + if (!resizing_) { + BeginResizing(); + } + if (width == width_ && height == height_) { + return false; + } + width_ = width; + height_ = height; + return true; +} + +void Window::EndResizing() { + XEASSERT(resizing_); + resizing_ = false; + auto e = UIEvent(this); + resized(e); +} + +void Window::Close() { + auto e = UIEvent(this); + closing(e); + + OnClose(); + + e = UIEvent(this); + closed(e); +} + +void Window::OnClose() { +} diff --git a/src/xenia/ui/window.h b/src/xenia/ui/window.h new file mode 100644 index 000000000..49fcbf17a --- /dev/null +++ b/src/xenia/ui/window.h @@ -0,0 +1,82 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2014 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_UI_WINDOW_H_ +#define XENIA_UI_WINDOW_H_ + +#include + +#include +#include + + +namespace xe { +namespace ui { + + +class Window { +public: + Window(xe_run_loop_ref run_loop); + virtual ~Window(); + + virtual int Initialize(const char* title, uint32_t width, uint32_t height); + + xe_run_loop_ref run_loop() const { return run_loop_; } + + const char* title() const { return title_; } + virtual bool set_title(const char* title); + bool is_visible() const { return is_visible_; } + bool is_cursor_visible() const { return is_cursor_visible_; } + virtual bool set_cursor_visible(bool value); + uint32_t width() const { return width_; } + uint32_t height() const { return height_; } + void Resize(uint32_t width, uint32_t height); + + void Close(); + +public: + alloy::Delegate shown; + alloy::Delegate hidden; + alloy::Delegate resizing; + alloy::Delegate resized; + alloy::Delegate closing; + alloy::Delegate closed; + + alloy::Delegate mouse_down; + alloy::Delegate mouse_move; + alloy::Delegate mouse_up; + alloy::Delegate mouse_wheel; + +protected: + void OnShow(); + void OnHide(); + + void BeginResizing(); + virtual bool OnResize(uint32_t width, uint32_t height); + void EndResizing(); + virtual bool SetSize(uint32_t width, uint32_t height) = 0; + + virtual void OnClose(); + +private: + xe_run_loop_ref run_loop_; + char* title_; + bool is_visible_; + bool is_cursor_visible_; + bool resizing_; + uint32_t width_; + uint32_t height_; +}; + + +} // namespace ui +} // namespace xe + + +#endif // XENIA_UI_WINDOW_H_