diff --git a/src/xenia/ui/main_window.cc b/src/xenia/ui/main_window.cc index 1ddbc26f8..3fd96f616 100644 --- a/src/xenia/ui/main_window.cc +++ b/src/xenia/ui/main_window.cc @@ -24,7 +24,8 @@ const std::wstring kBaseTitle = L"xenia"; MainWindow::MainWindow(Emulator* emulator) : PlatformWindow(kBaseTitle), emulator_(emulator), - main_menu_(MenuItem::Type::kNormal) {} + main_menu_(MenuItem::Type::kNormal), + fullscreen_(false) {} MainWindow::~MainWindow() = default; @@ -63,6 +64,16 @@ bool MainWindow::Initialize() { emulator()->graphics_system()->ClearCaches(); break; } + case 0x7A: { // VK_F11 + ToggleFullscreen(); + break; + } + case 0x1B: { // VK_ESCAPE + // Allow users to escape fullscreen (but not enter it) + if (fullscreen_) { + ToggleFullscreen(); + } + } case 0x6D: { // numpad minus Clock::set_guest_time_scalar(Clock::guest_time_scalar() / 2.0); UpdateTitle(); @@ -94,6 +105,15 @@ bool MainWindow::Initialize() { main_menu_.AddChild(std::move(file)); + // Window submenu + auto window = + std::make_unique(MenuItem::Type::kPopup, L"&Window"); + window->AddChild(std::make_unique( + MenuItem::Type::kString, Commands::IDC_WINDOW_FULLSCREEN, + L"Fullscreen\tF11")); + + main_menu_.AddChild(std::move(window)); + SetMenu(&main_menu_); Resize(1280, 720); @@ -111,6 +131,11 @@ void MainWindow::UpdateTitle() { set_title(title); } +void MainWindow::ToggleFullscreen() { + fullscreen_ = !fullscreen_; + SetFullscreen(fullscreen_); +} + void MainWindow::OnClose() { loop_.Quit(); @@ -119,7 +144,15 @@ void MainWindow::OnClose() { exit(1); } -void MainWindow::OnCommand(int id) {} +void MainWindow::OnCommand(int id) { + switch (id) { + // TODO: Setup delegates to MenuItems so we don't have to do this + case IDC_WINDOW_FULLSCREEN: { + ToggleFullscreen(); + break; + } + } +} X_STATUS MainWindow::LaunchPath(std::wstring path) { X_STATUS result; diff --git a/src/xenia/ui/main_window.h b/src/xenia/ui/main_window.h index 7fdf82e9e..d5d6f8531 100644 --- a/src/xenia/ui/main_window.h +++ b/src/xenia/ui/main_window.h @@ -45,17 +45,21 @@ class MainWindow : public PlatformWindow { bool Initialize(); void UpdateTitle(); + void ToggleFullscreen(); void OnClose() override; void OnCommand(int id) override; enum Commands { IDC_FILE_OPEN, + + IDC_WINDOW_FULLSCREEN, }; Emulator* emulator_; PlatformLoop loop_; PlatformMenu main_menu_; + bool fullscreen_; }; } // namespace ui diff --git a/src/xenia/ui/win32/win32_window.cc b/src/xenia/ui/win32/win32_window.cc index 67cced1b3..56d973b6e 100644 --- a/src/xenia/ui/win32/win32_window.cc +++ b/src/xenia/ui/win32/win32_window.cc @@ -20,7 +20,7 @@ namespace ui { namespace win32 { Win32Window::Win32Window(const std::wstring& title) - : Window(title), closing_(false) { + : Window(title), closing_(false), fullscreen_(false) { menu_ = nullptr; } @@ -159,6 +159,36 @@ void Win32Window::ResizeToFill(int32_t pad_left, int32_t pad_top, // TODO(benvanik): fullscreen. } +void Win32Window::SetFullscreen(bool fullscreen) { + fullscreen_ = fullscreen; + + DWORD style = GetWindowLong(hwnd_, GWL_STYLE); + if (fullscreen) { + // Kill our borders and resize to take up entire primary monitor + // http://blogs.msdn.com/b/oldnewthing/archive/2010/04/12/9994016.aspx + MONITORINFO mi = {sizeof(mi)}; + if (GetWindowPlacement(hwnd_, &windowed_pos_) && + GetMonitorInfo(MonitorFromWindow(hwnd_, MONITOR_DEFAULTTOPRIMARY), + &mi)) { + SetWindowLong(hwnd_, GWL_STYLE, style & ~WS_OVERLAPPEDWINDOW); + ::SetMenu(hwnd_, NULL); + + // Call into parent class to get around menu resizing code + Window::Resize(mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right, + mi.rcMonitor.bottom); + } + } else { + // Reinstate borders, resize to 1280x720 + SetWindowLong(hwnd_, GWL_STYLE, style | WS_OVERLAPPEDWINDOW); + SetWindowPlacement(hwnd_, &windowed_pos_); + + Win32MenuItem* win_menu = reinterpret_cast(menu_); + if (win_menu) { + ::SetMenu(hwnd_, win_menu->handle()); + } + } +} + void Win32Window::OnClose() { if (!closing_ && hwnd_) { closing_ = true; @@ -168,7 +198,8 @@ void Win32Window::OnClose() { void Win32Window::OnSetMenu(MenuItem* menu) { Win32MenuItem* win_menu = reinterpret_cast(menu); - if (win_menu) { + // Don't actually set the menu if we're fullscreen. We'll do that later. + if (win_menu && !fullscreen_) { ::SetMenu(hwnd_, win_menu->handle()); } } @@ -203,6 +234,7 @@ LRESULT Win32Window::WndProc(HWND hWnd, UINT message, WPARAM wParam, TABLET_DISABLE_TOUCHUIFORCEON | TABLET_ENABLE_MULTITOUCHDATA; case WM_COMMAND: { + // TODO: Redirect this to MenuItem's on_selected delegate. OnCommand(LOWORD(wParam)); } break; } diff --git a/src/xenia/ui/win32/win32_window.h b/src/xenia/ui/win32/win32_window.h index 4e1f6a7dd..eddb2f744 100644 --- a/src/xenia/ui/win32/win32_window.h +++ b/src/xenia/ui/win32/win32_window.h @@ -35,6 +35,8 @@ class Win32Window : public Window { void ResizeToFill(int32_t pad_left, int32_t pad_top, int32_t pad_right, int32_t pad_bottom) override; + void SetFullscreen(bool fullscreen) override; + protected: bool Create() override; void OnClose() override; @@ -48,6 +50,9 @@ class Win32Window : public Window { void EnableMMCSS(); bool closing_; + + bool fullscreen_; + WINDOWPLACEMENT windowed_pos_; }; } // namespace win32 diff --git a/src/xenia/ui/window.h b/src/xenia/ui/window.h index 5bf323ccb..aa98f2175 100644 --- a/src/xenia/ui/window.h +++ b/src/xenia/ui/window.h @@ -52,6 +52,8 @@ class Window : public T { OnSetMenu(menu); } + virtual void SetFullscreen(bool fullscreen) {} + public: Delegate on_shown; Delegate on_hidden;