diff options
Diffstat (limited to 'platform/windows/display_server_windows.cpp')
-rw-r--r-- | platform/windows/display_server_windows.cpp | 92 |
1 files changed, 76 insertions, 16 deletions
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index 93cab85441..32af329d09 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -607,8 +607,11 @@ void DisplayServerWindows::show_window(WindowID p_id) { _update_window_style(p_id); } - ShowWindow(wd.hWnd, (wd.no_focus || wd.is_popup) ? SW_SHOWNOACTIVATE : SW_SHOW); // Show the window. - if (!wd.no_focus && !wd.is_popup) { + if (wd.no_focus || wd.is_popup) { + // https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showwindow + ShowWindow(wd.hWnd, SW_SHOWNA); + } else { + ShowWindow(wd.hWnd, SW_SHOW); SetForegroundWindow(wd.hWnd); // Slightly higher priority. SetFocus(wd.hWnd); // Set keyboard focus. } @@ -1498,7 +1501,7 @@ void DisplayServerWindows::cursor_set_custom_image(const Ref<Resource> &p_cursor _THREAD_SAFE_METHOD_ if (p_cursor.is_valid()) { - Map<CursorShape, Vector<Variant>>::Element *cursor_c = cursors_cache.find(p_shape); + RBMap<CursorShape, Vector<Variant>>::Element *cursor_c = cursors_cache.find(p_shape); if (cursor_c) { if (cursor_c->get()[0] == p_cursor && cursor_c->get()[1] == p_hotspot) { @@ -1798,7 +1801,9 @@ void DisplayServerWindows::make_rendering_thread() { void DisplayServerWindows::swap_buffers() { #if defined(GLES3_ENABLED) - gl_manager->swap_buffers(); + if (gl_manager) { + gl_manager->swap_buffers(); + } #endif } @@ -1952,14 +1957,18 @@ void DisplayServerWindows::set_icon(const Ref<Image> &p_icon) { void DisplayServerWindows::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) { _THREAD_SAFE_METHOD_ #if defined(VULKAN_ENABLED) - context_vulkan->set_vsync_mode(p_window, p_vsync_mode); + if (context_vulkan) { + context_vulkan->set_vsync_mode(p_window, p_vsync_mode); + } #endif } DisplayServer::VSyncMode DisplayServerWindows::window_get_vsync_mode(WindowID p_window) const { _THREAD_SAFE_METHOD_ #if defined(VULKAN_ENABLED) - return context_vulkan->get_vsync_mode(p_window); + if (context_vulkan) { + return context_vulkan->get_vsync_mode(p_window); + } #endif return DisplayServer::VSYNC_ENABLED; } @@ -1997,7 +2006,7 @@ void DisplayServerWindows::_touch_event(WindowID p_window, bool p_pressed, float } void DisplayServerWindows::_drag_event(WindowID p_window, float p_x, float p_y, int idx) { - Map<int, Vector2>::Element *curr = touch_state.find(idx); + RBMap<int, Vector2>::Element *curr = touch_state.find(idx); if (!curr) { return; } @@ -2193,8 +2202,39 @@ LRESULT DisplayServerWindows::MouseProc(int code, WPARAM wParam, LPARAM lParam) return ::CallNextHookEx(mouse_monitor, code, wParam, lParam); } -// Our default window procedure to handle processing of window-related system messages/events. -// Also known as DefProc or DefWindowProc. +// Handle a single window message received while CreateWindowEx is still on the stack and our data +// structures are not fully initialized. +LRESULT DisplayServerWindows::_handle_early_window_message(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { + switch (uMsg) { + case WM_GETMINMAXINFO: { + // We receive this during CreateWindowEx and we haven't initialized the window + // struct, so let Windows figure out the maximized size. + // Silently forward to user/default. + } break; + case WM_NCCREATE: { + // We tunnel an unowned pointer to our window context (WindowData) through the + // first possible message (WM_NCCREATE) to fix up our window context collection. + CREATESTRUCTW *pCreate = (CREATESTRUCTW *)lParam; + WindowData *pWindowData = reinterpret_cast<WindowData *>(pCreate->lpCreateParams); + + // Fix this up so we can recognize the remaining messages. + pWindowData->hWnd = hWnd; + } break; + default: { + // Additional messages during window creation should happen after we fixed + // up the data structures on WM_NCCREATE, but this might change in the future, + // so report an error here and then we can implement them. + ERR_PRINT_ONCE(vformat("Unexpected window message 0x%x received for window we cannot recognize in our collection; sequence error.", uMsg)); + } break; + } + + if (user_proc) { + return CallWindowProcW(user_proc, hWnd, uMsg, wParam, lParam); + } + return DefWindowProcW(hWnd, uMsg, wParam, lParam); +} + +// The window procedure for our window class "Engine", used to handle processing of window-related system messages/events. // See: https://docs.microsoft.com/en-us/windows/win32/winmsg/window-procedures LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { if (drop_events) { @@ -2208,7 +2248,9 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA WindowID window_id = INVALID_WINDOW_ID; bool window_created = false; - // Check whether window exists. + // Check whether window exists + // FIXME this is O(n), where n is the set of currently open windows and subwindows + // we should have a secondary map from HWND to WindowID or even WindowData* alias, if we want to eliminate all the map lookups below for (const KeyValue<WindowID, WindowData> &E : windows) { if (E.value.hWnd == hWnd) { window_id = E.key; @@ -2217,10 +2259,12 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA } } - // Window doesn't exist or creation in progress, don't handle messages yet. + // WARNING: we get called with events before the window is registered in our collection + // specifically, even the call to CreateWindowEx already calls here while still on the stack, + // so there is no way to store the window handle in our collection before we get here if (!window_created) { - window_id = window_id_counter; - ERR_FAIL_COND_V(!windows.has(window_id), 0); + // don't let code below operate on incompletely initialized window objects or missing window_id + return _handle_early_window_message(hWnd, uMsg, wParam, lParam); } // Process window messages. @@ -3388,11 +3432,17 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, WindowRect.top, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top, - nullptr, nullptr, hInstance, nullptr); + nullptr, + nullptr, + hInstance, + // tunnel the WindowData we need to handle creation message + // lifetime is ensured because we are still on the stack when this is + // processed in the window proc + reinterpret_cast<void *>(&wd)); if (!wd.hWnd) { MessageBoxW(nullptr, L"Window Creation Error.", L"ERROR", MB_OK | MB_ICONEXCLAMATION); windows.erase(id); - return INVALID_WINDOW_ID; + ERR_FAIL_V_MSG(INVALID_WINDOW_ID, "Failed to create Windows OS window."); } if (p_mode != WINDOW_MODE_FULLSCREEN && p_mode != WINDOW_MODE_EXCLUSIVE_FULLSCREEN) { wd.pre_fs_valid = true; @@ -3412,7 +3462,14 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, #ifdef GLES3_ENABLED if (gl_manager) { Error err = gl_manager->window_create(id, wd.hWnd, hInstance, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top); - ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, "Failed to create an OpenGL window."); + + // shut down OpenGL, to mirror behavior of Vulkan code + if (err != OK) { + memdelete(gl_manager); + gl_manager = nullptr; + windows.erase(id); + ERR_FAIL_V_MSG(INVALID_WINDOW_ID, "Failed to create an OpenGL window."); + } } #endif @@ -3457,6 +3514,8 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, ImmReleaseContext(wd.hWnd, wd.im_himc); wd.im_position = Vector2(); + + // FIXME this is wrong in cases where the window coordinates were changed due to full screen mode; use WindowRect wd.last_pos = p_rect.position; wd.width = p_rect.size.width; wd.height = p_rect.size.height; @@ -3747,6 +3806,7 @@ DisplayServerWindows::~DisplayServerWindows() { #ifdef GLES3_ENABLED // destroy windows .. NYI? + // FIXME wglDeleteContext is never called #endif if (windows.has(MAIN_WINDOW_ID)) { |