diff --git a/src/xenia/app/premake5.lua b/src/xenia/app/premake5.lua index a99fec0cc..66f8beaa2 100644 --- a/src/xenia/app/premake5.lua +++ b/src/xenia/app/premake5.lua @@ -73,7 +73,6 @@ project("xenia-app") "X11", "xcb", "X11-xcb", - "vulkan", "SDL2", }) diff --git a/src/xenia/cpu/hir/value.cc b/src/xenia/cpu/hir/value.cc index 28ed07ee7..08de8af9b 100644 --- a/src/xenia/cpu/hir/value.cc +++ b/src/xenia/cpu/hir/value.cc @@ -395,9 +395,8 @@ void Value::MulHi(Value* other, bool is_unsigned) { (uint32_t)other->constant.i32) >> 32); } else { - constant.i32 = - (int32_t)(((int64_t)constant.i32 * (int64_t)other->constant.i32) >> - 32); + constant.i32 = (int32_t)( + ((int64_t)constant.i32 * (int64_t)other->constant.i32) >> 32); } break; case INT64_TYPE: diff --git a/src/xenia/cpu/ppc/ppc_emit_control.cc b/src/xenia/cpu/ppc/ppc_emit_control.cc index ec09ea458..eafd15492 100644 --- a/src/xenia/cpu/ppc/ppc_emit_control.cc +++ b/src/xenia/cpu/ppc/ppc_emit_control.cc @@ -810,6 +810,6 @@ void RegisterEmitCategoryControl() { XEREGISTERINSTR(mtmsrd); } -} // namespace ppc +} // namespace cpu } // namespace cpu } // namespace xe diff --git a/src/xenia/cpu/xex_module.cc b/src/xenia/cpu/xex_module.cc index 672d44666..aed4f4cb9 100644 --- a/src/xenia/cpu/xex_module.cc +++ b/src/xenia/cpu/xex_module.cc @@ -832,10 +832,9 @@ int XexModule::ReadPEHeaders() { // offsetof seems to be unable to find OptionalHeader. #define offsetof1(type, member) ((std::size_t) & (((type*)0)->member)) #define IMAGE_FIRST_SECTION1(ntheader) \ - ((PIMAGE_SECTION_HEADER)((uint8_t*)ntheader + \ - offsetof1(IMAGE_NT_HEADERS, OptionalHeader) + \ - ((PIMAGE_NT_HEADERS)(ntheader)) \ - ->FileHeader.SizeOfOptionalHeader)) + ((PIMAGE_SECTION_HEADER)( \ + (uint8_t*)ntheader + offsetof1(IMAGE_NT_HEADERS, OptionalHeader) + \ + ((PIMAGE_NT_HEADERS)(ntheader))->FileHeader.SizeOfOptionalHeader)) // Quick scan to determine bounds of sections. size_t upper_address = 0; diff --git a/src/xenia/gpu/vulkan/premake5.lua b/src/xenia/gpu/vulkan/premake5.lua index 12efb5174..7db3b21f8 100644 --- a/src/xenia/gpu/vulkan/premake5.lua +++ b/src/xenia/gpu/vulkan/premake5.lua @@ -70,8 +70,6 @@ project("xenia-gpu-vulkan-trace-viewer") "X11", "xcb", "X11-xcb", - "GL", - "vulkan", }) filter("platforms:Windows") @@ -138,8 +136,6 @@ project("xenia-gpu-vulkan-trace-dump") "X11", "xcb", "X11-xcb", - "GL", - "vulkan", }) filter("platforms:Windows") diff --git a/src/xenia/gpu/vulkan/vulkan_graphics_system.cc b/src/xenia/gpu/vulkan/vulkan_graphics_system.cc index fdb5b485a..f789e531d 100644 --- a/src/xenia/gpu/vulkan/vulkan_graphics_system.cc +++ b/src/xenia/gpu/vulkan/vulkan_graphics_system.cc @@ -271,7 +271,7 @@ VulkanGraphicsSystem::CreateCommandProcessor() { } void VulkanGraphicsSystem::Swap(xe::ui::UIEvent* e) { - if (!command_processor_) { + if (!command_processor_ || !display_context_) { return; } diff --git a/src/xenia/kernel/xam/xam_user.cc b/src/xenia/kernel/xam/xam_user.cc index aed0c765b..2a1d3c3f7 100644 --- a/src/xenia/kernel/xam/xam_user.cc +++ b/src/xenia/kernel/xam/xam_user.cc @@ -277,9 +277,8 @@ uint32_t xeXamUserReadProfileSettingsEx(uint32_t title_id, uint32_t user_index, auto setting = user_profile->GetSetting(setting_id); std::memset(out_setting, 0, sizeof(X_USER_READ_PROFILE_SETTING)); - out_setting->from = !setting || !setting->is_set ? 0 - : setting->is_title_specific() ? 2 - : 1; + out_setting->from = + !setting || !setting->is_set ? 0 : setting->is_title_specific() ? 2 : 1; out_setting->user_index = static_cast(user_index); out_setting->setting_id = setting_id; diff --git a/src/xenia/ui/loop_gtk.cc b/src/xenia/ui/loop_gtk.cc index 4a753c853..a2b704aeb 100644 --- a/src/xenia/ui/loop_gtk.cc +++ b/src/xenia/ui/loop_gtk.cc @@ -17,15 +17,6 @@ namespace xe { namespace ui { -class PostedFn { - public: - explicit PostedFn(std::function fn) : fn_(std::move(fn)) {} - void Call() { fn_(); } - - private: - std::function fn_; -}; - std::unique_ptr Loop::Create() { return std::make_unique(); } GTKLoop::GTKLoop() : thread_id_() { @@ -56,24 +47,33 @@ bool GTKLoop::is_on_loop_thread() { } gboolean _posted_fn_thunk(gpointer posted_fn) { - PostedFn* Fn = reinterpret_cast(posted_fn); - Fn->Call(); + // convert gpointer back to std::function, call it, then free std::function + std::function* f = + reinterpret_cast*>(posted_fn); + std::function& func = *f; + func(); + delete f; + // Tells GDK we don't want to run this again return G_SOURCE_REMOVE; } void GTKLoop::Post(std::function fn) { assert_true(thread_id_ != std::thread::id()); - gdk_threads_add_idle(_posted_fn_thunk, - reinterpret_cast(new PostedFn(std::move(fn)))); + // converting std::function to a generic pointer for gdk + gdk_threads_add_idle(_posted_fn_thunk, reinterpret_cast( + new std::function(fn))); } void GTKLoop::PostDelayed(std::function fn, uint64_t delay_millis) { gdk_threads_add_timeout( delay_millis, _posted_fn_thunk, - reinterpret_cast(new PostedFn(std::move(fn)))); + reinterpret_cast(new std::function(fn))); } -void GTKLoop::Quit() { assert_true(thread_id_ != std::thread::id()); } +void GTKLoop::Quit() { + assert_true(thread_id_ != std::thread::id()); + Post([]() { gtk_main_quit(); }); +} void GTKLoop::AwaitQuit() { quit_fence_.Wait(); } diff --git a/src/xenia/ui/vulkan/premake5.lua b/src/xenia/ui/vulkan/premake5.lua index d9f02318c..3f675ad0a 100644 --- a/src/xenia/ui/vulkan/premake5.lua +++ b/src/xenia/ui/vulkan/premake5.lua @@ -56,6 +56,4 @@ project("xenia-ui-window-vulkan-demo") "X11", "xcb", "X11-xcb", - "GL", - "vulkan", }) diff --git a/src/xenia/ui/vulkan/vulkan_context.cc b/src/xenia/ui/vulkan/vulkan_context.cc index d7c1cff4d..50a4e7a8a 100644 --- a/src/xenia/ui/vulkan/vulkan_context.cc +++ b/src/xenia/ui/vulkan/vulkan_context.cc @@ -25,7 +25,7 @@ #include "xenia/ui/vulkan/vulkan_util.h" #include "xenia/ui/window.h" -#if XE_PLATFORM_LINUX +#if XE_PLATFORM_GNU_LINUX #include "xenia/ui/window_gtk.h" #include @@ -71,14 +71,10 @@ bool VulkanContext::Initialize() { status = ifn.vkCreateWin32SurfaceKHR(*provider->instance(), &create_info, nullptr, &surface); CheckResult(status, "vkCreateWin32SurfaceKHR"); -#elif XE_PLATFORM_LINUX +#elif XE_PLATFORM_GNU_LINUX #ifdef GDK_WINDOWING_X11 GtkWidget* window_handle = - static_cast(target_window_->native_handle()); - GdkDisplay* gdk_display = gtk_widget_get_display(window_handle); - assert(GDK_IS_X11_DISPLAY(gdk_display)); - xcb_connection_t* connection = - XGetXCBConnection(gdk_x11_display_get_xdisplay(gdk_display)); + dynamic_cast(target_window_)->native_window_handle(); xcb_window_t window = gdk_x11_window_get_xid(gtk_widget_get_window(window_handle)); VkXcbSurfaceCreateInfoKHR create_info; diff --git a/src/xenia/ui/vulkan/vulkan_instance.cc b/src/xenia/ui/vulkan/vulkan_instance.cc index 36064528e..0ccbba7fa 100644 --- a/src/xenia/ui/vulkan/vulkan_instance.cc +++ b/src/xenia/ui/vulkan/vulkan_instance.cc @@ -32,7 +32,7 @@ #include "xenia/base/platform_win.h" #endif -#if XE_PLATFORM_LINUX +#if XE_PLATFORM_GNU_LINUX #include "xenia/ui/window_gtk.h" #endif diff --git a/src/xenia/ui/vulkan/vulkan_provider.cc b/src/xenia/ui/vulkan/vulkan_provider.cc index 119f03992..f9e9eea13 100644 --- a/src/xenia/ui/vulkan/vulkan_provider.cc +++ b/src/xenia/ui/vulkan/vulkan_provider.cc @@ -52,11 +52,16 @@ bool VulkanProvider::Initialize() { instance_ = std::make_unique(); // Always enable the swapchain. -#if XE_PLATFORM_WIN32 +#if XE_PLATFORM_GNU_LINUX || XE_PLATFORM_WIN32 instance_->DeclareRequiredExtension("VK_KHR_surface", Version::Make(0, 0, 0), false); +#if XE_PLATFORM_GNU_LINUX + instance_->DeclareRequiredExtension("VK_KHR_xcb_surface", + Version::Make(0, 0, 0), false); +#elif XE_PLATFORM_WIN32 instance_->DeclareRequiredExtension("VK_KHR_win32_surface", Version::Make(0, 0, 0), false); +#endif #endif // Attempt initialization and device query. diff --git a/src/xenia/ui/window.h b/src/xenia/ui/window.h index accdc65b9..56094553b 100644 --- a/src/xenia/ui/window.h +++ b/src/xenia/ui/window.h @@ -14,6 +14,7 @@ #include #include "xenia/base/delegate.h" +#include "xenia/base/platform.h" #include "xenia/ui/graphics_context.h" #include "xenia/ui/loop.h" #include "xenia/ui/menu_item.h" @@ -172,8 +173,16 @@ class Window { Loop* loop_ = nullptr; std::unique_ptr main_menu_; std::string title_; +#ifdef XE_PLATFORM_GNU_LINUX + // GTK must have a default value here that isn't 0 + // TODO(Triang3l): Cleanup and unify this. May need to get the first resize + // message on various platforms. + int32_t width_ = 1280; + int32_t height_ = 720; +#else int32_t width_ = 0; int32_t height_ = 0; +#endif bool has_focus_ = true; bool is_cursor_visible_ = true; bool is_imgui_input_enabled_ = false; diff --git a/src/xenia/ui/window_demo.cc b/src/xenia/ui/window_demo.cc index dd191fa7f..4f94a1fc3 100644 --- a/src/xenia/ui/window_demo.cc +++ b/src/xenia/ui/window_demo.cc @@ -71,7 +71,7 @@ int window_demo_main(const std::vector& args) { std::unique_ptr graphics_provider; loop->PostSynchronous([&window, &graphics_provider]() { // Create graphics provider and an initial context for the window. - // The window will finish initialization wtih the context (loading + // The window will finish initialization with the context (loading // resources, etc). graphics_provider = CreateDemoGraphicsProvider(window.get()); window->set_context(graphics_provider->CreateContext(window.get())); diff --git a/src/xenia/ui/window_gtk.cc b/src/xenia/ui/window_gtk.cc index 9dbeccad5..cf272619b 100644 --- a/src/xenia/ui/window_gtk.cc +++ b/src/xenia/ui/window_gtk.cc @@ -7,9 +7,13 @@ ****************************************************************************** */ +#include #include +#include + #include "xenia/base/assert.h" +#include "xenia/base/clock.h" #include "xenia/base/logging.h" #include "xenia/base/platform_linux.h" #include "xenia/ui/virtual_key.h" @@ -18,15 +22,6 @@ namespace xe { namespace ui { -class FnWrapper { - public: - explicit FnWrapper(std::function fn) : fn_(std::move(fn)) {} - void Call() { fn_(); } - - private: - std::function fn_; -}; - std::unique_ptr Window::Create(Loop* loop, const std::string& title) { return std::make_unique(loop, title); } @@ -37,14 +32,16 @@ GTKWindow::GTKWindow(Loop* loop, const std::string& title) GTKWindow::~GTKWindow() { OnDestroy(); if (window_) { - gtk_widget_destroy(window_); + if (GTK_IS_WIDGET(window_)) { + gtk_widget_destroy(window_); + } window_ = nullptr; } } bool GTKWindow::Initialize() { return OnCreate(); } -void gtk_event_handler_(GtkWidget* widget, GdkEvent* event, gpointer data) { +gboolean gtk_event_handler(GtkWidget* widget, GdkEvent* event, gpointer data) { GTKWindow* window = reinterpret_cast(data); switch (event->type) { case GDK_OWNER_CHANGE: @@ -58,30 +55,80 @@ void gtk_event_handler_(GtkWidget* widget, GdkEvent* event, gpointer data) { window->HandleKeyboard(&(event->key)); break; case GDK_SCROLL: - case GDK_BUTTON_PRESS: case GDK_MOTION_NOTIFY: + case GDK_BUTTON_PRESS: + case GDK_BUTTON_RELEASE: window->HandleMouse(&(event->any)); break; case GDK_FOCUS_CHANGE: window->HandleWindowFocus(&(event->focus_change)); break; case GDK_CONFIGURE: - window->HandleWindowResize(&(event->configure)); + // Only handle the event for the drawing area so we don't save + // a width and height that includes the menu bar on the full window + if (event->configure.window == + gtk_widget_get_window(window->drawing_area_)) { + window->HandleWindowResize(&(event->configure)); + } + break; default: // Do nothing - return; + break; } + // Propagate the event to other handlers + return GDK_EVENT_PROPAGATE; +} + +gboolean draw_callback(GtkWidget* widget, GdkFrameClock* frame_clock, + gpointer data) { + GTKWindow* window = reinterpret_cast(data); + window->HandleWindowPaint(); + return G_SOURCE_CONTINUE; +} + +gboolean close_callback(GtkWidget* widget, gpointer data) { + GTKWindow* window = reinterpret_cast(data); + window->Close(); + return G_SOURCE_CONTINUE; } void GTKWindow::Create() { + // GTK optionally allows passing argv and argc here for parsing gtk specific + // options. We won't bother window_ = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_title(GTK_WINDOW(window_), (gchar*)title_.c_str()); - gtk_window_set_default_size(GTK_WINDOW(window_), 1280, 720); - gtk_widget_show_all(window_); - g_signal_connect(G_OBJECT(window_), "destroy", G_CALLBACK(gtk_main_quit), - NULL); - g_signal_connect(G_OBJECT(window_), "event", G_CALLBACK(gtk_event_handler_), + gtk_window_set_resizable(GTK_WINDOW(window_), true); + gtk_window_set_title(GTK_WINDOW(window_), title_.c_str()); + gtk_window_set_default_size(GTK_WINDOW(window_), width_, height_); + // Drawing area is where we will attach our vulkan/gl context + drawing_area_ = gtk_drawing_area_new(); + // tick callback is for the refresh rate of the window + gtk_widget_add_tick_callback(drawing_area_, draw_callback, + reinterpret_cast(this), nullptr); + // Attach our event handler to both the main window (for keystrokes) and the + // drawing area (for mouse input, resize event, etc) + g_signal_connect(G_OBJECT(drawing_area_), "event", + G_CALLBACK(gtk_event_handler), reinterpret_cast(this)); + + GdkDisplay* gdk_display = gtk_widget_get_display(window_); + assert(GDK_IS_X11_DISPLAY(gdk_display)); + connection_ = XGetXCBConnection(gdk_x11_display_get_xdisplay(gdk_display)); + + g_signal_connect(G_OBJECT(window_), "event", G_CALLBACK(gtk_event_handler), + reinterpret_cast(this)); + // When the window manager kills the window (ie, the user hits X) + g_signal_connect(G_OBJECT(window_), "destroy", G_CALLBACK(close_callback), + reinterpret_cast(this)); + // Enable only keyboard events (so no mouse) for the top window + gtk_widget_set_events(window_, GDK_KEY_PRESS | GDK_KEY_RELEASE); + // Enable all events for the drawing area + gtk_widget_add_events(drawing_area_, GDK_ALL_EVENTS_MASK); + // Place the drawing area in a container (which later will hold the menu) + // then let it fill the whole area + box_ = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); + gtk_box_pack_end(GTK_BOX(box_), drawing_area_, TRUE, TRUE, 0); + gtk_container_add(GTK_CONTAINER(window_), box_); + gtk_widget_show_all(window_); } bool GTKWindow::OnCreate() { @@ -94,8 +141,6 @@ void GTKWindow::OnDestroy() { super::OnDestroy(); } void GTKWindow::OnClose() { if (!closing_ && window_) { closing_ = true; - gtk_widget_destroy(window_); - window_ = nullptr; } super::OnClose(); } @@ -123,7 +168,6 @@ void GTKWindow::ToggleFullscreen(bool fullscreen) { } fullscreen_ = fullscreen; - if (fullscreen) { gtk_window_fullscreen(GTK_WINDOW(window_)); } else { @@ -140,7 +184,6 @@ void GTKWindow::set_bordered(bool enabled) { // Don't screw with the borders if we're fullscreen. return; } - gtk_window_set_decorated(GTK_WINDOW(window_), enabled); } @@ -171,31 +214,30 @@ void GTKWindow::set_focus(bool value) { } void GTKWindow::Resize(int32_t width, int32_t height) { + if (is_fullscreen()) { + // Cannot resize while in fullscreen. + return; + } gtk_window_resize(GTK_WINDOW(window_), width, height); + super::Resize(width, height); } void GTKWindow::Resize(int32_t left, int32_t top, int32_t right, int32_t bottom) { - // TODO(dougvj) Verify that this is the desired behavior from this call + if (is_fullscreen()) { + // Cannot resize while in fullscreen. + return; + } gtk_window_move(GTK_WINDOW(window_), left, top); - gtk_window_resize(GTK_WINDOW(window_), left - right, top - bottom); + gtk_window_resize(GTK_WINDOW(window_), right - left, bottom - top); + super::Resize(left, top, right, bottom); } -void GTKWindow::OnResize(UIEvent* e) { - int32_t width; - int32_t height; - gtk_window_get_size(GTK_WINDOW(window_), &width, &height); - if (width != width_ || height != height_) { - width_ = width; - height_ = height; - Layout(); - } - super::OnResize(e); -} +void GTKWindow::OnResize(UIEvent* e) { super::OnResize(e); } void GTKWindow::Invalidate() { + // gtk_widget_queue_draw(drawing_area_); super::Invalidate(); - // TODO(dougvj) I am not sure what this is supposed to do } void GTKWindow::Close() { @@ -203,20 +245,22 @@ void GTKWindow::Close() { return; } closing_ = true; - Close(); OnClose(); + gtk_widget_destroy(window_); + window_ = nullptr; } void GTKWindow::OnMainMenuChange() { // We need to store the old handle for detachment - static GtkWidget* box = nullptr; + static int count = 0; auto main_menu = reinterpret_cast(main_menu_.get()); - if (main_menu && !is_fullscreen()) { - if (box) gtk_widget_destroy(box); - GtkWidget* menu = main_menu->handle(); - box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5); - gtk_box_pack_start(GTK_BOX(box), menu, FALSE, FALSE, 3); - gtk_container_add(GTK_CONTAINER(window_), box); + if (main_menu && main_menu->handle()) { + if (!is_fullscreen()) { + gtk_box_pack_start(GTK_BOX(box_), main_menu->handle(), FALSE, FALSE, 0); + gtk_widget_show_all(window_); + } else { + gtk_container_remove(GTK_CONTAINER(box_), main_menu->handle()); + } } } @@ -234,9 +278,22 @@ bool GTKWindow::HandleWindowOwnerChange(GdkEventOwnerChange* event) { return false; } +bool GTKWindow::HandleWindowPaint() { + auto e = UIEvent(this); + OnPaint(&e); + return true; +} + bool GTKWindow::HandleWindowResize(GdkEventConfigure* event) { if (event->type == GDK_CONFIGURE) { + int32_t width = event->width; + int32_t height = event->height; auto e = UIEvent(this); + if (width != width_ || height != height_) { + width_ = width; + height_ = height; + Layout(); + } OnResize(&e); return true; } @@ -351,6 +408,7 @@ bool GTKWindow::HandleKeyboard(GdkEventKey* event) { bool ctrl_pressed = modifiers & GDK_CONTROL_MASK; bool alt_pressed = modifiers & GDK_META_MASK; bool super_pressed = modifiers & GDK_SUPER_MASK; + uint32_t key_char = gdk_keyval_to_unicode(event->keyval); // TODO(Triang3l): event->hardware_keycode to VirtualKey translation. auto e = KeyEvent(this, VirtualKey(event->hardware_keycode), 1, event->type == GDK_KEY_RELEASE, shift_pressed, ctrl_pressed, @@ -358,12 +416,13 @@ bool GTKWindow::HandleKeyboard(GdkEventKey* event) { switch (event->type) { case GDK_KEY_PRESS: OnKeyDown(&e); + if (key_char > 0) { + OnKeyChar(&e); + } break; case GDK_KEY_RELEASE: OnKeyUp(&e); break; - // TODO(dougvj) GDK doesn't have a KEY CHAR event, so we will have to - // figure out its equivalent here to call OnKeyChar(&e); default: return false; } @@ -377,23 +436,35 @@ std::unique_ptr MenuItem::Create(Type type, return std::make_unique(type, text, hotkey, callback); } -static void _menu_activate_callback(GtkWidget* menu, gpointer data) { - auto fn = reinterpret_cast(data); - fn->Call(); - delete fn; +static void _menu_activate_callback(GtkWidget* gtk_menu, gpointer data) { + GTKMenuItem* menu = reinterpret_cast(data); + menu->Activate(); +} + +void GTKMenuItem::Activate() { + try { + callback_(); + } catch (const std::bad_function_call& e) { + // Ignore + } } GTKMenuItem::GTKMenuItem(Type type, const std::string& text, const std::string& hotkey, std::function callback) : MenuItem(type, text, hotkey, std::move(callback)) { + std::string label = text; + // TODO(dougvj) Would we ever need to escape underscores? + // Replace & with _ for gtk to see the memonic + std::replace(label.begin(), label.end(), '&', '_'); + const gchar* gtk_label = reinterpret_cast(label.c_str()); switch (type) { case MenuItem::Type::kNormal: default: menu_ = gtk_menu_bar_new(); break; case MenuItem::Type::kPopup: - menu_ = gtk_menu_item_new_with_label((gchar*)text.c_str()); + menu_ = gtk_menu_item_new_with_mnemonic(gtk_label); break; case MenuItem::Type::kSeparator: menu_ = gtk_separator_menu_item_new(); @@ -403,12 +474,12 @@ GTKMenuItem::GTKMenuItem(Type type, const std::string& text, if (!hotkey.empty()) { full_name += "\t" + hotkey; } - menu_ = gtk_menu_item_new_with_label((gchar*)full_name.c_str()); + menu_ = gtk_menu_item_new_with_mnemonic(gtk_label); break; } if (GTK_IS_MENU_ITEM(menu_)) g_signal_connect(menu_, "activate", G_CALLBACK(_menu_activate_callback), - (gpointer) new FnWrapper(callback)); + (gpointer)this); } GTKMenuItem::~GTKMenuItem() { @@ -456,4 +527,5 @@ void GTKMenuItem::OnChildRemoved(MenuItem* generic_child_item) { } } // namespace ui + } // namespace xe diff --git a/src/xenia/ui/window_gtk.h b/src/xenia/ui/window_gtk.h index c20c0d5d6..27a4c08b0 100644 --- a/src/xenia/ui/window_gtk.h +++ b/src/xenia/ui/window_gtk.h @@ -15,6 +15,7 @@ #include #include +#include #include "xenia/base/platform_linux.h" #include "xenia/ui/menu_item.h" @@ -31,9 +32,10 @@ class GTKWindow : public Window { ~GTKWindow() override; NativePlatformHandle native_platform_handle() const override { - return nullptr; + return connection_; } NativeWindowHandle native_handle() const override { return window_; } + GtkWidget* native_window_handle() const { return drawing_area_; } void EnableMainMenu() override {} void DisableMainMenu() override {} @@ -74,14 +76,22 @@ class GTKWindow : public Window { private: void Create(); GtkWidget* window_; + GtkWidget* box_; + GtkWidget* drawing_area_; + xcb_connection_t* connection_; + + // C Callback shims for GTK + friend gboolean gtk_event_handler(GtkWidget*, GdkEvent*, gpointer); + friend gboolean close_callback(GtkWidget*, gpointer); + friend gboolean draw_callback(GtkWidget*, GdkFrameClock*, gpointer); - friend void gtk_event_handler_(GtkWidget*, GdkEvent*, gpointer); bool HandleMouse(GdkEventAny* event); bool HandleKeyboard(GdkEventKey* event); bool HandleWindowResize(GdkEventConfigure* event); bool HandleWindowFocus(GdkEventFocus* event); bool HandleWindowVisibility(GdkEventVisibility* event); bool HandleWindowOwnerChange(GdkEventOwnerChange* event); + bool HandleWindowPaint(); bool closing_ = false; bool fullscreen_ = false; @@ -95,6 +105,7 @@ class GTKMenuItem : public MenuItem { GtkWidget* handle() { return menu_; } using MenuItem::OnSelected; + void Activate(); void EnableMenuItem(Window& window) override {} void DisableMenuItem(Window& window) override {} diff --git a/src/xenia/ui/window_win.cc b/src/xenia/ui/window_win.cc index c5bfc780a..a88cad529 100644 --- a/src/xenia/ui/window_win.cc +++ b/src/xenia/ui/window_win.cc @@ -447,6 +447,7 @@ void Win32Window::Close() { closing_ = true; OnClose(); DestroyWindow(hwnd_); + hwnd_ = nullptr; } void Win32Window::OnMainMenuChange() {