summaryrefslogtreecommitdiff
path: root/platform/windows
diff options
context:
space:
mode:
Diffstat (limited to 'platform/windows')
-rw-r--r--platform/windows/crash_handler_windows.cpp44
-rw-r--r--platform/windows/detect.py19
-rw-r--r--platform/windows/display_server_windows.cpp205
-rw-r--r--platform/windows/display_server_windows.h31
-rw-r--r--platform/windows/export/export.cpp8
-rw-r--r--platform/windows/export/export.h2
-rw-r--r--platform/windows/export/export_plugin.cpp88
-rw-r--r--platform/windows/export/export_plugin.h9
-rw-r--r--platform/windows/gl_manager_windows.cpp122
-rw-r--r--platform/windows/gl_manager_windows.h6
-rw-r--r--platform/windows/godot.natvis6
-rw-r--r--platform/windows/godot_windows.cpp4
-rw-r--r--platform/windows/key_mapping_windows.cpp17
-rw-r--r--platform/windows/os_windows.cpp254
-rw-r--r--platform/windows/os_windows.h39
-rw-r--r--platform/windows/tts_windows.cpp2
-rw-r--r--platform/windows/tts_windows.h4
-rw-r--r--platform/windows/vulkan_context_win.cpp4
-rw-r--r--platform/windows/vulkan_context_win.h6
-rw-r--r--platform/windows/windows_terminal_logger.h2
20 files changed, 673 insertions, 199 deletions
diff --git a/platform/windows/crash_handler_windows.cpp b/platform/windows/crash_handler_windows.cpp
index 3b2c6fe9f6..6ce10e6f0f 100644
--- a/platform/windows/crash_handler_windows.cpp
+++ b/platform/windows/crash_handler_windows.cpp
@@ -32,6 +32,7 @@
#include "core/config/project_settings.h"
#include "core/os/os.h"
+#include "core/string/print_string.h"
#include "core/version.h"
#include "main/main.h"
@@ -129,13 +130,28 @@ DWORD CrashHandlerException(EXCEPTION_POINTERS *ep) {
return EXCEPTION_CONTINUE_SEARCH;
}
- fprintf(stderr, "\n================================================================\n");
- fprintf(stderr, "%s: Program crashed\n", __FUNCTION__);
+ String msg;
+ const ProjectSettings *proj_settings = ProjectSettings::get_singleton();
+ if (proj_settings) {
+ msg = proj_settings->get("debug/settings/crash_handler/message");
+ }
+ // Tell MainLoop about the crash. This can be handled by users too in Node.
if (OS::get_singleton()->get_main_loop()) {
OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_CRASH);
}
+ print_error("\n================================================================");
+ print_error(vformat("%s: Program crashed", __FUNCTION__));
+
+ // Print the engine version just before, so that people are reminded to include the version in backtrace reports.
+ if (String(VERSION_HASH).is_empty()) {
+ print_error(vformat("Engine version: %s", VERSION_FULL_NAME));
+ } else {
+ print_error(vformat("Engine version: %s (%s)", VERSION_FULL_NAME, VERSION_HASH));
+ }
+ print_error(vformat("Dumping the backtrace. %s", msg));
+
// Load the symbols:
if (!SymInitialize(process, nullptr, false)) {
return EXCEPTION_CONTINUE_SEARCH;
@@ -174,20 +190,6 @@ DWORD CrashHandlerException(EXCEPTION_POINTERS *ep) {
IMAGE_NT_HEADERS *h = ImageNtHeader(base);
DWORD image_type = h->FileHeader.Machine;
- String msg;
- const ProjectSettings *proj_settings = ProjectSettings::get_singleton();
- if (proj_settings) {
- msg = proj_settings->get("debug/settings/crash_handler/message");
- }
-
- // Print the engine version just before, so that people are reminded to include the version in backtrace reports.
- if (String(VERSION_HASH).is_empty()) {
- fprintf(stderr, "Engine version: %s\n", VERSION_FULL_NAME);
- } else {
- fprintf(stderr, "Engine version: %s (%s)\n", VERSION_FULL_NAME, VERSION_HASH);
- }
- fprintf(stderr, "Dumping the backtrace. %s\n", msg.utf8().get_data());
-
int n = 0;
do {
if (skip_first) {
@@ -197,12 +199,12 @@ DWORD CrashHandlerException(EXCEPTION_POINTERS *ep) {
std::string fnName = symbol(process, frame.AddrPC.Offset).undecorated_name();
if (SymGetLineFromAddr64(process, frame.AddrPC.Offset, &offset_from_symbol, &line)) {
- fprintf(stderr, "[%d] %s (%s:%d)\n", n, fnName.c_str(), line.FileName, line.LineNumber);
+ print_error(vformat("[%d] %s (%s:%d)", n, fnName.c_str(), (char *)line.FileName, (int)line.LineNumber));
} else {
- fprintf(stderr, "[%d] %s\n", n, fnName.c_str());
+ print_error(vformat("[%d] %s", n, fnName.c_str()));
}
} else {
- fprintf(stderr, "[%d] ???\n", n);
+ print_error(vformat("[%d] ???", n));
}
n++;
@@ -213,8 +215,8 @@ DWORD CrashHandlerException(EXCEPTION_POINTERS *ep) {
}
} while (frame.AddrReturn.Offset != 0 && n < 256);
- fprintf(stderr, "-- END OF BACKTRACE --\n");
- fprintf(stderr, "================================================================\n");
+ print_error("-- END OF BACKTRACE --");
+ print_error("================================================================");
SymCleanup(process);
diff --git a/platform/windows/detect.py b/platform/windows/detect.py
index 0b18fb74fb..dd2df1f004 100644
--- a/platform/windows/detect.py
+++ b/platform/windows/detect.py
@@ -198,7 +198,6 @@ def configure_msvc(env, manual_msvc_config):
elif env["target"] == "debug":
env.AppendUnique(CCFLAGS=["/Zi", "/FS", "/Od", "/EHsc"])
# Allow big objects. Only needed for debug, see MinGW branch for rationale.
- env.AppendUnique(CCFLAGS=["/bigobj"])
env.Append(LINKFLAGS=["/DEBUG"])
if env["debug_symbols"]:
@@ -221,6 +220,10 @@ def configure_msvc(env, manual_msvc_config):
env.AppendUnique(CCFLAGS=["/Gd", "/GR", "/nologo"])
env.AppendUnique(CCFLAGS=["/utf-8"]) # Force to use Unicode encoding.
env.AppendUnique(CXXFLAGS=["/TP"]) # assume all sources are C++
+ # Once it was thought that only debug builds would be too large,
+ # but this has recently stopped being true. See the mingw function
+ # for notes on why this shouldn't be enabled for gcc
+ env.AppendUnique(CCFLAGS=["/bigobj"])
if manual_msvc_config: # should be automatic if SCons found it
if os.getenv("WindowsSdkDir") is not None:
@@ -267,14 +270,17 @@ def configure_msvc(env, manual_msvc_config):
"bcrypt",
"Avrt",
"dwmapi",
+ "dwrite",
]
- env.AppendUnique(CPPDEFINES=["VULKAN_ENABLED"])
- if not env["use_volk"]:
- LIBS += ["vulkan"]
+ if env["vulkan"]:
+ env.AppendUnique(CPPDEFINES=["VULKAN_ENABLED"])
+ if not env["use_volk"]:
+ LIBS += ["vulkan"]
- env.AppendUnique(CPPDEFINES=["GLES3_ENABLED"])
- LIBS += ["opengl32"]
+ if env["opengl3"]:
+ env.AppendUnique(CPPDEFINES=["GLES3_ENABLED"])
+ LIBS += ["opengl32"]
env.Append(LINKFLAGS=[p + env["LIBSUFFIX"] for p in LIBS])
@@ -436,6 +442,7 @@ def configure_mingw(env):
"avrt",
"uuid",
"dwmapi",
+ "dwrite",
]
)
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index 0412eb2d9c..8c8dbef8a4 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -531,10 +531,43 @@ DisplayServer::ScreenOrientation DisplayServerWindows::screen_get_orientation(in
}
void DisplayServerWindows::screen_set_keep_on(bool p_enable) {
+ if (keep_screen_on == p_enable) {
+ return;
+ }
+
+ if (p_enable) {
+ const String reason = "Godot Engine running with display/window/energy_saving/keep_screen_on = true";
+ Char16String reason_utf16 = reason.utf16();
+
+ REASON_CONTEXT context;
+ context.Version = POWER_REQUEST_CONTEXT_VERSION;
+ context.Flags = POWER_REQUEST_CONTEXT_SIMPLE_STRING;
+ context.Reason.SimpleReasonString = (LPWSTR)(reason_utf16.ptrw());
+ power_request = PowerCreateRequest(&context);
+ if (power_request == INVALID_HANDLE_VALUE) {
+ print_error("Failed to enable screen_keep_on.");
+ return;
+ }
+ if (PowerSetRequest(power_request, POWER_REQUEST_TYPE::PowerRequestSystemRequired) == 0) {
+ print_error("Failed to request system sleep override.");
+ return;
+ }
+ if (PowerSetRequest(power_request, POWER_REQUEST_TYPE::PowerRequestDisplayRequired) == 0) {
+ print_error("Failed to request display timeout override.");
+ return;
+ }
+ } else {
+ PowerClearRequest(power_request, POWER_REQUEST_TYPE::PowerRequestSystemRequired);
+ PowerClearRequest(power_request, POWER_REQUEST_TYPE::PowerRequestDisplayRequired);
+ CloseHandle(power_request);
+ power_request = nullptr;
+ }
+
+ keep_screen_on = p_enable;
}
bool DisplayServerWindows::screen_is_kept_on() const {
- return false;
+ return keep_screen_on;
}
Vector<DisplayServer::WindowID> DisplayServerWindows::get_window_list() const {
@@ -607,8 +640,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.
}
@@ -625,7 +661,7 @@ void DisplayServerWindows::delete_sub_window(WindowID p_window) {
WindowData &wd = windows[p_window];
while (wd.transient_children.size()) {
- window_set_transient(wd.transient_children.front()->get(), INVALID_WINDOW_ID);
+ window_set_transient(*wd.transient_children.begin(), INVALID_WINDOW_ID);
}
if (wd.transient_parent != INVALID_WINDOW_ID) {
@@ -653,7 +689,9 @@ void DisplayServerWindows::delete_sub_window(WindowID p_window) {
void DisplayServerWindows::gl_window_make_current(DisplayServer::WindowID p_window_id) {
#if defined(GLES3_ENABLED)
- gl_manager->window_make_current(p_window_id);
+ if (gl_manager) {
+ gl_manager->window_make_current(p_window_id);
+ }
#endif
}
@@ -1106,6 +1144,10 @@ void DisplayServerWindows::_update_window_style(WindowID p_window, bool p_repain
SetWindowLongPtr(wd.hWnd, GWL_STYLE, style);
SetWindowLongPtr(wd.hWnd, GWL_EXSTYLE, style_ex);
+ if (icon.is_valid()) {
+ set_icon(icon);
+ }
+
SetWindowPos(wd.hWnd, wd.always_on_top ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | ((wd.no_focus || wd.is_popup) ? SWP_NOACTIVATE : 0));
if (p_repaint) {
@@ -1490,11 +1532,11 @@ void DisplayServerWindows::GetMaskBitmaps(HBITMAP hSourceBitmap, COLORREF clrTra
DeleteDC(hMainDC);
}
-void DisplayServerWindows::cursor_set_custom_image(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
+void DisplayServerWindows::cursor_set_custom_image(const Ref<Resource> &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
_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) {
@@ -1794,7 +1836,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
}
@@ -1895,9 +1939,11 @@ void DisplayServerWindows::set_icon(const Ref<Image> &p_icon) {
_THREAD_SAFE_METHOD_
ERR_FAIL_COND(!p_icon.is_valid());
- Ref<Image> icon = p_icon->duplicate();
- if (icon->get_format() != Image::FORMAT_RGBA8) {
- icon->convert(Image::FORMAT_RGBA8);
+ if (icon != p_icon) {
+ icon = p_icon->duplicate();
+ if (icon->get_format() != Image::FORMAT_RGBA8) {
+ icon->convert(Image::FORMAT_RGBA8);
+ }
}
int w = icon->get_width();
int h = icon->get_height();
@@ -1946,14 +1992,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;
}
@@ -1991,7 +2041,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;
}
@@ -2018,7 +2068,7 @@ void DisplayServerWindows::_send_window_event(const WindowData &wd, WindowEvent
Variant *eventp = &event;
Variant ret;
Callable::CallError ce;
- wd.event_callback.call((const Variant **)&eventp, 1, ret, ce);
+ wd.event_callback.callp((const Variant **)&eventp, 1, ret, ce);
}
}
@@ -2045,7 +2095,7 @@ void DisplayServerWindows::_dispatch_input_event(const Ref<InputEvent> &p_event)
if (windows.has(E->get())) {
Callable callable = windows[E->get()].input_event_callback;
if (callable.is_valid()) {
- callable.call((const Variant **)&evp, 1, ret, ce);
+ callable.callp((const Variant **)&evp, 1, ret, ce);
}
}
in_dispatch_input_event = false;
@@ -2059,7 +2109,7 @@ void DisplayServerWindows::_dispatch_input_event(const Ref<InputEvent> &p_event)
if (windows.has(event_from_window->get_window_id())) {
Callable callable = windows[event_from_window->get_window_id()].input_event_callback;
if (callable.is_valid()) {
- callable.call((const Variant **)&evp, 1, ret, ce);
+ callable.callp((const Variant **)&evp, 1, ret, ce);
}
}
} else {
@@ -2067,7 +2117,7 @@ void DisplayServerWindows::_dispatch_input_event(const Ref<InputEvent> &p_event)
for (const KeyValue<WindowID, WindowData> &E : windows) {
const Callable callable = E.value.input_event_callback;
if (callable.is_valid()) {
- callable.call((const Variant **)&evp, 1, ret, ce);
+ callable.callp((const Variant **)&evp, 1, ret, ce);
}
}
}
@@ -2143,7 +2193,10 @@ void DisplayServerWindows::popup_close(WindowID p_window) {
WindowID win_id = E->get();
popup_list.erase(E);
- _send_window_event(windows[win_id], DisplayServerWindows::WINDOW_EVENT_CLOSE_REQUEST);
+ if (win_id != p_window) {
+ // Only request close on related windows, not this window. We are already processing it.
+ _send_window_event(windows[win_id], DisplayServerWindows::WINDOW_EVENT_CLOSE_REQUEST);
+ }
E = F;
}
}
@@ -2158,6 +2211,7 @@ LRESULT DisplayServerWindows::MouseProc(int code, WPARAM wParam, LPARAM lParam)
case WM_NCRBUTTONDOWN:
case WM_NCMBUTTONDOWN:
case WM_LBUTTONDOWN:
+ case WM_RBUTTONDOWN:
case WM_MBUTTONDOWN: {
MOUSEHOOKSTRUCT *ms = (MOUSEHOOKSTRUCT *)lParam;
Point2i pos = Point2i(ms->pt.x, ms->pt.y);
@@ -2180,6 +2234,7 @@ LRESULT DisplayServerWindows::MouseProc(int code, WPARAM wParam, LPARAM lParam)
}
if (C) {
_send_window_event(windows[C->get()], DisplayServerWindows::WINDOW_EVENT_CLOSE_REQUEST);
+ return 1;
}
} break;
}
@@ -2187,8 +2242,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) {
@@ -2202,7 +2288,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;
@@ -2211,10 +2299,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.
@@ -2325,7 +2415,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
case WM_MOUSELEAVE: {
old_invalid = true;
- outside = true;
+ windows[window_id].mouse_outside = true;
_send_window_event(windows[window_id], WINDOW_EVENT_MOUSE_EXIT);
@@ -2435,6 +2525,8 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
windows[window_id].last_tilt = Vector2();
}
+ windows[window_id].last_pen_inverted = packet.pkStatus & TPS_INVERT;
+
POINT coords;
GetCursorPos(&coords);
ScreenToClient(windows[window_id].hWnd, &coords);
@@ -2453,6 +2545,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
mm->set_pressure(windows[window_id].last_pressure);
mm->set_tilt(windows[window_id].last_tilt);
+ mm->set_pen_inverted(windows[window_id].last_pen_inverted);
mm->set_button_mask(last_button_state);
@@ -2552,7 +2645,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
}
- if (outside) {
+ if (windows[window_id].mouse_outside) {
// Mouse enter.
if (mouse_mode != MOUSE_MODE_CAPTURED) {
@@ -2562,7 +2655,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
CursorShape c = cursor_shape;
cursor_shape = CURSOR_MAX;
cursor_set_shape(c);
- outside = false;
+ windows[window_id].mouse_outside = false;
// Once-off notification, must call again.
track_mouse_leave_event(hWnd);
@@ -2585,6 +2678,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
if ((pen_info.penMask & PEN_MASK_TILT_X) && (pen_info.penMask & PEN_MASK_TILT_Y)) {
mm->set_tilt(Vector2((float)pen_info.tiltX / 90, (float)pen_info.tiltY / 90));
}
+ mm->set_pen_inverted(pen_info.penFlags & (PEN_FLAG_INVERTED | PEN_FLAG_ERASER));
mm->set_ctrl_pressed(GetKeyState(VK_CONTROL) < 0);
mm->set_shift_pressed(GetKeyState(VK_SHIFT) < 0);
@@ -2652,7 +2746,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
}
- if (outside) {
+ if (windows[window_id].mouse_outside) {
// Mouse enter.
if (mouse_mode != MOUSE_MODE_CAPTURED) {
@@ -2662,7 +2756,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
CursorShape c = cursor_shape;
cursor_shape = CURSOR_MAX;
cursor_set_shape(c);
- outside = false;
+ windows[window_id].mouse_outside = false;
// Once-off notification, must call again.
track_mouse_leave_event(hWnd);
@@ -2687,14 +2781,17 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
} else {
windows[window_id].last_tilt = Vector2();
windows[window_id].last_pressure = (wParam & MK_LBUTTON) ? 1.0f : 0.0f;
+ windows[window_id].last_pen_inverted = false;
}
} else {
windows[window_id].last_tilt = Vector2();
windows[window_id].last_pressure = (wParam & MK_LBUTTON) ? 1.0f : 0.0f;
+ windows[window_id].last_pen_inverted = false;
}
mm->set_pressure(windows[window_id].last_pressure);
mm->set_tilt(windows[window_id].last_tilt);
+ mm->set_pen_inverted(windows[window_id].last_pen_inverted);
mm->set_button_mask(last_button_state);
@@ -2975,7 +3072,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
const Variant *args[] = { &size };
Variant ret;
Callable::CallError ce;
- window.rect_changed_callback.call(args, 1, ret, ce);
+ window.rect_changed_callback.callp(args, 1, ret, ce);
}
}
@@ -3135,7 +3232,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
Variant *vp = &v;
Variant ret;
Callable::CallError ce;
- windows[window_id].drop_files_callback.call((const Variant **)&vp, 1, ret, ce);
+ windows[window_id].drop_files_callback.callp((const Variant **)&vp, 1, ret, ce);
}
} break;
default: {
@@ -3305,8 +3402,8 @@ void DisplayServerWindows::_update_tablet_ctx(const String &p_old_driver, const
if ((p_new_driver == "wintab") && wintab_available) {
wintab_WTInfo(WTI_DEFSYSCTX, 0, &wd.wtlc);
wd.wtlc.lcOptions |= CXO_MESSAGES;
- wd.wtlc.lcPktData = PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE | PK_ORIENTATION;
- wd.wtlc.lcMoveMask = PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE;
+ wd.wtlc.lcPktData = PK_STATUS | PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE | PK_ORIENTATION;
+ wd.wtlc.lcMoveMask = PK_STATUS | PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE;
wd.wtlc.lcPktMode = 0;
wd.wtlc.lcOutOrgX = 0;
wd.wtlc.lcOutExtX = wd.wtlc.lcInExtX;
@@ -3382,11 +3479,23 @@ 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.fullscreen = true;
+ if (p_mode == WINDOW_MODE_FULLSCREEN) {
+ wd.multiwindow_fs = true;
+ }
}
if (p_mode != WINDOW_MODE_FULLSCREEN && p_mode != WINDOW_MODE_EXCLUSIVE_FULLSCREEN) {
wd.pre_fs_valid = true;
@@ -3406,7 +3515,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
@@ -3416,8 +3532,8 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
if ((tablet_get_current_driver() == "wintab") && wintab_available) {
wintab_WTInfo(WTI_DEFSYSCTX, 0, &wd.wtlc);
wd.wtlc.lcOptions |= CXO_MESSAGES;
- wd.wtlc.lcPktData = PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE | PK_ORIENTATION;
- wd.wtlc.lcMoveMask = PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE;
+ wd.wtlc.lcPktData = PK_STATUS | PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE | PK_ORIENTATION;
+ wd.wtlc.lcMoveMask = PK_STATUS | PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE;
wd.wtlc.lcPktMode = 0;
wd.wtlc.lcOutOrgX = 0;
wd.wtlc.lcOutExtX = wd.wtlc.lcInExtX;
@@ -3451,6 +3567,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;
@@ -3529,13 +3647,14 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
old_invalid = true;
mouse_mode = MOUSE_MODE_VISIBLE;
- outside = true;
-
rendering_driver = p_rendering_driver;
// Init TTS
tts = memnew(TTS_Windows);
+ // Enforce default keep screen on value.
+ screen_set_keep_on(GLOBAL_GET("display/window/energy_saving/keep_screen_on"));
+
// Note: Wacom WinTab driver API for pen input, for devices incompatible with Windows Ink.
HMODULE wintab_lib = LoadLibraryW(L"wintab32.dll");
if (wintab_lib) {
@@ -3739,8 +3858,12 @@ DisplayServerWindows::~DisplayServerWindows() {
SetWindowLongPtr(windows[MAIN_WINDOW_ID].hWnd, GWLP_WNDPROC, (LONG_PTR)user_proc);
}
+ // Close power request handle.
+ screen_set_keep_on(false);
+
#ifdef GLES3_ENABLED
// destroy windows .. NYI?
+ // FIXME wglDeleteContext is never called
#endif
if (windows.has(MAIN_WINDOW_ID)) {
diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h
index 80faf71bd4..db9b589304 100644
--- a/platform/windows/display_server_windows.h
+++ b/platform/windows/display_server_windows.h
@@ -82,10 +82,13 @@
#define DVC_ROTATION 18
#define CXO_MESSAGES 0x0004
+#define PK_STATUS 0x0002
#define PK_NORMAL_PRESSURE 0x0400
#define PK_TANGENT_PRESSURE 0x0800
#define PK_ORIENTATION 0x1000
+#define TPS_INVERT 0x0010 /* 1.1 */
+
typedef struct tagLOGCONTEXTW {
WCHAR lcName[40];
UINT lcOptions;
@@ -137,6 +140,7 @@ typedef struct tagORIENTATION {
} ORIENTATION;
typedef struct tagPACKET {
+ int pkStatus;
int pkNormalPressure;
int pkTangentPressure;
ORIENTATION pkOrientation;
@@ -158,6 +162,14 @@ typedef UINT32 POINTER_FLAGS;
typedef UINT32 PEN_FLAGS;
typedef UINT32 PEN_MASK;
+#ifndef PEN_FLAG_INVERTED
+#define PEN_FLAG_INVERTED 0x00000002
+#endif
+
+#ifndef PEN_FLAG_ERASER
+#define PEN_FLAG_ERASER 0x00000004
+#endif
+
#ifndef PEN_MASK_PRESSURE
#define PEN_MASK_PRESSURE 0x00000001
#endif
@@ -301,7 +313,6 @@ class DisplayServerWindows : public DisplayServer {
int key_event_pos;
bool old_invalid;
- bool outside;
int old_x, old_y;
Point2i center;
@@ -314,12 +325,14 @@ class DisplayServerWindows : public DisplayServer {
RenderingDeviceVulkan *rendering_device_vulkan = nullptr;
#endif
- Map<int, Vector2> touch_state;
+ RBMap<int, Vector2> touch_state;
int pressrc;
HINSTANCE hInstance; // Holds The Instance Of The Application
String rendering_driver;
bool app_focused = false;
+ bool keep_screen_on = false;
+ HANDLE power_request;
TTS_Windows *tts = nullptr;
@@ -357,11 +370,13 @@ class DisplayServerWindows : public DisplayServer {
int min_pressure;
int max_pressure;
bool tilt_supported;
+ bool pen_inverted = false;
bool block_mm = false;
int last_pressure_update;
float last_pressure;
Vector2 last_tilt;
+ bool last_pen_inverted = false;
HBITMAP hBitmap; //DIB section for layered window
uint8_t *dib_data = nullptr;
@@ -373,6 +388,7 @@ class DisplayServerWindows : public DisplayServer {
Size2 window_rect;
Point2 last_pos;
+ bool mouse_outside = true;
ObjectID instance_id;
@@ -389,7 +405,7 @@ class DisplayServerWindows : public DisplayServer {
Callable drop_files_callback;
WindowID transient_parent = INVALID_WINDOW_ID;
- Set<WindowID> transient_children;
+ HashSet<WindowID> transient_children;
bool is_popup = false;
Rect2i parent_safe_rect;
@@ -399,10 +415,11 @@ class DisplayServerWindows : public DisplayServer {
HHOOK mouse_monitor = nullptr;
List<WindowID> popup_list;
uint64_t time_since_popup = 0;
+ Ref<Image> icon;
WindowID _create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect);
WindowID window_id_counter = MAIN_WINDOW_ID;
- Map<WindowID, WindowData> windows;
+ RBMap<WindowID, WindowData> windows;
WindowID last_focused_window = INVALID_WINDOW_ID;
@@ -429,7 +446,7 @@ class DisplayServerWindows : public DisplayServer {
HCURSOR cursors[CURSOR_MAX] = { nullptr };
CursorShape cursor_shape = CursorShape::CURSOR_ARROW;
- Map<CursorShape, Vector<Variant>> cursors_cache;
+ RBMap<CursorShape, Vector<Variant>> cursors_cache;
void _drag_event(WindowID p_window, float p_x, float p_y, int idx);
void _touch_event(WindowID p_window, bool p_pressed, float p_x, float p_y, int idx);
@@ -447,6 +464,8 @@ class DisplayServerWindows : public DisplayServer {
static void _dispatch_input_events(const Ref<InputEvent> &p_event);
void _dispatch_input_event(const Ref<InputEvent> &p_event);
+ LRESULT _handle_early_window_message(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
public:
LRESULT WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
LRESULT MouseProc(int code, WPARAM wParam, LPARAM lParam);
@@ -561,7 +580,7 @@ public:
virtual void cursor_set_shape(CursorShape p_shape) override;
virtual CursorShape cursor_get_shape() const override;
- virtual void cursor_set_custom_image(const RES &p_cursor, CursorShape p_shape = CURSOR_ARROW, const Vector2 &p_hotspot = Vector2()) override;
+ virtual void cursor_set_custom_image(const Ref<Resource> &p_cursor, CursorShape p_shape = CURSOR_ARROW, const Vector2 &p_hotspot = Vector2()) override;
virtual bool get_swap_cancel_ok() override;
diff --git a/platform/windows/export/export.cpp b/platform/windows/export/export.cpp
index 0fa2913218..20320470b8 100644
--- a/platform/windows/export/export.cpp
+++ b/platform/windows/export/export.cpp
@@ -30,6 +30,7 @@
#include "export.h"
+#include "editor/export/editor_export.h"
#include "export_plugin.h"
void register_windows_exporter() {
@@ -48,12 +49,7 @@ void register_windows_exporter() {
Ref<EditorExportPlatformWindows> platform;
platform.instantiate();
-
- Ref<Image> img = memnew(Image(_windows_logo));
- Ref<ImageTexture> logo;
- logo.instantiate();
- logo->create_from_image(img);
- platform->set_logo(logo);
+ platform->set_logo(ImageTexture::create_from_image(memnew(Image(_windows_logo))));
platform->set_name("Windows Desktop");
platform->set_os_name("Windows");
diff --git a/platform/windows/export/export.h b/platform/windows/export/export.h
index 09399f2bee..1054e04b1e 100644
--- a/platform/windows/export/export.h
+++ b/platform/windows/export/export.h
@@ -33,4 +33,4 @@
void register_windows_exporter();
-#endif
+#endif // WINDOWS_EXPORT_H
diff --git a/platform/windows/export/export_plugin.cpp b/platform/windows/export/export_plugin.cpp
index b4d8ce64b2..febef5ad12 100644
--- a/platform/windows/export/export_plugin.cpp
+++ b/platform/windows/export/export_plugin.cpp
@@ -43,7 +43,10 @@ Error EditorExportPlatformWindows::sign_shared_object(const Ref<EditorExportPres
Error EditorExportPlatformWindows::_export_debug_script(const Ref<EditorExportPreset> &p_preset, const String &p_app_name, const String &p_pkg_name, const String &p_path) {
Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE);
- ERR_FAIL_COND_V(f.is_null(), ERR_CANT_CREATE);
+ if (f.is_null()) {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Debug Script Export"), vformat(TTR("Could not open file \"%s\"."), p_path));
+ return ERR_CANT_CREATE;
+ }
f->store_line("@echo off");
f->store_line("title \"" + p_app_name + "\"");
@@ -53,24 +56,29 @@ Error EditorExportPlatformWindows::_export_debug_script(const Ref<EditorExportPr
return OK;
}
+Error EditorExportPlatformWindows::modify_template(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
+ if (p_preset->get("application/modify_resources")) {
+ _rcedit_add_data(p_preset, p_path);
+ }
+ return OK;
+}
+
Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
String pck_path = p_path;
if (p_preset->get("binary_format/embed_pck")) {
pck_path = p_path.get_basename() + ".tmp";
}
- Error err = EditorExportPlatformPC::prepare_template(p_preset, p_debug, pck_path, p_flags);
- if (p_preset->get("application/modify_resources") && err == OK) {
- err = _rcedit_add_data(p_preset, pck_path);
- }
- if (err == OK) {
- err = EditorExportPlatformPC::export_project_data(p_preset, p_debug, pck_path, p_flags);
- }
+ Error err = EditorExportPlatformPC::export_project(p_preset, p_debug, pck_path, p_flags);
if (p_preset->get("codesign/enable") && err == OK) {
- err = _code_sign(p_preset, pck_path);
+ _code_sign(p_preset, pck_path);
}
+
if (p_preset->get("binary_format/embed_pck") && err == OK) {
Ref<DirAccess> tmp_dir = DirAccess::create_for_path(p_path.get_base_dir());
err = tmp_dir->rename(pck_path, p_path);
+ if (err != OK) {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("PCK Embedding"), vformat(TTR("Failed to rename temporary file \"%s\"."), pck_path));
+ }
}
String app_name;
@@ -86,7 +94,9 @@ Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset>
int con_scr = p_preset->get("debug/export_console_script");
if ((con_scr == 1 && p_debug) || (con_scr == 2)) {
String scr_path = p_path.get_basename() + ".cmd";
- err = _export_debug_script(p_preset, app_name, p_path.get_file(), scr_path);
+ if (_export_debug_script(p_preset, app_name, p_path.get_file(), scr_path) != OK) {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Debug Script Export"), TTR("Could not create console script."));
+ }
}
}
@@ -94,7 +104,7 @@ Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset>
}
String EditorExportPlatformWindows::get_template_file_name(const String &p_target, const String &p_arch) const {
- return "windows_" + p_arch + "_" + p_target + ".exe";
+ return "windows_" + p_target + "_" + p_arch + ".exe";
}
List<String> EditorExportPlatformWindows::get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const {
@@ -103,7 +113,7 @@ List<String> EditorExportPlatformWindows::get_binary_extensions(const Ref<Editor
return list;
}
-bool EditorExportPlatformWindows::get_export_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const {
+bool EditorExportPlatformWindows::get_export_option_visibility(const String &p_option, const HashMap<StringName, Variant> &p_options) const {
// This option is not supported by "osslsigncode", used on non-Windows host.
if (!OS::get_singleton()->has_feature("windows") && p_option == "codesign/identity_type") {
return false;
@@ -113,6 +123,7 @@ bool EditorExportPlatformWindows::get_export_option_visibility(const String &p_o
void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_options) {
EditorExportPlatformPC::get_export_options(r_options);
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "binary_format/architecture", PROPERTY_HINT_ENUM, "x86_64,x86_32"), "x86_64"));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/enable"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/identity_type", PROPERTY_HINT_ENUM, "Select automatically,Use PKCS12 file (specify *.PFX/*.P12 file),Use certificate store (specify SHA1 hash)"), 0));
@@ -139,7 +150,7 @@ Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset
String rcedit_path = EditorSettings::get_singleton()->get("export/windows/rcedit");
if (rcedit_path != String() && !FileAccess::exists(rcedit_path)) {
- ERR_PRINT("Could not find rcedit executable at " + rcedit_path + ", aborting.");
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Resources Modification"), vformat(TTR("Could not find rcedit executable at \"%s\"."), rcedit_path));
return ERR_FILE_NOT_FOUND;
}
@@ -152,7 +163,7 @@ Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset
String wine_path = EditorSettings::get_singleton()->get("export/windows/wine");
if (!wine_path.is_empty() && !FileAccess::exists(wine_path)) {
- ERR_PRINT("Could not find wine executable at " + wine_path + ", aborting.");
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Resources Modification"), vformat(TTR("Could not find wine executable at \"%s\"."), wine_path));
return ERR_FILE_NOT_FOUND;
}
@@ -219,10 +230,14 @@ Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset
String str;
Error err = OS::get_singleton()->execute(rcedit_path, args, &str, nullptr, true);
- ERR_FAIL_COND_V_MSG(err != OK, err, "Could not start rcedit executable, configure rcedit path in the Editor Settings (Export > Windows > Rcedit).");
+ if (err != OK || (str.find("not found") != -1) || (str.find("not recognized") != -1)) {
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Resources Modification"), TTR("Could not start rcedit executable. Configure rcedit path in the Editor Settings (Export > Windows > Rcedit), or disable \"Application > Modify Resources\" in the export preset."));
+ return err;
+ }
print_line("rcedit (" + p_path + "): " + str);
if (str.find("Fatal error") != -1) {
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Resources Modification"), vformat(TTR("rcedit failed to modify executable: %s."), str));
return FAILED;
}
@@ -235,7 +250,7 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
#ifdef WINDOWS_ENABLED
String signtool_path = EditorSettings::get_singleton()->get("export/windows/signtool");
if (!signtool_path.is_empty() && !FileAccess::exists(signtool_path)) {
- ERR_PRINT("Could not find signtool executable at " + signtool_path + ", aborting.");
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("Could not find signtool executable at \"%s\"."), signtool_path));
return ERR_FILE_NOT_FOUND;
}
if (signtool_path.is_empty()) {
@@ -244,7 +259,7 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
#else
String signtool_path = EditorSettings::get_singleton()->get("export/windows/osslsigncode");
if (!signtool_path.is_empty() && !FileAccess::exists(signtool_path)) {
- ERR_PRINT("Could not find osslsigncode executable at " + signtool_path + ", aborting.");
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("Could not find osslsigncode executable at \"%s\"."), signtool_path));
return ERR_FILE_NOT_FOUND;
}
if (signtool_path.is_empty()) {
@@ -264,7 +279,7 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
args.push_back("/f");
args.push_back(p_preset->get("codesign/identity"));
} else {
- EditorNode::add_io_error("codesign: no identity found");
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("No identity found."));
return FAILED;
}
} else if (id_type == 2) { //Windows certificate store
@@ -272,11 +287,11 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
args.push_back("/sha1");
args.push_back(p_preset->get("codesign/identity"));
} else {
- EditorNode::add_io_error("codesign: no identity found");
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("No identity found."));
return FAILED;
}
} else {
- EditorNode::add_io_error("codesign: invalid identity type");
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Invalid identity type."));
return FAILED;
}
#else
@@ -284,7 +299,7 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
args.push_back("-pkcs12");
args.push_back(p_preset->get("codesign/identity"));
} else {
- EditorNode::add_io_error("codesign: no identity found");
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("No identity found."));
return FAILED;
}
#endif
@@ -316,7 +331,7 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
args.push_back(p_preset->get("codesign/timestamp_server_url"));
#endif
} else {
- EditorNode::add_io_error("codesign: invalid timestamp server");
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Invalid timestamp server."));
return FAILED;
}
}
@@ -363,7 +378,10 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
String str;
Error err = OS::get_singleton()->execute(signtool_path, args, &str, nullptr, true);
- ERR_FAIL_COND_V_MSG(err != OK, err, "Could not start signtool executable, configure signtool path in the Editor Settings (Export > Windows > Signtool).");
+ if (err != OK || (str.find("not found") != -1) || (str.find("not recognized") != -1)) {
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Could not start signtool executable. Configure signtool path in the Editor Settings (Export > Windows > Signtool), or disable \"Codesign\" in the export preset."));
+ return err;
+ }
print_line("codesign (" + p_path + "): " + str);
#ifndef WINDOWS_ENABLED
@@ -371,6 +389,7 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
#else
if (str.find("Failed") != -1) {
#endif
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("Signtool failed to sign executable: %s."), str));
return FAILED;
}
@@ -378,10 +397,16 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
Ref<DirAccess> tmp_dir = DirAccess::create_for_path(p_path.get_base_dir());
err = tmp_dir->remove(p_path);
- ERR_FAIL_COND_V(err != OK, err);
+ if (err != OK) {
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("Failed to remove temporary file \"%s\"."), p_path));
+ return err;
+ }
err = tmp_dir->rename(p_path + "_signed", p_path);
- ERR_FAIL_COND_V(err != OK, err);
+ if (err != OK) {
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("Failed to rename temporary file \"%s\"."), p_path + "_signed"));
+ return err;
+ }
#endif
return OK;
@@ -430,15 +455,17 @@ bool EditorExportPlatformWindows::can_export(const Ref<EditorExportPreset> &p_pr
return valid;
}
-Error EditorExportPlatformWindows::fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) const {
+Error EditorExportPlatformWindows::fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) {
// Patch the header of the "pck" section in the PE file so that it corresponds to the embedded data
if (p_embedded_size + p_embedded_start >= 0x100000000) { // Check for total executable size
- ERR_FAIL_V_MSG(ERR_INVALID_DATA, "Windows executables cannot be >= 4 GiB.");
+ add_message(EXPORT_MESSAGE_ERROR, TTR("PCK Embedding"), TTR("Windows executables cannot be >= 4 GiB."));
+ return ERR_INVALID_DATA;
}
Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ_WRITE);
if (f.is_null()) {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("PCK Embedding"), vformat(TTR("Failed to open executable file \"%s\"."), p_path));
return ERR_CANT_OPEN;
}
@@ -450,6 +477,7 @@ Error EditorExportPlatformWindows::fixup_embedded_pck(const String &p_path, int6
f->seek(pe_pos);
uint32_t magic = f->get_32();
if (magic != 0x00004550) {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("PCK Embedding"), TTR("Executable file header corrupted."));
return ERR_FILE_CORRUPT;
}
}
@@ -499,5 +527,9 @@ Error EditorExportPlatformWindows::fixup_embedded_pck(const String &p_path, int6
}
}
- return found ? OK : ERR_FILE_CORRUPT;
+ if (!found) {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("PCK Embedding"), TTR("Executable \"pck\" section not found."));
+ return ERR_FILE_CORRUPT;
+ }
+ return OK;
}
diff --git a/platform/windows/export/export_plugin.h b/platform/windows/export/export_plugin.h
index c33c7f1f63..b9e59829a0 100644
--- a/platform/windows/export/export_plugin.h
+++ b/platform/windows/export/export_plugin.h
@@ -33,8 +33,8 @@
#include "core/io/file_access.h"
#include "core/os/os.h"
-#include "editor/editor_export.h"
#include "editor/editor_settings.h"
+#include "editor/export/editor_export_platform_pc.h"
#include "platform/windows/logo.gen.h"
class EditorExportPlatformWindows : public EditorExportPlatformPC {
@@ -44,13 +44,14 @@ class EditorExportPlatformWindows : public EditorExportPlatformPC {
public:
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override;
+ virtual Error modify_template(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) override;
virtual Error sign_shared_object(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path) override;
virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override;
virtual void get_export_options(List<ExportOption> *r_options) override;
- virtual bool get_export_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const override;
+ virtual bool get_export_option_visibility(const String &p_option, const HashMap<StringName, Variant> &p_options) const override;
virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override;
virtual String get_template_file_name(const String &p_target, const String &p_arch) const override;
- virtual Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) const override;
+ virtual Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) override;
};
-#endif
+#endif // WINDOWS_EXPORT_PLUGIN_H
diff --git a/platform/windows/gl_manager_windows.cpp b/platform/windows/gl_manager_windows.cpp
index a97fa99d7f..d509ff8c51 100644
--- a/platform/windows/gl_manager_windows.cpp
+++ b/platform/windows/gl_manager_windows.cpp
@@ -54,6 +54,18 @@
typedef HGLRC(APIENTRY *PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC, HGLRC, const int *);
+static String format_error_message(DWORD id) {
+ LPWSTR messageBuffer = nullptr;
+ size_t size = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+ nullptr, id, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0, nullptr);
+
+ String msg = "Error " + itos(id) + ": " + String::utf16((const char16_t *)messageBuffer, size);
+
+ LocalFree(messageBuffer);
+
+ return msg;
+}
+
int GLManager_Windows::_find_or_create_display(GLWindow &win) {
// find display NYI, only 1 supported so far
if (_displays.size()) {
@@ -79,7 +91,7 @@ int GLManager_Windows::_find_or_create_display(GLWindow &win) {
return new_display_id;
}
-Error GLManager_Windows::_create_context(GLWindow &win, GLDisplay &gl_display) {
+static Error _configure_pixel_format(HDC hDC) {
static PIXELFORMATDESCRIPTOR pfd = {
sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor
1,
@@ -101,9 +113,6 @@ Error GLManager_Windows::_create_context(GLWindow &win, GLDisplay &gl_display) {
0, 0, 0 // Layer Masks Ignored
};
- // alias
- HDC hDC = win.hDC;
-
int pixel_format = ChoosePixelFormat(hDC, &pfd);
if (!pixel_format) // Did Windows Find A Matching Pixel Format?
{
@@ -116,13 +125,24 @@ Error GLManager_Windows::_create_context(GLWindow &win, GLDisplay &gl_display) {
return ERR_CANT_CREATE; // Return FALSE
}
- gl_display.hRC = wglCreateContext(hDC);
+ return OK;
+}
+
+Error GLManager_Windows::_create_context(GLWindow &win, GLDisplay &gl_display) {
+ Error err = _configure_pixel_format(win.hDC);
+ if (err != OK) {
+ return err;
+ }
+
+ gl_display.hRC = wglCreateContext(win.hDC);
if (!gl_display.hRC) // Are We Able To Get A Rendering Context?
{
return ERR_CANT_CREATE; // Return FALSE
}
- wglMakeCurrent(hDC, gl_display.hRC);
+ if (!wglMakeCurrent(win.hDC, gl_display.hRC)) {
+ ERR_PRINT("Could not attach OpenGL context to newly created window: " + format_error_message(GetLastError()));
+ }
int attribs[] = {
WGL_CONTEXT_MAJOR_VERSION_ARB, 3, //we want a 3.3 context
@@ -143,57 +163,61 @@ Error GLManager_Windows::_create_context(GLWindow &win, GLDisplay &gl_display) {
return ERR_CANT_CREATE;
}
- HGLRC new_hRC = wglCreateContextAttribsARB(hDC, 0, attribs);
+ HGLRC new_hRC = wglCreateContextAttribsARB(win.hDC, 0, attribs);
if (!new_hRC) {
wglDeleteContext(gl_display.hRC);
gl_display.hRC = 0;
- return ERR_CANT_CREATE; // Return false
+ return ERR_CANT_CREATE;
}
- wglMakeCurrent(hDC, nullptr);
+
+ if (!wglMakeCurrent(win.hDC, nullptr)) {
+ ERR_PRINT("Could not detach OpenGL context from newly created window: " + format_error_message(GetLastError()));
+ }
+
wglDeleteContext(gl_display.hRC);
gl_display.hRC = new_hRC;
- if (!wglMakeCurrent(hDC, gl_display.hRC)) // Try To Activate The Rendering Context
+ if (!wglMakeCurrent(win.hDC, gl_display.hRC)) // Try To Activate The Rendering Context
{
+ ERR_PRINT("Could not attach OpenGL context to newly created window with replaced OpenGL context: " + format_error_message(GetLastError()));
wglDeleteContext(gl_display.hRC);
gl_display.hRC = 0;
- return ERR_CANT_CREATE; // Return FALSE
+ return ERR_CANT_CREATE;
}
return OK;
}
Error GLManager_Windows::window_create(DisplayServer::WindowID p_window_id, HWND p_hwnd, HINSTANCE p_hinstance, int p_width, int p_height) {
- HDC hdc = GetDC(p_hwnd);
- if (!hdc) {
- return ERR_CANT_CREATE; // Return FALSE
+ HDC hDC = GetDC(p_hwnd);
+ if (!hDC) {
+ return ERR_CANT_CREATE;
}
- // make sure vector is big enough...
- // we can mirror the external vector, it is simpler
- // to keep the IDs identical for fast lookup
- if (p_window_id >= (int)_windows.size()) {
- _windows.resize(p_window_id + 1);
+ // configure the HDC to use a compatible pixel format
+ Error result = _configure_pixel_format(hDC);
+ if (result != OK) {
+ return result;
}
- GLWindow &win = _windows[p_window_id];
- win.in_use = true;
- win.window_id = p_window_id;
+ GLWindow win;
win.width = p_width;
win.height = p_height;
win.hwnd = p_hwnd;
- win.hDC = hdc;
+ win.hDC = hDC;
win.gldisplay_id = _find_or_create_display(win);
if (win.gldisplay_id == -1) {
- // release DC?
- _windows.remove_at(_windows.size() - 1);
return FAILED;
}
+ // WARNING: p_window_id is an eternally growing integer since popup windows keep coming and going
+ // and each of them has a higher id than the previous, so it must be used in a map not a vector
+ _windows[p_window_id] = win;
+
// make current
- window_make_current(_windows.size() - 1);
+ window_make_current(p_window_id);
return OK;
}
@@ -217,11 +241,10 @@ int GLManager_Windows::window_get_height(DisplayServer::WindowID p_window_id) {
void GLManager_Windows::window_destroy(DisplayServer::WindowID p_window_id) {
GLWindow &win = get_window(p_window_id);
- win.in_use = false;
-
if (_current_window == &win) {
_current_window = nullptr;
}
+ _windows.erase(p_window_id);
}
void GLManager_Windows::release_current() {
@@ -229,7 +252,9 @@ void GLManager_Windows::release_current() {
return;
}
- wglMakeCurrent(_current_window->hDC, nullptr);
+ if (!wglMakeCurrent(_current_window->hDC, nullptr)) {
+ ERR_PRINT("Could not detach OpenGL context from window marked current: " + format_error_message(GetLastError()));
+ }
}
void GLManager_Windows::window_make_current(DisplayServer::WindowID p_window_id) {
@@ -237,10 +262,8 @@ void GLManager_Windows::window_make_current(DisplayServer::WindowID p_window_id)
return;
}
+ // crash if our data structures are out of sync, i.e. not found
GLWindow &win = _windows[p_window_id];
- if (!win.in_use) {
- return;
- }
// noop
if (&win == _current_window) {
@@ -248,7 +271,9 @@ void GLManager_Windows::window_make_current(DisplayServer::WindowID p_window_id)
}
const GLDisplay &disp = get_display(win.gldisplay_id);
- wglMakeCurrent(win.hDC, disp.hRC);
+ if (!wglMakeCurrent(win.hDC, disp.hRC)) {
+ ERR_PRINT("Could not switch OpenGL context to other window: " + format_error_message(GetLastError()));
+ }
_internal_set_current_window(&win);
}
@@ -257,34 +282,19 @@ void GLManager_Windows::make_current() {
if (!_current_window) {
return;
}
- if (!_current_window->in_use) {
- WARN_PRINT("current window not in use!");
- return;
- }
const GLDisplay &disp = get_current_display();
- wglMakeCurrent(_current_window->hDC, disp.hRC);
+ if (!wglMakeCurrent(_current_window->hDC, disp.hRC)) {
+ ERR_PRINT("Could not switch OpenGL context to window marked current: " + format_error_message(GetLastError()));
+ }
}
void GLManager_Windows::swap_buffers() {
- // NO NEED TO CALL SWAP BUFFERS for each window...
- // see https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glXSwapBuffers.xml
-
- if (!_current_window) {
- return;
+ // on other platforms, OpenGL swaps buffers for all windows (on all displays, really?)
+ // Windows swaps buffers on a per-window basis
+ // REVISIT: this could be structurally bad, should we have "dirty" flags then?
+ for (KeyValue<DisplayServer::WindowID, GLWindow> &entry : _windows) {
+ SwapBuffers(entry.value.hDC);
}
- if (!_current_window->in_use) {
- WARN_PRINT("current window not in use!");
- return;
- }
-
- // print_line("\tswap_buffers");
-
- // only for debugging without drawing anything
- // glClearColor(Math::randf(), 0, 1, 1);
- //glClear(GL_COLOR_BUFFER_BIT);
-
- // const GLDisplay &disp = get_current_display();
- SwapBuffers(_current_window->hDC);
}
Error GLManager_Windows::initialize() {
diff --git a/platform/windows/gl_manager_windows.h b/platform/windows/gl_manager_windows.h
index dc411983e8..5e43a3de2a 100644
--- a/platform/windows/gl_manager_windows.h
+++ b/platform/windows/gl_manager_windows.h
@@ -52,10 +52,6 @@ public:
private:
// any data specific to the window
struct GLWindow {
- bool in_use = false;
-
- // the external ID .. should match the GL window number .. unused I think
- DisplayServer::WindowID window_id = DisplayServer::INVALID_WINDOW_ID;
int width = 0;
int height = 0;
@@ -71,7 +67,7 @@ private:
HGLRC hRC;
};
- LocalVector<GLWindow> _windows;
+ RBMap<DisplayServer::WindowID, GLWindow> _windows;
LocalVector<GLDisplay> _displays;
GLWindow *_current_window = nullptr;
diff --git a/platform/windows/godot.natvis b/platform/windows/godot.natvis
index bb855e4ac8..cdd1c14978 100644
--- a/platform/windows/godot.natvis
+++ b/platform/windows/godot.natvis
@@ -40,11 +40,13 @@
<DisplayString Condition="type == Variant::TRANSFORM2D">{_data._transform2d}</DisplayString>
<DisplayString Condition="type == Variant::AABB">{_data._aabb}</DisplayString>
<DisplayString Condition="type == Variant::BASIS">{_data._basis}</DisplayString>
- <DisplayString Condition="type == Variant::TRANSFORM3D">{_data._transform}</DisplayString>
+ <DisplayString Condition="type == Variant::TRANSFORM3D">{_data._transform3d}</DisplayString>
+ <DisplayString Condition="type == Variant::PROJECTION">{_data._projection}</DisplayString>
<DisplayString Condition="type == Variant::STRING">{*(String *)_data._mem}</DisplayString>
<DisplayString Condition="type == Variant::VECTOR2">{*(Vector2 *)_data._mem}</DisplayString>
<DisplayString Condition="type == Variant::RECT2">{*(Rect2 *)_data._mem}</DisplayString>
<DisplayString Condition="type == Variant::VECTOR3">{*(Vector3 *)_data._mem}</DisplayString>
+ <DisplayString Condition="type == Variant::VECTOR4">{*(Vector4 *)_data._mem}</DisplayString>
<DisplayString Condition="type == Variant::PLANE">{*(Plane *)_data._mem}</DisplayString>
<DisplayString Condition="type == Variant::QUATERNION">{*(Quaternion *)_data._mem}</DisplayString>
<DisplayString Condition="type == Variant::COLOR">{*(Color *)_data._mem}</DisplayString>
@@ -72,7 +74,7 @@
<Item Name="[value]" Condition="type == Variant::TRANSFORM2D">_data._transform2d</Item>
<Item Name="[value]" Condition="type == Variant::AABB">_data._aabb</Item>
<Item Name="[value]" Condition="type == Variant::BASIS">_data._basis</Item>
- <Item Name="[value]" Condition="type == Variant::TRANSFORM3D">_data._transform</Item>
+ <Item Name="[value]" Condition="type == Variant::TRANSFORM3D">_data._transform3d</Item>
<Item Name="[value]" Condition="type == Variant::STRING">*(String *)_data._mem</Item>
<Item Name="[value]" Condition="type == Variant::VECTOR2">*(Vector2 *)_data._mem</Item>
<Item Name="[value]" Condition="type == Variant::RECT2">*(Rect2 *)_data._mem</Item>
diff --git a/platform/windows/godot_windows.cpp b/platform/windows/godot_windows.cpp
index 8de3ef294a..72920d2816 100644
--- a/platform/windows/godot_windows.cpp
+++ b/platform/windows/godot_windows.cpp
@@ -166,6 +166,10 @@ int widechar_main(int argc, wchar_t **argv) {
delete[] argv_utf8[i];
}
delete[] argv_utf8;
+
+ if (err == ERR_HELP) { // Returned by --help and --version, so success.
+ return 0;
+ }
return 255;
}
diff --git a/platform/windows/key_mapping_windows.cpp b/platform/windows/key_mapping_windows.cpp
index e32dc0d1a6..2d8d68a575 100644
--- a/platform/windows/key_mapping_windows.cpp
+++ b/platform/windows/key_mapping_windows.cpp
@@ -179,7 +179,14 @@ static _WinTranslatePair _vk_to_keycode[] = {
{ Key::F14, VK_F14 }, // (0x7D)
{ Key::F15, VK_F15 }, // (0x7E)
{ Key::F16, VK_F16 }, // (0x7F)
- // We have no mappings for F17-F24. (0x80-87)
+ { Key::F17, VK_F17 }, // (0x80)
+ { Key::F18, VK_F18 }, // (0x81)
+ { Key::F19, VK_F19 }, // (0x82)
+ { Key::F20, VK_F20 }, // (0x83)
+ { Key::F21, VK_F21 }, // (0x84)
+ { Key::F22, VK_F22 }, // (0x85)
+ { Key::F23, VK_F23 }, // (0x86)
+ { Key::F24, VK_F24 }, // (0x87)
// 0x88-8F are reserved for UI navigation.
{ Key::NUMLOCK, VK_NUMLOCK }, // (0x90)
{ Key::SCROLLLOCK, VK_SCROLL }, // (0x91)
@@ -409,6 +416,14 @@ static _WinTranslatePair _scancode_to_keycode[] = {
{ Key::F14, 0x65 },
{ Key::F15, 0x66 },
{ Key::F16, 0x67 },
+ { Key::F17, 0x68 },
+ { Key::F18, 0x69 },
+ { Key::F19, 0x6A },
+ { Key::F20, 0x6B },
+ { Key::F21, 0x6C },
+ { Key::F22, 0x6D },
+ { Key::F23, 0x6E },
+ { Key::F24, 0x76 },
{ Key::UNKNOWN, 0 }
};
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index 8755bc65dc..ad4be950cc 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -48,6 +48,7 @@
#include <avrt.h>
#include <bcrypt.h>
#include <direct.h>
+#include <dwrite.h>
#include <knownfolders.h>
#include <process.h>
#include <regstr.h>
@@ -129,9 +130,34 @@ void OS_Windows::initialize_debugging() {
SetConsoleCtrlHandler(HandlerRoutine, TRUE);
}
+#ifdef WINDOWS_DEBUG_OUTPUT_ENABLED
+static void _error_handler(void *p_self, const char *p_func, const char *p_file, int p_line, const char *p_error, const char *p_errorexp, bool p_editor_notify, ErrorHandlerType p_type) {
+ String err_str;
+ if (p_errorexp && p_errorexp[0]) {
+ err_str = String::utf8(p_errorexp);
+ } else {
+ err_str = String::utf8(p_file) + ":" + itos(p_line) + " - " + String::utf8(p_error);
+ }
+
+ if (p_editor_notify) {
+ err_str += " (User)\n";
+ } else {
+ err_str += "\n";
+ }
+
+ OutputDebugStringW((LPCWSTR)err_str.utf16().ptr());
+}
+#endif
+
void OS_Windows::initialize() {
crash_handler.initialize();
+#ifdef WINDOWS_DEBUG_OUTPUT_ENABLED
+ error_handlers.errfunc = _error_handler;
+ error_handlers.userdata = this;
+ add_error_handler(&error_handlers);
+#endif
+
#ifndef WINDOWS_SUBSYSTEM_CONSOLE
RedirectIOToConsole();
#endif
@@ -153,7 +179,7 @@ void OS_Windows::initialize() {
// long as the windows scheduler resolution (~16-30ms) even for calls like Sleep(1)
timeBeginPeriod(1);
- process_map = memnew((Map<ProcessID, ProcessInfo>));
+ process_map = memnew((HashMap<ProcessID, ProcessInfo>));
// Add current Godot PID to the list of known PIDs
ProcessInfo current_pi = {};
@@ -194,6 +220,10 @@ void OS_Windows::finalize_core() {
memdelete(process_map);
NetSocketPosix::cleanup();
+
+#ifdef WINDOWS_DEBUG_OUTPUT_ENABLED
+ remove_error_handler(&error_handlers);
+#endif
}
Error OS_Windows::get_entropy(uint8_t *r_buffer, int p_bytes) {
@@ -202,7 +232,7 @@ Error OS_Windows::get_entropy(uint8_t *r_buffer, int p_bytes) {
return OK;
}
-Error OS_Windows::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path) {
+Error OS_Windows::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path, String *r_resolved_path) {
String path = p_path.replace("/", "\\");
if (!FileAccess::exists(path)) {
@@ -230,6 +260,10 @@ Error OS_Windows::open_dynamic_library(const String p_path, void *&p_library_han
remove_dll_directory(cookie);
}
+ if (r_resolved_path != nullptr) {
+ *r_resolved_path = path;
+ }
+
return OK;
}
@@ -383,6 +417,31 @@ String OS_Windows::_quote_command_line_argument(const String &p_text) const {
return p_text;
}
+static void _append_to_pipe(char *p_bytes, int p_size, String *r_pipe, Mutex *p_pipe_mutex) {
+ // Try to convert from default ANSI code page to Unicode.
+ LocalVector<wchar_t> wchars;
+ int total_wchars = MultiByteToWideChar(CP_ACP, 0, p_bytes, p_size, nullptr, 0);
+ if (total_wchars > 0) {
+ wchars.resize(total_wchars);
+ if (MultiByteToWideChar(CP_ACP, 0, p_bytes, p_size, wchars.ptr(), total_wchars) == 0) {
+ wchars.clear();
+ }
+ }
+
+ if (p_pipe_mutex) {
+ p_pipe_mutex->lock();
+ }
+ if (wchars.is_empty()) {
+ // Let's hope it's compatible with UTF-8.
+ (*r_pipe) += String::utf8(p_bytes, p_size);
+ } else {
+ (*r_pipe) += String(wchars.ptr(), total_wchars);
+ }
+ if (p_pipe_mutex) {
+ p_pipe_mutex->unlock();
+ }
+}
+
Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex, bool p_open_console) {
String path = p_path.replace("/", "\\");
String command = _quote_command_line_argument(path);
@@ -431,21 +490,44 @@ Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments,
if (r_pipe) {
CloseHandle(pipe[1]); // Close pipe write handle (only child process is writing).
- char buf[4096];
+
+ LocalVector<char> bytes;
+ int bytes_in_buffer = 0;
+
+ const int CHUNK_SIZE = 4096;
DWORD read = 0;
for (;;) { // Read StdOut and StdErr from pipe.
- bool success = ReadFile(pipe[0], buf, 4096, &read, NULL);
+ bytes.resize(bytes_in_buffer + CHUNK_SIZE);
+ const bool success = ReadFile(pipe[0], bytes.ptr() + bytes_in_buffer, CHUNK_SIZE, &read, NULL);
if (!success || read == 0) {
break;
}
- if (p_pipe_mutex) {
- p_pipe_mutex->lock();
+
+ // Assume that all possible encodings are ASCII-compatible.
+ // Break at newline to allow receiving long output in portions.
+ int newline_index = -1;
+ for (int i = read - 1; i >= 0; i--) {
+ if (bytes[bytes_in_buffer + i] == '\n') {
+ newline_index = i;
+ break;
+ }
}
- (*r_pipe) += String::utf8(buf, read);
- if (p_pipe_mutex) {
- p_pipe_mutex->unlock();
+ if (newline_index == -1) {
+ bytes_in_buffer += read;
+ continue;
}
+
+ const int bytes_to_convert = bytes_in_buffer + (newline_index + 1);
+ _append_to_pipe(bytes.ptr(), bytes_to_convert, r_pipe, p_pipe_mutex);
+
+ bytes_in_buffer = read - (newline_index + 1);
+ memmove(bytes.ptr(), bytes.ptr() + bytes_to_convert, bytes_in_buffer);
+ }
+
+ if (bytes_in_buffer > 0) {
+ _append_to_pipe(bytes.ptr(), bytes_in_buffer, r_pipe, p_pipe_mutex);
}
+
CloseHandle(pipe[0]); // Close pipe read handle.
} else {
WaitForSingleObject(pi.pi.hProcess, INFINITE);
@@ -513,6 +595,25 @@ int OS_Windows::get_process_id() const {
return _getpid();
}
+bool OS_Windows::is_process_running(const ProcessID &p_pid) const {
+ if (!process_map->has(p_pid)) {
+ return false;
+ }
+
+ const PROCESS_INFORMATION &pi = (*process_map)[p_pid].pi;
+
+ DWORD dw_exit_code = 0;
+ if (!GetExitCodeProcess(pi.hProcess, &dw_exit_code)) {
+ return false;
+ }
+
+ if (dw_exit_code != STILL_ACTIVE) {
+ return false;
+ }
+
+ return true;
+}
+
Error OS_Windows::set_cwd(const String &p_cwd) {
if (_wchdir((LPCWSTR)(p_cwd.utf16().get_data())) != 0) {
return ERR_CANT_OPEN;
@@ -521,6 +622,135 @@ Error OS_Windows::set_cwd(const String &p_cwd) {
return OK;
}
+Vector<String> OS_Windows::get_system_fonts() const {
+ Vector<String> ret;
+ HashSet<String> font_names;
+
+ ComAutoreleaseRef<IDWriteFactory> dwrite_factory;
+ HRESULT hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), reinterpret_cast<IUnknown **>(&dwrite_factory.reference));
+ ERR_FAIL_COND_V(FAILED(hr) || dwrite_factory.is_null(), ret);
+
+ ComAutoreleaseRef<IDWriteFontCollection> font_collection;
+ hr = dwrite_factory->GetSystemFontCollection(&font_collection.reference, false);
+ ERR_FAIL_COND_V(FAILED(hr) || font_collection.is_null(), ret);
+
+ UINT32 family_count = font_collection->GetFontFamilyCount();
+ for (UINT32 i = 0; i < family_count; i++) {
+ ComAutoreleaseRef<IDWriteFontFamily> family;
+ hr = font_collection->GetFontFamily(i, &family.reference);
+ ERR_CONTINUE(FAILED(hr) || family.is_null());
+
+ ComAutoreleaseRef<IDWriteLocalizedStrings> family_names;
+ hr = family->GetFamilyNames(&family_names.reference);
+ ERR_CONTINUE(FAILED(hr) || family_names.is_null());
+
+ UINT32 index = 0;
+ BOOL exists = false;
+ UINT32 length = 0;
+ Char16String name;
+
+ hr = family_names->FindLocaleName(L"en-us", &index, &exists);
+ ERR_CONTINUE(FAILED(hr));
+
+ hr = family_names->GetStringLength(index, &length);
+ ERR_CONTINUE(FAILED(hr));
+
+ name.resize(length + 1);
+ hr = family_names->GetString(index, (WCHAR *)name.ptrw(), length + 1);
+ ERR_CONTINUE(FAILED(hr));
+
+ font_names.insert(String::utf16(name.ptr(), length));
+ }
+
+ for (const String &E : font_names) {
+ ret.push_back(E);
+ }
+ return ret;
+}
+
+String OS_Windows::get_system_font_path(const String &p_font_name, bool p_bold, bool p_italic) const {
+ String font_name = p_font_name;
+ if (font_name.to_lower() == "sans-serif") {
+ font_name = "Arial";
+ } else if (font_name.to_lower() == "serif") {
+ font_name = "Times New Roman";
+ } else if (font_name.to_lower() == "monospace") {
+ font_name = "Courier New";
+ } else if (font_name.to_lower() == "cursive") {
+ font_name = "Comic Sans MS";
+ } else if (font_name.to_lower() == "fantasy") {
+ font_name = "Gabriola";
+ }
+
+ ComAutoreleaseRef<IDWriteFactory> dwrite_factory;
+ HRESULT hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), reinterpret_cast<IUnknown **>(&dwrite_factory.reference));
+ ERR_FAIL_COND_V(FAILED(hr) || dwrite_factory.is_null(), String());
+
+ ComAutoreleaseRef<IDWriteFontCollection> font_collection;
+ hr = dwrite_factory->GetSystemFontCollection(&font_collection.reference, false);
+ ERR_FAIL_COND_V(FAILED(hr) || font_collection.is_null(), String());
+
+ UINT32 index = 0;
+ BOOL exists = false;
+ font_collection->FindFamilyName((const WCHAR *)font_name.utf16().get_data(), &index, &exists);
+ if (FAILED(hr)) {
+ return String();
+ }
+
+ ComAutoreleaseRef<IDWriteFontFamily> family;
+ hr = font_collection->GetFontFamily(index, &family.reference);
+ if (FAILED(hr) || family.is_null()) {
+ return String();
+ }
+
+ ComAutoreleaseRef<IDWriteFont> dwrite_font;
+ hr = family->GetFirstMatchingFont(p_bold ? DWRITE_FONT_WEIGHT_BOLD : DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL, p_italic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL, &dwrite_font.reference);
+ if (FAILED(hr) || dwrite_font.is_null()) {
+ return String();
+ }
+
+ ComAutoreleaseRef<IDWriteFontFace> dwrite_face;
+ hr = dwrite_font->CreateFontFace(&dwrite_face.reference);
+ if (FAILED(hr) || dwrite_face.is_null()) {
+ return String();
+ }
+
+ UINT32 number_of_files = 0;
+ hr = dwrite_face->GetFiles(&number_of_files, nullptr);
+ if (FAILED(hr)) {
+ return String();
+ }
+ Vector<ComAutoreleaseRef<IDWriteFontFile>> files;
+ files.resize(number_of_files);
+ hr = dwrite_face->GetFiles(&number_of_files, (IDWriteFontFile **)files.ptrw());
+ if (FAILED(hr)) {
+ return String();
+ }
+
+ for (UINT32 i = 0; i < number_of_files; i++) {
+ void const *reference_key = nullptr;
+ UINT32 reference_key_size = 0;
+ ComAutoreleaseRef<IDWriteLocalFontFileLoader> loader;
+
+ hr = files.write[i]->GetLoader((IDWriteFontFileLoader **)&loader.reference);
+ if (FAILED(hr) || loader.is_null()) {
+ continue;
+ }
+ hr = files.write[i]->GetReferenceKey(&reference_key, &reference_key_size);
+ if (FAILED(hr)) {
+ continue;
+ }
+
+ WCHAR file_path[MAX_PATH];
+ hr = loader->GetFilePathFromKey(reference_key, reference_key_size, &file_path[0], MAX_PATH);
+ if (FAILED(hr)) {
+ continue;
+ }
+ return String::utf16((const char16_t *)&file_path[0]);
+ }
+ return String();
+}
+
String OS_Windows::get_executable_path() const {
WCHAR bufname[4096];
GetModuleFileNameW(nullptr, bufname, 4096);
@@ -851,9 +1081,9 @@ String OS_Windows::get_user_data_dir() const {
}
String OS_Windows::get_unique_id() const {
- HW_PROFILE_INFO HwProfInfo;
- ERR_FAIL_COND_V(!GetCurrentHwProfile(&HwProfInfo), "");
- return String::utf16((const char16_t *)(HwProfInfo.szHwProfileGuid), HW_PROFILE_GUIDLEN);
+ HW_PROFILE_INFOA HwProfInfo;
+ ERR_FAIL_COND_V(!GetCurrentHwProfileA(&HwProfInfo), "");
+ return String((HwProfInfo.szHwProfileGuid), HW_PROFILE_GUIDLEN);
}
bool OS_Windows::_check_internal_feature_support(const String &p_feature) {
diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h
index 370cb77fde..80fc860738 100644
--- a/platform/windows/os_windows.h
+++ b/platform/windows/os_windows.h
@@ -57,6 +57,31 @@
#include <windows.h>
#include <windowsx.h>
+#ifdef DEBUG_ENABLED
+// forward error messages to OutputDebugString
+#define WINDOWS_DEBUG_OUTPUT_ENABLED
+#endif
+
+template <class T>
+class ComAutoreleaseRef {
+public:
+ T *reference = nullptr;
+
+ _FORCE_INLINE_ T *operator->() { return reference; }
+ _FORCE_INLINE_ const T *operator->() const { return reference; }
+ _FORCE_INLINE_ T *operator*() { return reference; }
+ _FORCE_INLINE_ const T *operator*() const { return reference; }
+ _FORCE_INLINE_ bool is_valid() const { return reference != nullptr; }
+ _FORCE_INLINE_ bool is_null() const { return reference == nullptr; }
+ ComAutoreleaseRef() {}
+ ~ComAutoreleaseRef() {
+ if (reference != nullptr) {
+ reference->Release();
+ reference = nullptr;
+ }
+ }
+};
+
class JoypadWindows;
class OS_Windows : public OS {
#ifdef STDOUT_FILE
@@ -81,6 +106,10 @@ class OS_Windows : public OS {
CrashHandler crash_handler;
+#ifdef WINDOWS_DEBUG_OUTPUT_ENABLED
+ ErrorHandlerList error_handlers;
+#endif
+
bool force_quit;
HWND main_window;
@@ -101,14 +130,14 @@ protected:
STARTUPINFO si;
PROCESS_INFORMATION pi;
};
- Map<ProcessID, ProcessInfo> *process_map;
+ HashMap<ProcessID, ProcessInfo> *process_map;
public:
virtual void alert(const String &p_alert, const String &p_title = "ALERT!") override;
virtual Error get_entropy(uint8_t *r_buffer, int p_bytes) override;
- virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false) override;
+ virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false, String *r_resolved_path = nullptr) override;
virtual Error close_dynamic_library(void *p_library_handle) override;
virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional = false) override;
@@ -132,11 +161,15 @@ public:
virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr, bool p_open_console = false) override;
virtual Error kill(const ProcessID &p_pid) override;
virtual int get_process_id() const override;
+ virtual bool is_process_running(const ProcessID &p_pid) const override;
virtual bool has_environment(const String &p_var) const override;
virtual String get_environment(const String &p_var) const override;
virtual bool set_environment(const String &p_var, const String &p_value) const override;
+ virtual Vector<String> get_system_fonts() const override;
+ virtual String get_system_font_path(const String &p_font_name, bool p_bold = false, bool p_italic = false) const override;
+
virtual String get_executable_path() const override;
virtual String get_locale() const override;
@@ -175,4 +208,4 @@ public:
~OS_Windows();
};
-#endif
+#endif // OS_WINDOWS_H
diff --git a/platform/windows/tts_windows.cpp b/platform/windows/tts_windows.cpp
index 05249934ba..e5daf602e6 100644
--- a/platform/windows/tts_windows.cpp
+++ b/platform/windows/tts_windows.cpp
@@ -99,7 +99,7 @@ void TTS_Windows::_update_tts() {
UTData ut;
ut.string = text.utf16();
- ut.offset = pitch_tag.length(); // Substract injected <pitch> tag offset.
+ ut.offset = pitch_tag.length(); // Subtract injected <pitch> tag offset.
ut.id = message.id;
synth->SetVolume(message.volume);
diff --git a/platform/windows/tts_windows.h b/platform/windows/tts_windows.h
index 5da404baf9..d84a3d273a 100644
--- a/platform/windows/tts_windows.h
+++ b/platform/windows/tts_windows.h
@@ -33,7 +33,7 @@
#include "core/string/ustring.h"
#include "core/templates/list.h"
-#include "core/templates/map.h"
+#include "core/templates/rb_map.h"
#include "core/variant/array.h"
#include "servers/display_server.h"
@@ -54,7 +54,7 @@ class TTS_Windows {
int offset;
int id;
};
- Map<ULONG, UTData> ids;
+ RBMap<ULONG, UTData> ids;
static void __stdcall speech_event_callback(WPARAM wParam, LPARAM lParam);
void _update_tts();
diff --git a/platform/windows/vulkan_context_win.cpp b/platform/windows/vulkan_context_win.cpp
index 07c41395fb..e62c6c1dc8 100644
--- a/platform/windows/vulkan_context_win.cpp
+++ b/platform/windows/vulkan_context_win.cpp
@@ -28,6 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#if defined(WINDOWS_ENABLED) && defined(VULKAN_ENABLED)
+
#include "vulkan_context_win.h"
#ifdef USE_VOLK
#include <volk.h>
@@ -57,3 +59,5 @@ VulkanContextWindows::VulkanContextWindows() {
VulkanContextWindows::~VulkanContextWindows() {
}
+
+#endif
diff --git a/platform/windows/vulkan_context_win.h b/platform/windows/vulkan_context_win.h
index e68f0125ca..d5950a129a 100644
--- a/platform/windows/vulkan_context_win.h
+++ b/platform/windows/vulkan_context_win.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef VULKAN_DEVICE_WIN_H
-#define VULKAN_DEVICE_WIN_H
+#ifndef VULKAN_CONTEXT_WIN_H
+#define VULKAN_CONTEXT_WIN_H
#include "drivers/vulkan/vulkan_context.h"
@@ -46,4 +46,4 @@ public:
~VulkanContextWindows();
};
-#endif // VULKAN_DEVICE_WIN_H
+#endif // VULKAN_CONTEXT_WIN_H
diff --git a/platform/windows/windows_terminal_logger.h b/platform/windows/windows_terminal_logger.h
index 1045f12201..348a49c845 100644
--- a/platform/windows/windows_terminal_logger.h
+++ b/platform/windows/windows_terminal_logger.h
@@ -44,4 +44,4 @@ public:
#endif
-#endif
+#endif // WINDOWS_TERMINAL_LOGGER_H