Refactoring window stuff. Still needs some work.

This commit is contained in:
Ben Vanik 2014-01-14 22:40:02 -08:00
parent e7d61f4b1f
commit 991e7d8ad3
23 changed files with 926 additions and 412 deletions

View File

@ -52,7 +52,7 @@ private:
class DebugEvent { class DebugEvent {
public: public:
DebugEvent(Debugger* debugger) : DebugEvent(Debugger* debugger) :
debugger_(debugger) {} debugger_(debugger) {}
virtual ~DebugEvent() {} virtual ~DebugEvent() {}
Debugger* debugger() const { return debugger_; } Debugger* debugger() const { return debugger_; }
protected: protected:

View File

@ -27,10 +27,5 @@ namespace xe {
#include <xenia/core/run_loop.h> #include <xenia/core/run_loop.h>
#include <xenia/core/socket.h> #include <xenia/core/socket.h>
#include <xenia/core/thread.h> #include <xenia/core/thread.h>
#include <xenia/core/window.h>
#if XE_PLATFORM_WIN32
#include <xenia/core/win32_window.h>
#endif // WIN32
#endif // XENIA_CORE_H_ #endif // XENIA_CORE_H_

View File

@ -59,7 +59,7 @@ int xe_run_loop_pump(xe_run_loop_ref run_loop) {
} }
break; break;
case WM_XE_RUN_LOOP_QUIT: case WM_XE_RUN_LOOP_QUIT:
if (msg.lParam == (WPARAM)run_loop) { if (msg.wParam == (WPARAM)run_loop) {
// Done! // Done!
return 1; 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) { 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, void xe_run_loop_call(xe_run_loop_ref run_loop,

View File

@ -18,8 +18,6 @@
'socket.h', 'socket.h',
'thread.cc', 'thread.cc',
'thread.h', 'thread.h',
'window.cc',
'window.h',
], ],
'conditions': [ 'conditions': [
@ -49,8 +47,6 @@
'path_win.cc', 'path_win.cc',
'run_loop_win.cc', 'run_loop_win.cc',
'socket_win.cc', 'socket_win.cc',
'win32_window.cc',
'win32_window.h',
], ],
}], }],
], ],

View File

@ -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 <xenia/common.h>
#include <xenia/core/pal.h>
#include <xenia/core/ref.h>
#include <xenia/core/run_loop.h>
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_

View File

@ -19,6 +19,7 @@
#include <xenia/kernel/kernel_state.h> #include <xenia/kernel/kernel_state.h>
#include <xenia/kernel/modules.h> #include <xenia/kernel/modules.h>
#include <xenia/kernel/fs/filesystem.h> #include <xenia/kernel/fs/filesystem.h>
#include <xenia/ui/window.h>
using namespace xe; using namespace xe;
@ -29,9 +30,11 @@ using namespace xe::gpu;
using namespace xe::hid; using namespace xe::hid;
using namespace xe::kernel; using namespace xe::kernel;
using namespace xe::kernel::fs; using namespace xe::kernel::fs;
using namespace xe::ui;
Emulator::Emulator(const xechar_t* command_line) : Emulator::Emulator(const xechar_t* command_line) :
main_window_(0),
memory_(0), memory_(0),
debug_server_(0), debug_server_(0),
processor_(0), processor_(0),
@ -44,6 +47,10 @@ Emulator::Emulator(const xechar_t* command_line) :
Emulator::~Emulator() { Emulator::~Emulator() {
// Note that we delete things in the reverse order they were initialized. // Note that we delete things in the reverse order they were initialized.
if (main_window_) {
main_window_->Close();
}
// Disconnect all debug clients first. // Disconnect all debug clients first.
if (debug_server_) { if (debug_server_) {
debug_server_->Shutdown(); debug_server_->Shutdown();

View File

@ -25,6 +25,7 @@ XEDECLARECLASS2(xe, kernel, KernelState);
XEDECLARECLASS2(xe, kernel, XamModule); XEDECLARECLASS2(xe, kernel, XamModule);
XEDECLARECLASS2(xe, kernel, XboxkrnlModule); XEDECLARECLASS2(xe, kernel, XboxkrnlModule);
XEDECLARECLASS3(xe, kernel, fs, FileSystem); XEDECLARECLASS3(xe, kernel, fs, FileSystem);
XEDECLARECLASS2(xe, ui, Window);
namespace xe { namespace xe {
@ -36,6 +37,10 @@ public:
~Emulator(); ~Emulator();
const xechar_t* command_line() const { return command_line_; } 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_; } Memory* memory() const { return memory_; }
debug::DebugServer* debug_server() const { return debug_server_; } debug::DebugServer* debug_server() const { return debug_server_; }
@ -58,8 +63,11 @@ public:
X_STATUS LaunchDiscImage(const xechar_t* path); X_STATUS LaunchDiscImage(const xechar_t* path);
private: private:
xechar_t command_line_[XE_MAX_PATH]; xechar_t command_line_[XE_MAX_PATH];
Memory* memory_;
ui::Window* main_window_;
Memory* memory_;
debug::DebugServer* debug_server_; debug::DebugServer* debug_server_;

View File

@ -9,6 +9,7 @@
#include <xenia/gpu/d3d11/d3d11_graphics_system.h> #include <xenia/gpu/d3d11/d3d11_graphics_system.h>
#include <xenia/emulator.h>
#include <xenia/gpu/gpu-private.h> #include <xenia/gpu/gpu-private.h>
#include <xenia/gpu/d3d11/d3d11_graphics_driver.h> #include <xenia/gpu/d3d11/d3d11_graphics_driver.h>
#include <xenia/gpu/d3d11/d3d11_window.h> #include <xenia/gpu/d3d11/d3d11_window.h>
@ -122,7 +123,12 @@ void D3D11GraphicsSystem::Initialize() {
// will take place. // will take place.
XEASSERTNULL(window_); XEASSERTNULL(window_);
window_ = new D3D11Window(run_loop_, dxgi_factory_, device_); 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. // Listen for alt-enter/etc.
dxgi_factory_->MakeWindowAssociation(window_->handle(), 0); dxgi_factory_->MakeWindowAssociation(window_->handle(), 0);

View File

@ -11,9 +11,10 @@
using namespace xe; using namespace xe;
using namespace xe::core;
using namespace xe::gpu; using namespace xe::gpu;
using namespace xe::gpu::d3d11; using namespace xe::gpu::d3d11;
using namespace xe::ui;
using namespace xe::ui::win32;
D3D11Window::D3D11Window( D3D11Window::D3D11Window(
@ -29,10 +30,33 @@ D3D11Window::D3D11Window(
swap_chain_ = 0; swap_chain_ = 0;
render_target_view_ = 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. // Setup swap chain.
DXGI_SWAP_CHAIN_DESC desc; DXGI_SWAP_CHAIN_DESC desc;
xe_zero_struct(&desc, sizeof(desc)); xe_zero_struct(&desc, sizeof(desc));
desc.OutputWindow = handle_; desc.OutputWindow = handle();
desc.Windowed = TRUE; desc.Windowed = TRUE;
desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
@ -40,8 +64,8 @@ D3D11Window::D3D11Window(
// Setup buffers. // Setup buffers.
desc.BufferCount = 1; desc.BufferCount = 1;
desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
desc.BufferDesc.Width = width_; desc.BufferDesc.Width = width;
desc.BufferDesc.Height = height_; desc.BufferDesc.Height = height;
desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.BufferDesc.RefreshRate.Numerator = 60; desc.BufferDesc.RefreshRate.Numerator = 60;
desc.BufferDesc.RefreshRate.Denominator = 1; desc.BufferDesc.RefreshRate.Denominator = 1;
@ -57,8 +81,7 @@ D3D11Window::D3D11Window(
&swap_chain_); &swap_chain_);
if (FAILED(hr)) { if (FAILED(hr)) {
XELOGE("CreateSwapChain failed with %.8X", hr); XELOGE("CreateSwapChain failed with %.8X", hr);
exit(1); return 1;
return;
} }
// Create a render target view to draw into. // Create a render target view to draw into.
@ -67,29 +90,18 @@ D3D11Window::D3D11Window(
0, __uuidof(ID3D11Texture2D), (void**)&back_buffer); 0, __uuidof(ID3D11Texture2D), (void**)&back_buffer);
if (FAILED(hr)) { if (FAILED(hr)) {
XELOGE("GetBuffer (back_buffer) failed with %.8X", hr); XELOGE("GetBuffer (back_buffer) failed with %.8X", hr);
exit(1); return 1;
return;
} }
hr = device_->CreateRenderTargetView( hr = device_->CreateRenderTargetView(
back_buffer, NULL, &render_target_view_); back_buffer, NULL, &render_target_view_);
back_buffer->Release(); back_buffer->Release();
if (FAILED(hr)) { if (FAILED(hr)) {
XELOGE("CreateRenderTargetView (back_buffer) failed with %.8X", hr); XELOGE("CreateRenderTargetView (back_buffer) failed with %.8X", hr);
exit(1); return 1;
return;
} }
context_->OMSetRenderTargets(1, &render_target_view_, NULL); context_->OMSetRenderTargets(1, &render_target_view_, NULL);
}
D3D11Window::~D3D11Window() { return 0;
if (context_) {
context_->ClearState();
}
XESAFERELEASE(render_target_view_);
XESAFERELEASE(context_);
XESAFERELEASE(swap_chain_);
XESAFERELEASE(device_);
XESAFERELEASE(dxgi_factory_);
} }
void D3D11Window::Swap() { void D3D11Window::Swap() {
@ -102,13 +114,13 @@ void D3D11Window::Swap() {
} }
} }
void D3D11Window::OnResize(uint32_t width, uint32_t height) { bool D3D11Window::OnResize(uint32_t width, uint32_t height) {
Win32Window::OnResize(width, height); if (!Win32Window::OnResize(width, height)) {
return false;
}
// TODO(benvanik): resize swap buffers? // 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_);
}

View File

@ -12,6 +12,8 @@
#include <xenia/core.h> #include <xenia/core.h>
#include <xenia/ui/win32/win32_window.h>
#include <d3d11.h> #include <d3d11.h>
@ -20,18 +22,19 @@ namespace gpu {
namespace d3d11 { namespace d3d11 {
class D3D11Window : public xe::core::Win32Window { class D3D11Window : public xe::ui::win32::Win32Window {
public: public:
D3D11Window( D3D11Window(
xe_run_loop_ref run_loop, xe_run_loop_ref run_loop,
IDXGIFactory1* dxgi_factory, ID3D11Device* device); IDXGIFactory1* dxgi_factory, ID3D11Device* device);
virtual ~D3D11Window(); virtual ~D3D11Window();
virtual int Initialize(const char* title, uint32_t width, uint32_t height);
void Swap(); void Swap();
protected: protected:
virtual void OnResize(uint32_t width, uint32_t height); virtual bool OnResize(uint32_t width, uint32_t height);
virtual void OnClose();
private: private:
IDXGIFactory1* dxgi_factory_; IDXGIFactory1* dxgi_factory_;

View File

@ -93,7 +93,8 @@ void GraphicsSystem::ThreadStart() {
xe_run_loop_release(run_loop); 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() { void GraphicsSystem::Initialize() {

View File

@ -33,5 +33,6 @@
'gpu/sources.gypi', 'gpu/sources.gypi',
'hid/sources.gypi', 'hid/sources.gypi',
'kernel/sources.gypi', 'kernel/sources.gypi',
'ui/sources.gypi',
], ],
} }

View File

@ -1,23 +1,22 @@
/** /**
****************************************************************************** ******************************************************************************
* Xenia : Xbox 360 Emulator Research Project * * Xenia : Xbox 360 Emulator Research Project *
****************************************************************************** ******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. * * Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. * * Released under the BSD license - see LICENSE in the root for more details. *
****************************************************************************** ******************************************************************************
*/ */
#include <xenia/core/window.h> #include <xenia/ui/menu_item.h>
using namespace xe; using namespace xe;
using namespace xe::core; using namespace xe::ui;
Window::Window(xe_run_loop_ref run_loop) { MenuItem::MenuItem(Window* window, MenuItem* parent_item) :
run_loop_ = xe_run_loop_retain(run_loop); window_(window), parent_item_(parent_item) {
} }
Window::~Window() { MenuItem::~MenuItem() {
xe_run_loop_release(run_loop_); }
}

41
src/xenia/ui/menu_item.h Normal file
View File

@ -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 <xenia/core.h>
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_

18
src/xenia/ui/sources.gypi Normal file
View File

@ -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',
],
}],
],
}

74
src/xenia/ui/ui_event.h Normal file
View File

@ -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 <xenia/core.h>
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_

View File

@ -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',
],
}

View File

@ -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 <xenia/ui/win32/win32_menu_item.h>
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() {
}

View File

@ -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 <xenia/core.h>
#include <xenia/ui/menu_item.h>
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_

View File

@ -1,244 +1,371 @@
/** /**
****************************************************************************** ******************************************************************************
* Xenia : Xbox 360 Emulator Research Project * * Xenia : Xbox 360 Emulator Research Project *
****************************************************************************** ******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. * * Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. * * Released under the BSD license - see LICENSE in the root for more details. *
****************************************************************************** ******************************************************************************
*/ */
#include <xenia/core/win32_window.h> #include <xenia/ui/win32/win32_window.h>
#include <dwmapi.h> #include <dwmapi.h>
#include <tpcshrd.h> #include <tpcshrd.h>
#include <windowsx.h>
using namespace xe;
using namespace xe::core; using namespace xe;
using namespace xe::ui;
using namespace xe::ui::win32;
namespace {
static LRESULT CALLBACK Win32WindowWndProc( namespace {
HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
Win32Window* window = 0; static LRESULT CALLBACK Win32WindowWndProc(
if (message == WM_NCCREATE) { HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
LPCREATESTRUCT create_struct = (LPCREATESTRUCT)lParam; Win32Window* window = 0;
window = (Win32Window*)create_struct->lpCreateParams; if (message == WM_NCCREATE) {
SetWindowLongPtr(hWnd, GWLP_USERDATA, (__int3264)(LONG_PTR)window); LPCREATESTRUCT create_struct = (LPCREATESTRUCT)lParam;
} else { window = (Win32Window*)create_struct->lpCreateParams;
window = (Win32Window*)GetWindowLongPtr(hWnd, GWLP_USERDATA); SetWindowLongPtr(hWnd, GWLP_USERDATA, (__int3264)(LONG_PTR)window);
} } else {
if (window) { window = (Win32Window*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
return window->WndProc(hWnd, message, wParam, lParam); }
} else { if (window) {
return DefWindowProc(hWnd, message, wParam, lParam); 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),
Window(run_loop) { Win32Window::Win32Window(xe_run_loop_ref run_loop) :
Create(); handle_(0), closing_(false),
} Window(run_loop) {
}
Win32Window::~Win32Window() {
if (handle_) { Win32Window::~Win32Window() {
CloseWindow(handle_); if (handle_) {
} CloseWindow(handle_);
} handle_ = NULL;
}
void Win32Window::Create() { }
HINSTANCE hInstance = GetModuleHandle(NULL);
int Win32Window::Initialize(const char* title, uint32_t width, uint32_t height) {
width_ = 1280; int result = Window::Initialize(title, width, height);
height_ = 720; if (result) {
return result;
WNDCLASSEX wcex; }
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW; HINSTANCE hInstance = GetModuleHandle(NULL);
wcex.lpfnWndProc = Win32WindowWndProc;
wcex.cbClsExtra = 0; WNDCLASSEX wcex;
wcex.cbWndExtra = 0; wcex.cbSize = sizeof(WNDCLASSEX);
wcex.hInstance = hInstance; wcex.style = 0;
wcex.hIcon = NULL; // LoadIcon(hInstance, (LPCTSTR)IDI_TUTORIAL1); wcex.lpfnWndProc = Win32WindowWndProc;
wcex.hIconSm = NULL; // LoadIcon(hInstance, (LPCTSTR)IDI_TUTORIAL1); wcex.cbClsExtra = 0;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.cbWndExtra = 0;
wcex.hbrBackground = ( HBRUSH )( COLOR_WINDOW + 1 ); wcex.hInstance = hInstance;
wcex.lpszMenuName = NULL; wcex.hIcon = NULL; // LoadIcon(hInstance, (LPCTSTR)IDI_TUTORIAL1);
wcex.lpszClassName = L"XeniaWindowClass"; wcex.hIconSm = NULL; // LoadIcon(hInstance, (LPCTSTR)IDI_TUTORIAL1);
if (!RegisterClassEx(&wcex)) { wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
XELOGE("RegisterClassEx failed"); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
exit(1); wcex.lpszMenuName = NULL;
return; wcex.lpszClassName = L"XeniaWindowClass";
} if (!RegisterClassEx(&wcex)) {
XELOGE("RegisterClassEx failed");
// Setup initial size. return 1;
DWORD window_style = WS_OVERLAPPEDWINDOW; }
DWORD window_ex_style = WS_EX_APPWINDOW;
RECT rc = { // Setup initial size.
0, 0, DWORD window_style = WS_OVERLAPPEDWINDOW;
width_, height_ DWORD window_ex_style = WS_EX_APPWINDOW;
}; RECT rc = {
AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE); 0, 0,
width, height
// Create window. };
handle_ = CreateWindowEx( AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE);
window_ex_style,
L"XeniaWindowClass", // Create window.
L"Xenia", handle_ = CreateWindowEx(
window_style, window_ex_style,
CW_USEDEFAULT, CW_USEDEFAULT, L"XeniaWindowClass",
rc.right - rc.left, rc.bottom - rc.top, L"Xenia",
NULL, window_style,
NULL, CW_USEDEFAULT, CW_USEDEFAULT,
hInstance, rc.right - rc.left, rc.bottom - rc.top,
this); NULL,
if (!handle_) { NULL,
XELOGE("CreateWindow failed"); hInstance,
exit(1); this);
return; if (!handle_) {
} XELOGE("CreateWindow failed");
return 1;
// Disable flicks. }
ATOM atom = GlobalAddAtom(L"MicrosoftTabletPenServiceProperty");
const DWORD_PTR dwHwndTabletProperty = // Disable flicks.
TABLET_DISABLE_PRESSANDHOLD | // disables press and hold (right-click) gesture ATOM atom = GlobalAddAtom(L"MicrosoftTabletPenServiceProperty");
TABLET_DISABLE_PENTAPFEEDBACK | // disables UI feedback on pen up (waves) const DWORD_PTR dwHwndTabletProperty =
TABLET_DISABLE_PENBARRELFEEDBACK | // disables UI feedback on pen button down (circle) TABLET_DISABLE_PRESSANDHOLD | // disables press and hold (right-click) gesture
TABLET_DISABLE_FLICKS | // disables pen flicks (back, forward, drag down, drag up) TABLET_DISABLE_PENTAPFEEDBACK | // disables UI feedback on pen up (waves)
TABLET_DISABLE_TOUCHSWITCH | TABLET_DISABLE_PENBARRELFEEDBACK | // disables UI feedback on pen button down (circle)
TABLET_DISABLE_SMOOTHSCROLLING | TABLET_DISABLE_FLICKS | // disables pen flicks (back, forward, drag down, drag up)
TABLET_DISABLE_TOUCHUIFORCEON | TABLET_DISABLE_TOUCHSWITCH |
TABLET_ENABLE_MULTITOUCHDATA; TABLET_DISABLE_SMOOTHSCROLLING |
SetProp( TABLET_DISABLE_TOUCHUIFORCEON |
handle_, TABLET_ENABLE_MULTITOUCHDATA;
L"MicrosoftTabletPenServiceProperty", SetProp(
reinterpret_cast<HANDLE>(dwHwndTabletProperty)); handle_,
GlobalDeleteAtom(atom); L"MicrosoftTabletPenServiceProperty",
reinterpret_cast<HANDLE>(dwHwndTabletProperty));
// Enable DWM elevation. GlobalDeleteAtom(atom);
EnableMMCSS();
// Enable DWM elevation.
ShowWindow(handle_, SW_SHOWNORMAL); EnableMMCSS();
UpdateWindow(handle_);
} ShowWindow(handle_, SW_SHOWNORMAL);
UpdateWindow(handle_);
void Win32Window::EnableMMCSS() {
HMODULE hLibrary = LoadLibrary(L"DWMAPI.DLL"); return 0;
if (!hLibrary) { }
return;
} void Win32Window::EnableMMCSS() {
HMODULE hLibrary = LoadLibrary(L"DWMAPI.DLL");
typedef HRESULT (__stdcall *PDwmEnableMMCSS)(BOOL); if (!hLibrary) {
PDwmEnableMMCSS pDwmEnableMMCSS = return;
(PDwmEnableMMCSS)GetProcAddress( }
hLibrary, "DwmEnableMMCSS");
if (pDwmEnableMMCSS) { typedef HRESULT (__stdcall *PDwmEnableMMCSS)(BOOL);
pDwmEnableMMCSS(TRUE); PDwmEnableMMCSS pDwmEnableMMCSS =
} (PDwmEnableMMCSS)GetProcAddress(
hLibrary, "DwmEnableMMCSS");
typedef HRESULT (__stdcall *PDwmSetPresentParameters)(HWND, DWM_PRESENT_PARAMETERS*); if (pDwmEnableMMCSS) {
PDwmSetPresentParameters pDwmSetPresentParameters = pDwmEnableMMCSS(TRUE);
(PDwmSetPresentParameters)GetProcAddress( }
hLibrary, "DwmSetPresentParameters");
if (pDwmSetPresentParameters) { typedef HRESULT (__stdcall *PDwmSetPresentParameters)(HWND, DWM_PRESENT_PARAMETERS*);
DWM_PRESENT_PARAMETERS pp; PDwmSetPresentParameters pDwmSetPresentParameters =
memset(&pp, 0, sizeof(DWM_PRESENT_PARAMETERS)); (PDwmSetPresentParameters)GetProcAddress(
pp.cbSize = sizeof(DWM_PRESENT_PARAMETERS); hLibrary, "DwmSetPresentParameters");
pp.fQueue = FALSE; if (pDwmSetPresentParameters) {
pp.cBuffer = 2; DWM_PRESENT_PARAMETERS pp;
pp.fUseSourceRate = FALSE; memset(&pp, 0, sizeof(DWM_PRESENT_PARAMETERS));
pp.cRefreshesPerFrame = 1; pp.cbSize = sizeof(DWM_PRESENT_PARAMETERS);
pp.eSampling = DWM_SOURCE_FRAME_SAMPLING_POINT; pp.fQueue = FALSE;
pDwmSetPresentParameters(handle_, &pp); pp.cBuffer = 2;
} pp.fUseSourceRate = FALSE;
pp.cRefreshesPerFrame = 1;
FreeLibrary( hLibrary ); pp.eSampling = DWM_SOURCE_FRAME_SAMPLING_POINT;
} pDwmSetPresentParameters(handle_, &pp);
}
void Win32Window::set_title(const xechar_t* title) {
XEIGNORE(SetWindowText(handle_, title)); FreeLibrary(hLibrary);
} }
void Win32Window::Resize(uint32_t width, uint32_t height) { bool Win32Window::set_title(const char* title) {
if (width == width_ && height == height_) { if (!Window::set_title(title)) {
return; return false;
} }
width_ = width; XEIGNORE(SetWindowTextA(handle_, title));
height_ = height; return true;
}
RECT rc = {
0, 0, bool Win32Window::set_cursor_visible(bool value) {
width_, height_ if (!Window::set_cursor_visible(value)) {
}; return false;
AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE); }
// TODO(benvanik): center. if (value) {
MoveWindow(handle_, 0, 0, rc.right - rc.left, rc.bottom - rc.top, TRUE); ShowCursor(TRUE);
SetCursor(NULL);
OnResize(width_, height_); } else {
} ShowCursor(FALSE);
}
void Win32Window::ShowError(const xechar_t* message) { return true;
XEIGNORE(MessageBox(handle_, message, L"Xenia Error", MB_ICONERROR | MB_OK)); }
}
bool Win32Window::SetSize(uint32_t width, uint32_t height) {
LRESULT Win32Window::WndProc(HWND hWnd, UINT message, RECT rc = {
WPARAM wParam, LPARAM lParam) { 0, 0,
switch (message) { width, height
case WM_NCCREATE: };
handle_ = hWnd; AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE);
return DefWindowProc(hWnd, message, wParam, lParam); // TODO(benvanik): center?
case WM_ACTIVATEAPP: MoveWindow(handle_, 0, 0, rc.right - rc.left, rc.bottom - rc.top, TRUE);
if (wParam) { return true;
// Made active. }
} else {
// Made inactive. void Win32Window::OnClose() {
} if (!closing_ && handle_) {
return DefWindowProc(hWnd, message, wParam, lParam); closing_ = true;
case WM_CLOSE: CloseWindow(handle_);
OnClose(); handle_ = NULL;
return DefWindowProc(hWnd, message, wParam, lParam); }
case WM_DESTROY: }
PostQuitMessage(0);
return 0; bool Win32Window::HandleMouse(UINT message, WPARAM wParam, LPARAM lParam) {
int32_t x = GET_X_LPARAM(lParam);
case WM_PAINT: int32_t y = GET_Y_LPARAM(lParam);
{ if (message == WM_MOUSEWHEEL) {
PAINTSTRUCT ps; POINT pt = { x, y };
HDC hdc = BeginPaint(hWnd, &ps); ScreenToClient(handle_, &pt);
EndPaint(hWnd, &ps); x = pt.x;
} y = pt.y;
return 0; }
case WM_ERASEBKGND:
return 0; // ignore MouseEvent::Button button = MouseEvent::MOUSE_BUTTON_NONE;
case WM_DISPLAYCHANGE: int32_t dx = 0;
return DefWindowProc(hWnd, message, wParam, lParam); int32_t dy = 0;
switch (message) {
case WM_MOVE: case WM_LBUTTONDOWN:
return DefWindowProc(hWnd, message, wParam, lParam); case WM_LBUTTONUP:
case WM_SIZE: button = MouseEvent::MOUSE_BUTTON_LEFT;
{ break;
RECT frame; case WM_RBUTTONDOWN:
GetClientRect(handle_, &frame); case WM_RBUTTONUP:
OnResize(frame.right - frame.left, frame.bottom - frame.top); button = MouseEvent::MOUSE_BUTTON_RIGHT;
} break;
return DefWindowProc(hWnd, message, wParam, lParam); case WM_MBUTTONDOWN:
case WM_MBUTTONUP:
case WM_TABLET_QUERYSYSTEMGESTURESTATUS: button = MouseEvent::MOUSE_BUTTON_MIDDLE;
return break;
TABLET_DISABLE_PRESSANDHOLD | // disables press and hold (right-click) gesture case WM_XBUTTONDOWN:
TABLET_DISABLE_PENTAPFEEDBACK | // disables UI feedback on pen up (waves) case WM_XBUTTONUP:
TABLET_DISABLE_PENBARRELFEEDBACK | // disables UI feedback on pen button down (circle) switch (GET_XBUTTON_WPARAM(wParam)) {
TABLET_DISABLE_FLICKS | // disables pen flicks (back, forward, drag down, drag up) case XBUTTON1:
TABLET_DISABLE_TOUCHSWITCH | button = MouseEvent::MOUSE_BUTTON_X1;
TABLET_DISABLE_SMOOTHSCROLLING | break;
TABLET_DISABLE_TOUCHUIFORCEON | case XBUTTON2:
TABLET_ENABLE_MULTITOUCHDATA; button = MouseEvent::MOUSE_BUTTON_X2;
default: break;
return DefWindowProc(hWnd, message, wParam, lParam); 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);
}
}

View File

@ -1,49 +1,55 @@
/** /**
****************************************************************************** ******************************************************************************
* Xenia : Xbox 360 Emulator Research Project * * Xenia : Xbox 360 Emulator Research Project *
****************************************************************************** ******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. * * Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. * * Released under the BSD license - see LICENSE in the root for more details. *
****************************************************************************** ******************************************************************************
*/ */
#ifndef XENIA_CORE_WIN32_WINDOW_H_ #ifndef XENIA_UI_WIN32_WIN32_WINDOW_H_
#define XENIA_CORE_WIN32_WINDOW_H_ #define XENIA_UI_WIN32_WIN32_WINDOW_H_
#include <xenia/common.h> #include <xenia/core.h>
#include <xenia/core/window.h>
#include <xenia/ui/window.h>
namespace xe {
namespace core { namespace xe {
namespace ui {
namespace win32 {
class Win32Window : public Window {
public:
Win32Window(xe_run_loop_ref run_loop); class Win32Window : public Window {
virtual ~Win32Window(); public:
Win32Window(xe_run_loop_ref run_loop);
HWND handle() const { return handle_; } virtual ~Win32Window();
virtual void set_title(const xechar_t* title); virtual int Initialize(const char* title, uint32_t width, uint32_t height);
virtual void Resize(uint32_t width, uint32_t height); virtual bool set_title(const char* title);
virtual bool set_cursor_visible(bool value);
virtual void ShowError(const xechar_t* message); HWND handle() const { return handle_; }
LRESULT WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); LRESULT WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
protected: protected:
HWND handle_; virtual bool SetSize(uint32_t width, uint32_t height);
virtual void OnClose();
private:
void Create(); private:
void EnableMMCSS(); void EnableMMCSS();
}; bool HandleMouse(UINT message, WPARAM wParam, LPARAM lParam);
bool HandleKeyboard(UINT message, WPARAM wParam, LPARAM lParam);
} // namespace core HWND handle_;
} // namespace xe bool closing_;
};
#endif // XENIA_CORE_WIN32_WINDOW_H_
} // namespace win32
} // namespace ui
} // namespace xe
#endif // XENIA_UI_WIN32_WIN32_WINDOW_H_

120
src/xenia/ui/window.cc Normal file
View File

@ -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 <xenia/ui/window.h>
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() {
}

82
src/xenia/ui/window.h Normal file
View File

@ -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 <xenia/core.h>
#include <alloy/delegate.h>
#include <xenia/ui/ui_event.h>
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<UIEvent> shown;
alloy::Delegate<UIEvent> hidden;
alloy::Delegate<UIEvent> resizing;
alloy::Delegate<UIEvent> resized;
alloy::Delegate<UIEvent> closing;
alloy::Delegate<UIEvent> closed;
alloy::Delegate<MouseEvent> mouse_down;
alloy::Delegate<MouseEvent> mouse_move;
alloy::Delegate<MouseEvent> mouse_up;
alloy::Delegate<MouseEvent> 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_