summaryrefslogtreecommitdiffstats
path: root/platform/windows/display_server_windows.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'platform/windows/display_server_windows.cpp')
-rw-r--r--platform/windows/display_server_windows.cpp716
1 files changed, 549 insertions, 167 deletions
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index 16eabf6855..b6b713687f 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -35,9 +35,9 @@
#include "core/config/project_settings.h"
#include "core/io/marshalls.h"
+#include "core/version.h"
#include "drivers/png/png_driver_common.h"
#include "main/main.h"
-#include "scene/resources/atlas_texture.h"
#if defined(VULKAN_ENABLED)
#include "rendering_context_driver_vulkan_windows.h"
@@ -51,6 +51,9 @@
#include <avrt.h>
#include <dwmapi.h>
+#include <propkey.h>
+#include <propvarutil.h>
+#include <shellapi.h>
#include <shlwapi.h>
#include <shobjidl.h>
#include <wbemcli.h>
@@ -93,6 +96,11 @@ static void track_mouse_leave_event(HWND hWnd) {
bool DisplayServerWindows::has_feature(Feature p_feature) const {
switch (p_feature) {
+#ifndef DISABLE_DEPRECATED
+ case FEATURE_GLOBAL_MENU: {
+ return (native_menu && native_menu->has_feature(NativeMenu::FEATURE_GLOBAL_MENU));
+ } break;
+#endif
case FEATURE_SUBWINDOWS:
case FEATURE_TOUCHSCREEN:
case FEATURE_MOUSE:
@@ -106,6 +114,8 @@ bool DisplayServerWindows::has_feature(Feature p_feature) const {
case FEATURE_ICON:
case FEATURE_NATIVE_ICON:
case FEATURE_NATIVE_DIALOG:
+ case FEATURE_NATIVE_DIALOG_INPUT:
+ case FEATURE_NATIVE_DIALOG_FILE:
case FEATURE_SWAP_BUFFERS:
case FEATURE_KEEP_SCREEN_ON:
case FEATURE_TEXT_TO_SPEECH:
@@ -194,8 +204,8 @@ void DisplayServerWindows::_register_raw_input_devices(WindowID p_target_window)
rid[1].hwndTarget = windows[p_target_window].hWnd;
} else {
// Follow the keyboard focus
- rid[0].hwndTarget = 0;
- rid[1].hwndTarget = 0;
+ rid[0].hwndTarget = nullptr;
+ rid[1].hwndTarget = nullptr;
}
if (RegisterRawInputDevices(rid, 2, sizeof(rid[0])) == FALSE) {
@@ -264,7 +274,7 @@ public:
QITABENT(FileDialogEventHandler, IFileDialogEvents),
QITABENT(FileDialogEventHandler, IFileDialogControlEvents),
#endif
- { 0, 0 },
+ { nullptr, 0 },
};
return QISearch(this, qit, riid, ppv);
}
@@ -754,15 +764,15 @@ Ref<Image> DisplayServerWindows::clipboard_get_image() const {
}
} else if (IsClipboardFormatAvailable(CF_DIB)) {
HGLOBAL mem = GetClipboardData(CF_DIB);
- if (mem != NULL) {
+ if (mem != nullptr) {
BITMAPINFO *ptr = static_cast<BITMAPINFO *>(GlobalLock(mem));
- if (ptr != NULL) {
+ if (ptr != nullptr) {
BITMAPINFOHEADER *info = &ptr->bmiHeader;
void *dib_bits = (void *)(ptr->bmiColors);
// Draw DIB image to temporary DC surface and read it back as BGRA8.
- HDC dc = GetDC(0);
+ HDC dc = GetDC(nullptr);
if (dc) {
HDC hdc = CreateCompatibleDC(dc);
if (hdc) {
@@ -796,7 +806,7 @@ Ref<Image> DisplayServerWindows::clipboard_get_image() const {
}
DeleteDC(hdc);
}
- ReleaseDC(NULL, dc);
+ ReleaseDC(nullptr, dc);
}
GlobalUnlock(mem);
}
@@ -860,7 +870,7 @@ int DisplayServerWindows::get_screen_count() const {
}
int DisplayServerWindows::get_primary_screen() const {
- EnumScreenData data = { 0, 0, 0 };
+ EnumScreenData data = { 0, 0, nullptr };
EnumDisplayMonitors(nullptr, nullptr, _MonitorEnumProcPrim, (LPARAM)&data);
return data.screen;
}
@@ -895,8 +905,7 @@ static BOOL CALLBACK _MonitorEnumProcPos(HMONITOR hMonitor, HDC hdcMonitor, LPRE
static BOOL CALLBACK _MonitorEnumProcOrigin(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
EnumPosData *data = (EnumPosData *)dwData;
- data->pos.x = MIN(data->pos.x, lprcMonitor->left);
- data->pos.y = MIN(data->pos.y, lprcMonitor->top);
+ data->pos = data->pos.min(Point2(lprcMonitor->left, lprcMonitor->top));
return TRUE;
}
@@ -1108,16 +1117,16 @@ Color DisplayServerWindows::screen_get_pixel(const Point2i &p_position) const {
p.x = pos.x;
p.y = pos.y;
if (win81p_LogicalToPhysicalPointForPerMonitorDPI) {
- win81p_LogicalToPhysicalPointForPerMonitorDPI(0, &p);
+ win81p_LogicalToPhysicalPointForPerMonitorDPI(nullptr, &p);
}
- HDC dc = GetDC(0);
+ HDC dc = GetDC(nullptr);
if (dc) {
COLORREF col = GetPixel(dc, p.x, p.y);
if (col != CLR_INVALID) {
- ReleaseDC(NULL, dc);
+ ReleaseDC(nullptr, dc);
return Color(float(col & 0x000000FF) / 255.0f, float((col & 0x0000FF00) >> 8) / 255.0f, float((col & 0x00FF0000) >> 16) / 255.0f, 1.0f);
}
- ReleaseDC(NULL, dc);
+ ReleaseDC(nullptr, dc);
}
return Color();
@@ -1148,12 +1157,12 @@ Ref<Image> DisplayServerWindows::screen_get_image(int p_screen) const {
p2.x = pos.x + size.x;
p2.y = pos.y + size.y;
if (win81p_LogicalToPhysicalPointForPerMonitorDPI) {
- win81p_LogicalToPhysicalPointForPerMonitorDPI(0, &p1);
- win81p_LogicalToPhysicalPointForPerMonitorDPI(0, &p2);
+ win81p_LogicalToPhysicalPointForPerMonitorDPI(nullptr, &p1);
+ win81p_LogicalToPhysicalPointForPerMonitorDPI(nullptr, &p2);
}
Ref<Image> img;
- HDC dc = GetDC(0);
+ HDC dc = GetDC(nullptr);
if (dc) {
HDC hdc = CreateCompatibleDC(dc);
int width = p2.x - p1.x;
@@ -1186,7 +1195,7 @@ Ref<Image> DisplayServerWindows::screen_get_image(int p_screen) const {
}
DeleteDC(hdc);
}
- ReleaseDC(NULL, dc);
+ ReleaseDC(nullptr, dc);
}
return img;
@@ -1375,6 +1384,15 @@ void DisplayServerWindows::delete_sub_window(WindowID p_window) {
WindowData &wd = windows[p_window];
+ IPropertyStore *prop_store;
+ HRESULT hr = SHGetPropertyStoreForWindow(wd.hWnd, IID_IPropertyStore, (void **)&prop_store);
+ if (hr == S_OK) {
+ PROPVARIANT val;
+ PropVariantInit(&val);
+ prop_store->SetValue(PKEY_AppUserModel_ID, val);
+ prop_store->Release();
+ }
+
while (wd.transient_children.size()) {
window_set_transient(*wd.transient_children.begin(), INVALID_WINDOW_ID);
}
@@ -1403,7 +1421,7 @@ void DisplayServerWindows::delete_sub_window(WindowID p_window) {
if ((tablet_get_current_driver() == "wintab") && wintab_available && windows[p_window].wtctx) {
wintab_WTClose(windows[p_window].wtctx);
- windows[p_window].wtctx = 0;
+ windows[p_window].wtctx = nullptr;
}
DestroyWindow(windows[p_window].hWnd);
windows.erase(p_window);
@@ -1524,7 +1542,7 @@ Size2i DisplayServerWindows::window_get_title_size(const String &p_title, Window
return size;
}
- HDC hdc = GetDCEx(wd.hWnd, NULL, DCX_WINDOW);
+ HDC hdc = GetDCEx(wd.hWnd, nullptr, DCX_WINDOW);
if (hdc) {
Char16String s = p_title.utf16();
SIZE text_size;
@@ -1542,8 +1560,8 @@ Size2i DisplayServerWindows::window_get_title_size(const String &p_title, Window
ClientToScreen(wd.hWnd, (POINT *)&rect.right);
if (win81p_PhysicalToLogicalPointForPerMonitorDPI) {
- win81p_PhysicalToLogicalPointForPerMonitorDPI(0, (POINT *)&rect.left);
- win81p_PhysicalToLogicalPointForPerMonitorDPI(0, (POINT *)&rect.right);
+ win81p_PhysicalToLogicalPointForPerMonitorDPI(nullptr, (POINT *)&rect.left);
+ win81p_PhysicalToLogicalPointForPerMonitorDPI(nullptr, (POINT *)&rect.right);
}
size.x += (rect.right - rect.left);
@@ -1620,8 +1638,7 @@ void DisplayServerWindows::window_set_current_screen(int p_screen, WindowID p_wi
Size2i wsize = window_get_size(p_window);
wpos += srect.position;
- wpos.x = CLAMP(wpos.x, srect.position.x, srect.position.x + srect.size.width - wsize.width / 3);
- wpos.y = CLAMP(wpos.y, srect.position.y, srect.position.y + srect.size.height - wsize.height / 3);
+ wpos = wpos.clamp(srect.position, srect.position + srect.size - wsize / 3);
window_set_position(wpos, p_window);
}
}
@@ -1878,7 +1895,7 @@ Size2i DisplayServerWindows::window_get_size_with_decorations(WindowID p_window)
return Size2();
}
-void DisplayServerWindows::_get_window_style(bool p_main_window, bool p_fullscreen, bool p_multiwindow_fs, bool p_borderless, bool p_resizable, bool p_maximized, bool p_no_activate_focus, DWORD &r_style, DWORD &r_style_ex) {
+void DisplayServerWindows::_get_window_style(bool p_main_window, bool p_fullscreen, bool p_multiwindow_fs, bool p_borderless, bool p_resizable, bool p_maximized, bool p_maximized_fs, bool p_no_activate_focus, DWORD &r_style, DWORD &r_style_ex) {
// Windows docs for window styles:
// https://docs.microsoft.com/en-us/windows/win32/winmsg/window-styles
// https://docs.microsoft.com/en-us/windows/win32/winmsg/extended-window-styles
@@ -1892,7 +1909,17 @@ void DisplayServerWindows::_get_window_style(bool p_main_window, bool p_fullscre
if (p_fullscreen || p_borderless) {
r_style |= WS_POPUP; // p_borderless was WS_EX_TOOLWINDOW in the past.
- if ((p_fullscreen && p_multiwindow_fs) || p_maximized) {
+ if (p_maximized) {
+ r_style |= WS_MAXIMIZE;
+ }
+ if (!p_fullscreen) {
+ r_style |= WS_SYSMENU | WS_MINIMIZEBOX;
+
+ if (p_resizable) {
+ r_style |= WS_MAXIMIZEBOX;
+ }
+ }
+ if ((p_fullscreen && p_multiwindow_fs) || p_maximized_fs) {
r_style |= WS_BORDER; // Allows child windows to be displayed on top of full screen.
}
} else {
@@ -1928,7 +1955,7 @@ void DisplayServerWindows::_update_window_style(WindowID p_window, bool p_repain
DWORD style = 0;
DWORD style_ex = 0;
- _get_window_style(p_window == MAIN_WINDOW_ID, wd.fullscreen, wd.multiwindow_fs, wd.borderless, wd.resizable, wd.maximized, wd.no_focus || wd.is_popup, style, style_ex);
+ _get_window_style(p_window == MAIN_WINDOW_ID, wd.fullscreen, wd.multiwindow_fs, wd.borderless, wd.resizable, wd.maximized, wd.maximized_fs, wd.no_focus || wd.is_popup, style, style_ex);
SetWindowLongPtr(wd.hWnd, GWL_STYLE, style);
SetWindowLongPtr(wd.hWnd, GWL_EXSTYLE, style_ex);
@@ -1971,10 +1998,11 @@ void DisplayServerWindows::window_set_mode(WindowMode p_mode, WindowID p_window)
wd.pre_fs_valid = true;
}
+ ShowWindow(wd.hWnd, SW_RESTORE);
MoveWindow(wd.hWnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, TRUE);
if (restore_mouse_trails > 1) {
- SystemParametersInfoA(SPI_SETMOUSETRAILS, restore_mouse_trails, 0, 0);
+ SystemParametersInfoA(SPI_SETMOUSETRAILS, restore_mouse_trails, nullptr, 0);
restore_mouse_trails = 0;
}
}
@@ -2006,7 +2034,7 @@ void DisplayServerWindows::window_set_mode(WindowMode p_mode, WindowID p_window)
}
if ((p_mode == WINDOW_MODE_FULLSCREEN || p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN) && !wd.fullscreen) {
- if (wd.minimized) {
+ if (wd.minimized || wd.maximized) {
ShowWindow(wd.hWnd, SW_RESTORE);
}
wd.was_maximized = wd.maximized;
@@ -2031,7 +2059,7 @@ void DisplayServerWindows::window_set_mode(WindowMode p_mode, WindowID p_window)
// Save number of trails so we can restore when exiting, then turn off mouse trails
SystemParametersInfoA(SPI_GETMOUSETRAILS, 0, &restore_mouse_trails, 0);
if (restore_mouse_trails > 1) {
- SystemParametersInfoA(SPI_SETMOUSETRAILS, 0, 0, 0);
+ SystemParametersInfoA(SPI_SETMOUSETRAILS, 0, nullptr, 0);
}
}
}
@@ -2286,10 +2314,10 @@ void DisplayServerWindows::window_set_ime_active(const bool p_active, WindowID p
if (p_active) {
wd.ime_active = true;
ImmAssociateContext(wd.hWnd, wd.im_himc);
- CreateCaret(wd.hWnd, NULL, 1, 1);
+ CreateCaret(wd.hWnd, nullptr, 1, 1);
window_set_ime_position(wd.im_position, p_window);
} else {
- ImmAssociateContext(wd.hWnd, (HIMC)0);
+ ImmAssociateContext(wd.hWnd, (HIMC) nullptr);
DestroyCaret();
wd.ime_active = false;
}
@@ -2304,7 +2332,7 @@ void DisplayServerWindows::window_set_ime_position(const Point2i &p_pos, WindowI
wd.im_position = p_pos;
HIMC himc = ImmGetContext(wd.hWnd);
- if (himc == (HIMC)0) {
+ if (himc == (HIMC) nullptr) {
return;
}
@@ -2380,38 +2408,10 @@ void DisplayServerWindows::cursor_set_custom_image(const Ref<Resource> &p_cursor
cursors_cache.erase(p_shape);
}
- Ref<Texture2D> texture = p_cursor;
- ERR_FAIL_COND(!texture.is_valid());
- Ref<AtlasTexture> atlas_texture = p_cursor;
- Size2 texture_size;
Rect2 atlas_rect;
-
- if (atlas_texture.is_valid()) {
- texture = atlas_texture->get_atlas();
-
- atlas_rect.size.width = texture->get_width();
- atlas_rect.size.height = texture->get_height();
- atlas_rect.position.x = atlas_texture->get_region().position.x;
- atlas_rect.position.y = atlas_texture->get_region().position.y;
- texture_size.width = atlas_texture->get_region().size.x;
- texture_size.height = atlas_texture->get_region().size.y;
- } else {
- texture_size.width = texture->get_width();
- texture_size.height = texture->get_height();
- }
-
- ERR_FAIL_COND(p_hotspot.x < 0 || p_hotspot.y < 0);
- ERR_FAIL_COND(texture_size.width > 256 || texture_size.height > 256);
- ERR_FAIL_COND(p_hotspot.x > texture_size.width || p_hotspot.y > texture_size.height);
-
- Ref<Image> image = texture->get_image();
-
- ERR_FAIL_COND(!image.is_valid());
- if (image->is_compressed()) {
- image = image->duplicate(true);
- Error err = image->decompress();
- ERR_FAIL_COND_MSG(err != OK, "Couldn't decompress VRAM-compressed custom mouse cursor image. Switch to a lossless compression mode in the Import dock.");
- }
+ Ref<Image> image = _get_cursor_image_from_resource(p_cursor, p_hotspot, atlas_rect);
+ ERR_FAIL_COND(image.is_null());
+ Vector2i texture_size = image->get_size();
UINT image_size = texture_size.width * texture_size.height;
@@ -2440,7 +2440,7 @@ void DisplayServerWindows::cursor_set_custom_image(const Ref<Resource> &p_cursor
int row_index = floor(index / texture_size.width) + atlas_rect.position.y;
int column_index = (index % int(texture_size.width)) + atlas_rect.position.x;
- if (atlas_texture.is_valid()) {
+ if (atlas_rect.has_area()) {
column_index = MIN(column_index, atlas_rect.size.width - 1);
row_index = MIN(row_index, atlas_rect.size.height - 1);
}
@@ -2506,6 +2506,298 @@ void DisplayServerWindows::enable_for_stealing_focus(OS::ProcessID pid) {
AllowSetForegroundWindow(pid);
}
+static HRESULT CALLBACK win32_task_dialog_callback(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, LONG_PTR lpRefData) {
+ if (msg == TDN_CREATED) {
+ // To match the input text dialog.
+ SendMessageW(hwnd, WM_SETICON, ICON_BIG, 0);
+ SendMessageW(hwnd, WM_SETICON, ICON_SMALL, 0);
+ }
+
+ return 0;
+}
+
+Error DisplayServerWindows::dialog_show(String p_title, String p_description, Vector<String> p_buttons, const Callable &p_callback) {
+ _THREAD_SAFE_METHOD_
+
+ TASKDIALOGCONFIG config;
+ ZeroMemory(&config, sizeof(TASKDIALOGCONFIG));
+ config.cbSize = sizeof(TASKDIALOGCONFIG);
+
+ Char16String title = p_title.utf16();
+ Char16String message = p_description.utf16();
+ List<Char16String> buttons;
+ for (String s : p_buttons) {
+ buttons.push_back(s.utf16());
+ }
+
+ config.pszWindowTitle = (LPCWSTR)(title.get_data());
+ config.pszContent = (LPCWSTR)(message.get_data());
+
+ const int button_count = MIN(buttons.size(), 8);
+ config.cButtons = button_count;
+
+ // No dynamic stack array size :(
+ TASKDIALOG_BUTTON *tbuttons = button_count != 0 ? (TASKDIALOG_BUTTON *)alloca(sizeof(TASKDIALOG_BUTTON) * button_count) : nullptr;
+ if (tbuttons) {
+ for (int i = 0; i < button_count; i++) {
+ tbuttons[i].nButtonID = i;
+ tbuttons[i].pszButtonText = (LPCWSTR)(buttons[i].get_data());
+ }
+ }
+ config.pButtons = tbuttons;
+ config.pfCallback = win32_task_dialog_callback;
+
+ Error result = FAILED;
+ HMODULE comctl = LoadLibraryW(L"comctl32.dll");
+ if (comctl) {
+ typedef HRESULT(WINAPI * TaskDialogIndirectPtr)(const TASKDIALOGCONFIG *pTaskConfig, int *pnButton, int *pnRadioButton, BOOL *pfVerificationFlagChecked);
+
+ TaskDialogIndirectPtr task_dialog_indirect = (TaskDialogIndirectPtr)GetProcAddress(comctl, "TaskDialogIndirect");
+ int button_pressed;
+
+ if (task_dialog_indirect && SUCCEEDED(task_dialog_indirect(&config, &button_pressed, nullptr, nullptr))) {
+ if (!p_callback.is_null()) {
+ Variant button = button_pressed;
+ const Variant *args[1] = { &button };
+ Variant ret;
+ Callable::CallError ce;
+ p_callback.callp(args, 1, ret, ce);
+ if (ce.error != Callable::CallError::CALL_OK) {
+ ERR_PRINT(vformat("Failed to execute dialog callback: %s.", Variant::get_callable_error_text(p_callback, args, 1, ce)));
+ }
+ }
+
+ result = OK;
+ }
+ FreeLibrary(comctl);
+ } else {
+ ERR_PRINT("Unable to create native dialog.");
+ }
+
+ return result;
+}
+
+struct Win32InputTextDialogInit {
+ const char16_t *title;
+ const char16_t *description;
+ const char16_t *partial;
+ const Callable &callback;
+};
+
+static int scale_with_dpi(int p_pos, int p_dpi) {
+ return IsProcessDPIAware() ? (p_pos * p_dpi / 96) : p_pos;
+}
+
+static INT_PTR input_text_dialog_init(HWND hWnd, UINT code, WPARAM wParam, LPARAM lParam) {
+ Win32InputTextDialogInit init = *(Win32InputTextDialogInit *)lParam;
+ SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LONG_PTR)&init.callback); // Set dialog callback.
+
+ SetWindowTextW(hWnd, (LPCWSTR)init.title);
+
+ const int dpi = DisplayServerWindows::get_singleton()->screen_get_dpi();
+
+ const int margin = scale_with_dpi(7, dpi);
+ const SIZE dlg_size = { scale_with_dpi(300, dpi), scale_with_dpi(50, dpi) };
+
+ int str_len = lstrlenW((LPCWSTR)init.description);
+ SIZE str_size = { dlg_size.cx, 0 };
+ if (str_len > 0) {
+ HDC hdc = GetDC(nullptr);
+ RECT trect = { margin, margin, margin + dlg_size.cx, margin + dlg_size.cy };
+ SelectObject(hdc, (HFONT)SendMessageW(hWnd, WM_GETFONT, 0, 0));
+
+ // `+ margin` adds some space between the static text and the edit field.
+ // Don't scale this with DPI because DPI is already handled by DrawText.
+ str_size.cy = DrawTextW(hdc, (LPCWSTR)init.description, str_len, &trect, DT_LEFT | DT_WORDBREAK | DT_CALCRECT) + margin;
+
+ ReleaseDC(nullptr, hdc);
+ }
+
+ RECT crect, wrect;
+ GetClientRect(hWnd, &crect);
+ GetWindowRect(hWnd, &wrect);
+ int sw = GetSystemMetrics(SM_CXSCREEN);
+ int sh = GetSystemMetrics(SM_CYSCREEN);
+ int new_width = dlg_size.cx + margin * 2 + wrect.right - wrect.left - crect.right;
+ int new_height = dlg_size.cy + margin * 2 + wrect.bottom - wrect.top - crect.bottom + str_size.cy;
+
+ MoveWindow(hWnd, (sw - new_width) / 2, (sh - new_height) / 2, new_width, new_height, true);
+
+ HWND ok_button = GetDlgItem(hWnd, 1);
+ MoveWindow(ok_button,
+ dlg_size.cx + margin - scale_with_dpi(65, dpi),
+ dlg_size.cy + str_size.cy + margin - scale_with_dpi(20, dpi),
+ scale_with_dpi(65, dpi), scale_with_dpi(20, dpi), true);
+
+ HWND description = GetDlgItem(hWnd, 3);
+ MoveWindow(description, margin, margin, dlg_size.cx, str_size.cy, true);
+ SetWindowTextW(description, (LPCWSTR)init.description);
+
+ HWND text_edit = GetDlgItem(hWnd, 2);
+ MoveWindow(text_edit, margin, str_size.cy + margin, dlg_size.cx, scale_with_dpi(20, dpi), true);
+ SetWindowTextW(text_edit, (LPCWSTR)init.partial);
+
+ return TRUE;
+}
+
+static INT_PTR input_text_dialog_cmd_proc(HWND hWnd, UINT code, WPARAM wParam, LPARAM lParam) {
+ if (LOWORD(wParam) == 1) {
+ HWND text_edit = GetDlgItem(hWnd, 2);
+ ERR_FAIL_NULL_V(text_edit, false);
+
+ Char16String text;
+ text.resize(GetWindowTextLengthW(text_edit) + 1);
+ GetWindowTextW(text_edit, (LPWSTR)text.get_data(), text.size());
+
+ const Callable *callback = (const Callable *)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
+ if (callback && callback->is_valid()) {
+ Variant v_result = String((const wchar_t *)text.get_data());
+ Variant ret;
+ Callable::CallError ce;
+ const Variant *args[1] = { &v_result };
+
+ callback->callp(args, 1, ret, ce);
+ if (ce.error != Callable::CallError::CALL_OK) {
+ ERR_PRINT(vformat("Failed to execute input dialog callback: %s.", Variant::get_callable_error_text(*callback, args, 1, ce)));
+ }
+ }
+
+ return EndDialog(hWnd, 0);
+ }
+
+ return false;
+}
+
+static INT_PTR CALLBACK input_text_dialog_proc(HWND hWnd, UINT code, WPARAM wParam, LPARAM lParam) {
+ switch (code) {
+ case WM_INITDIALOG:
+ return input_text_dialog_init(hWnd, code, wParam, lParam);
+
+ case WM_COMMAND:
+ return input_text_dialog_cmd_proc(hWnd, code, wParam, lParam);
+
+ default:
+ return FALSE;
+ }
+}
+
+Error DisplayServerWindows::dialog_input_text(String p_title, String p_description, String p_partial, const Callable &p_callback) {
+#pragma pack(push, 1)
+
+ // NOTE: Use default/placeholder coordinates here. Windows uses its own coordinate system
+ // specifically for dialogs which relies on font sizes instead of pixels.
+ const struct {
+ WORD dlgVer; // must be 1
+ WORD signature; // must be 0xFFFF
+ DWORD helpID;
+ DWORD exStyle;
+ DWORD style;
+ WORD cDlgItems;
+ short x;
+ short y;
+ short cx;
+ short cy;
+ WCHAR menu[1]; // must be 0
+ WCHAR windowClass[7]; // must be "#32770" -- the default window class for dialogs
+ WCHAR title[1]; // must be 0
+ WORD pointsize;
+ WORD weight;
+ BYTE italic;
+ BYTE charset;
+ WCHAR font[13]; // must be "MS Shell Dlg"
+ } template_base = {
+ 1, 0xFFFF, 0, 0,
+ DS_SYSMODAL | DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU,
+ 3, 0, 0, 20, 20, L"", L"#32770", L"", 8, FW_NORMAL, 0, DEFAULT_CHARSET, L"MS Shell Dlg"
+ };
+
+ const struct {
+ DWORD helpID;
+ DWORD exStyle;
+ DWORD style;
+ short x;
+ short y;
+ short cx;
+ short cy;
+ DWORD id;
+ WCHAR windowClass[7]; // must be "Button"
+ WCHAR title[3]; // must be "OK"
+ WORD extraCount;
+ } ok_button = {
+ 0, 0, WS_VISIBLE | BS_DEFPUSHBUTTON, 0, 0, 50, 14, 1, WC_BUTTONW, L"OK", 0
+ };
+ const struct {
+ DWORD helpID;
+ DWORD exStyle;
+ DWORD style;
+ short x;
+ short y;
+ short cx;
+ short cy;
+ DWORD id;
+ WCHAR windowClass[5]; // must be "Edit"
+ WCHAR title[1]; // must be 0
+ WORD extraCount;
+ } text_field = {
+ 0, 0, WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL, 0, 0, 250, 14, 2, WC_EDITW, L"", 0
+ };
+ const struct {
+ DWORD helpID;
+ DWORD exStyle;
+ DWORD style;
+ short x;
+ short y;
+ short cx;
+ short cy;
+ DWORD id;
+ WCHAR windowClass[7]; // must be "Static"
+ WCHAR title[1]; // must be 0
+ WORD extraCount;
+ } static_text = {
+ 0, 0, WS_VISIBLE, 0, 0, 250, 14, 3, WC_STATICW, L"", 0
+ };
+
+#pragma pack(pop)
+
+ // Dialog template
+ const size_t data_size = sizeof(template_base) + (sizeof(template_base) % 4) +
+ sizeof(ok_button) + (sizeof(ok_button) % 4) +
+ sizeof(text_field) + (sizeof(text_field) % 4) +
+ sizeof(static_text) + (sizeof(static_text) % 4);
+
+ void *data_template = memalloc(data_size);
+ ERR_FAIL_NULL_V_MSG(data_template, FAILED, "Unable to allocate memory for the dialog template.");
+ ZeroMemory(data_template, data_size);
+
+ char *current_block = (char *)data_template;
+ CopyMemory(current_block, &template_base, sizeof(template_base));
+ current_block += sizeof(template_base) + (sizeof(template_base) % 4);
+ CopyMemory(current_block, &ok_button, sizeof(ok_button));
+ current_block += sizeof(ok_button) + (sizeof(ok_button) % 4);
+ CopyMemory(current_block, &text_field, sizeof(text_field));
+ current_block += sizeof(text_field) + (sizeof(text_field) % 4);
+ CopyMemory(current_block, &static_text, sizeof(static_text));
+
+ Char16String title16 = p_title.utf16();
+ Char16String description16 = p_description.utf16();
+ Char16String partial16 = p_partial.utf16();
+
+ Win32InputTextDialogInit init = {
+ title16.get_data(), description16.get_data(), partial16.get_data(), p_callback
+ };
+
+ // No modal dialogs for specific windows? Assume main window here.
+ INT_PTR ret = DialogBoxIndirectParamW(hInstance, (LPDLGTEMPLATEW)data_template, nullptr, (DLGPROC)input_text_dialog_proc, (LPARAM)(&init));
+
+ Error result = ret != -1 ? OK : FAILED;
+ memfree(data_template);
+
+ if (result == FAILED) {
+ ERR_PRINT("Unable to create native dialog.");
+ }
+ return result;
+}
+
int DisplayServerWindows::keyboard_get_layout_count() const {
return GetKeyboardLayoutList(0, nullptr);
}
@@ -2670,7 +2962,7 @@ String DisplayServerWindows::keyboard_get_layout_name(int p_index) const {
}
void DisplayServerWindows::process_events() {
- _THREAD_SAFE_METHOD_
+ _THREAD_SAFE_LOCK_
MSG msg;
@@ -2685,7 +2977,10 @@ void DisplayServerWindows::process_events() {
if (!drop_events) {
_process_key_events();
+ _THREAD_SAFE_UNLOCK_
Input::get_singleton()->flush_buffered_events();
+ } else {
+ _THREAD_SAFE_UNLOCK_
}
}
@@ -2698,9 +2993,14 @@ void DisplayServerWindows::force_process_and_drop_events() {
}
void DisplayServerWindows::release_rendering_thread() {
-}
-
-void DisplayServerWindows::make_rendering_thread() {
+#if defined(GLES3_ENABLED)
+ if (gl_manager_angle) {
+ gl_manager_angle->release_current();
+ }
+ if (gl_manager_native) {
+ gl_manager_native->release_current();
+ }
+#endif
}
void DisplayServerWindows::swap_buffers() {
@@ -3081,9 +3381,9 @@ void DisplayServerWindows::set_context(Context p_context) {
#define SIGNATURE_MASK 0xFFFFFF00
// Keeping the name suggested by Microsoft, but this macro really answers:
// Is this mouse event emulated from touch or pen input?
-#define IsPenEvent(dw) (((dw)&SIGNATURE_MASK) == MI_WP_SIGNATURE)
+#define IsPenEvent(dw) (((dw) & SIGNATURE_MASK) == MI_WP_SIGNATURE)
// This one tells whether the event comes from touchscreen (and not from pen).
-#define IsTouchEvent(dw) (IsPenEvent(dw) && ((dw)&0x80))
+#define IsTouchEvent(dw) (IsPenEvent(dw) && ((dw) & 0x80))
void DisplayServerWindows::_touch_event(WindowID p_window, bool p_pressed, float p_x, float p_y, int idx) {
if (touch_state.has(idx) == p_pressed) {
@@ -3141,7 +3441,6 @@ void DisplayServerWindows::_dispatch_input_events(const Ref<InputEvent> &p_event
}
void DisplayServerWindows::_dispatch_input_event(const Ref<InputEvent> &p_event) {
- _THREAD_SAFE_METHOD_
if (in_dispatch_input_event) {
return;
}
@@ -3383,6 +3682,9 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
// Process window messages.
switch (uMsg) {
+ case WM_MENUCOMMAND: {
+ native_menu->_menu_activate(HMENU(lParam), (int)wParam);
+ } break;
case WM_CREATE: {
if (is_dark_mode_supported() && dark_title_available) {
BOOL value = is_dark_mode();
@@ -3425,63 +3727,18 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
return MA_NOACTIVATE; // Do not activate, but process mouse messages.
}
} break;
- case WM_SETFOCUS: {
- windows[window_id].window_has_focus = true;
- last_focused_window = window_id;
-
- // Restore mouse mode.
- _set_mouse_mode_impl(mouse_mode);
-
- if (!app_focused) {
- if (OS::get_singleton()->get_main_loop()) {
- OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_FOCUS_IN);
- }
- app_focused = true;
- }
- } break;
- case WM_KILLFOCUS: {
- windows[window_id].window_has_focus = false;
- last_focused_window = window_id;
-
- // Release capture unconditionally because it can be set due to dragging, in addition to captured mode.
- ReleaseCapture();
-
- // Release every touch to avoid sticky points.
- for (const KeyValue<int, Vector2> &E : touch_state) {
- _touch_event(window_id, false, E.value.x, E.value.y, E.key);
- }
- touch_state.clear();
-
- bool self_steal = false;
- HWND new_hwnd = (HWND)wParam;
- if (IsWindow(new_hwnd)) {
- self_steal = true;
+ case WM_ACTIVATEAPP: {
+ bool new_app_focused = (bool)wParam;
+ if (new_app_focused == app_focused) {
+ break;
}
-
- if (!self_steal) {
- if (OS::get_singleton()->get_main_loop()) {
- OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_FOCUS_OUT);
- }
- app_focused = false;
+ app_focused = new_app_focused;
+ if (OS::get_singleton()->get_main_loop()) {
+ OS::get_singleton()->get_main_loop()->notification(app_focused ? MainLoop::NOTIFICATION_APPLICATION_FOCUS_IN : MainLoop::NOTIFICATION_APPLICATION_FOCUS_OUT);
}
} break;
- case WM_ACTIVATE: { // Watch for window activate message.
- if (!windows[window_id].window_focused) {
- _process_activate_event(window_id, wParam, lParam);
- } else {
- windows[window_id].saved_wparam = wParam;
- windows[window_id].saved_lparam = lParam;
-
- // Run a timer to prevent event catching warning if the focused window is closing.
- windows[window_id].focus_timer_id = SetTimer(windows[window_id].hWnd, 2, USER_TIMER_MINIMUM, (TIMERPROC) nullptr);
- }
- if (wParam != WA_INACTIVE) {
- track_mouse_leave_event(hWnd);
-
- if (!IsIconic(hWnd)) {
- SetFocus(hWnd);
- }
- }
+ case WM_ACTIVATE: {
+ _process_activate_event(window_id, wParam, lParam);
return 0; // Return to the message loop.
} break;
case WM_GETMINMAXINFO: {
@@ -3498,6 +3755,15 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
min_max_info->ptMaxTrackSize.x = windows[window_id].max_size.x + decor.x;
min_max_info->ptMaxTrackSize.y = windows[window_id].max_size.y + decor.y;
}
+ if (windows[window_id].borderless) {
+ Rect2i screen_rect = screen_get_usable_rect(window_get_current_screen(window_id));
+
+ // Set the size of (borderless) maximized mode to exclude taskbar (or any other panel) if present.
+ min_max_info->ptMaxPosition.x = screen_rect.position.x;
+ min_max_info->ptMaxPosition.y = screen_rect.position.y;
+ min_max_info->ptMaxSize.x = screen_rect.size.x;
+ min_max_info->ptMaxSize.y = screen_rect.size.y;
+ }
return 0;
}
} break;
@@ -3549,9 +3815,15 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
case SC_MONITORPOWER: // Monitor trying to enter powersave?
return 0; // Prevent from happening.
case SC_KEYMENU:
- if ((lParam >> 16) <= 0) {
+ Engine *engine = Engine::get_singleton();
+ if (((lParam >> 16) <= 0) && !engine->is_project_manager_hint() && !engine->is_editor_hint() && !GLOBAL_GET("application/run/enable_alt_space_menu")) {
+ return 0;
+ }
+ if (!alt_mem || !(GetAsyncKeyState(VK_SPACE) & (1 << 15))) {
return 0;
}
+ SendMessage(windows[window_id].hWnd, WM_SYSKEYUP, VK_SPACE, 0);
+ SendMessage(windows[window_id].hWnd, WM_SYSKEYUP, VK_MENU, 0);
}
} break;
case WM_INDICATOR_CALLBACK_MESSAGE: {
@@ -3580,9 +3852,6 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
} break;
case WM_CLOSE: // Did we receive a close message?
{
- if (windows[window_id].focus_timer_id != 0U) {
- KillTimer(windows[window_id].hWnd, windows[window_id].focus_timer_id);
- }
_send_window_event(windows[window_id], WINDOW_EVENT_CLOSE_REQUEST);
return 0; // Jump back.
@@ -3694,7 +3963,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
mm->set_relative_screen_position(mm->get_relative());
- if ((windows[window_id].window_has_focus || windows[window_id].is_popup) && mm->get_relative() != Vector2()) {
+ if ((windows[window_id].window_focused || windows[window_id].is_popup) && mm->get_relative() != Vector2()) {
Input::get_singleton()->parse_input_event(mm);
}
}
@@ -3742,7 +4011,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
windows[window_id].last_pen_inverted = inverted;
// Don't calculate relative mouse movement if we don't have focus in CAPTURED mode.
- if (!windows[window_id].window_has_focus && mouse_mode == MOUSE_MODE_CAPTURED) {
+ if (!windows[window_id].window_focused && mouse_mode == MOUSE_MODE_CAPTURED) {
break;
}
@@ -3792,7 +4061,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
mm->set_relative_screen_position(mm->get_relative());
old_x = mm->get_position().x;
old_y = mm->get_position().y;
- if (windows[window_id].window_has_focus || window_get_active_popup() == window_id) {
+ if (windows[window_id].window_focused || window_get_active_popup() == window_id) {
Input::get_singleton()->parse_input_event(mm);
}
}
@@ -3878,7 +4147,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
// Don't calculate relative mouse movement if we don't have focus in CAPTURED mode.
- if (!windows[window_id].window_has_focus && mouse_mode == MOUSE_MODE_CAPTURED) {
+ if (!windows[window_id].window_focused && mouse_mode == MOUSE_MODE_CAPTURED) {
break;
}
@@ -3941,7 +4210,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
mm->set_relative_screen_position(mm->get_relative());
old_x = mm->get_position().x;
old_y = mm->get_position().y;
- if (windows[window_id].window_has_focus || window_get_active_popup() == window_id) {
+ if (windows[window_id].window_focused || window_get_active_popup() == window_id) {
Input::get_singleton()->parse_input_event(mm);
}
@@ -3993,7 +4262,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
// Don't calculate relative mouse movement if we don't have focus in CAPTURED mode.
- if (!windows[window_id].window_has_focus && mouse_mode == MOUSE_MODE_CAPTURED) {
+ if (!windows[window_id].window_focused && mouse_mode == MOUSE_MODE_CAPTURED) {
break;
}
@@ -4285,10 +4554,23 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
window.minimized = true;
} else if (IsZoomed(hWnd)) {
window.maximized = true;
+
+ // If maximized_window_size == screen_size add 1px border to prevent switching to exclusive_fs.
+ if (!window.maximized_fs && window.borderless && window_rect.position == screen_position && window_rect.size == screen_size) {
+ // Window (borderless) was just maximized and the covers the entire screen.
+ window.maximized_fs = true;
+ _update_window_style(window_id, false);
+ }
} else if (window_rect.position == screen_position && window_rect.size == screen_size) {
window.fullscreen = true;
}
+ if (window.maximized_fs && !window.maximized) {
+ // Window (maximized and covering fullscreen) was just non-maximized.
+ window.maximized_fs = false;
+ _update_window_style(window_id, false);
+ }
+
if (!window.minimized) {
window.width = window_client_rect.size.width;
window.height = window_client_rect.size.height;
@@ -4341,10 +4623,6 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
if (!Main::is_iterating()) {
Main::iteration();
}
- } else if (wParam == windows[window_id].focus_timer_id) {
- _process_activate_event(window_id, windows[window_id].saved_wparam, windows[window_id].saved_lparam);
- KillTimer(windows[window_id].hWnd, wParam);
- windows[window_id].focus_timer_id = 0U;
}
} break;
case WM_SYSKEYUP:
@@ -4493,7 +4771,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
} break;
case WM_SETCURSOR: {
if (LOWORD(lParam) == HTCLIENT) {
- if (windows[window_id].window_has_focus && (mouse_mode == MOUSE_MODE_HIDDEN || mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED_HIDDEN)) {
+ if (windows[window_id].window_focused && (mouse_mode == MOUSE_MODE_HIDDEN || mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED_HIDDEN)) {
// Hide the cursor.
if (hCursor == nullptr) {
hCursor = SetCursor(nullptr);
@@ -4550,20 +4828,25 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
void DisplayServerWindows::_process_activate_event(WindowID p_window_id, WPARAM wParam, LPARAM lParam) {
if (LOWORD(wParam) == WA_ACTIVE || LOWORD(wParam) == WA_CLICKACTIVE) {
- _send_window_event(windows[p_window_id], WINDOW_EVENT_FOCUS_IN);
- windows[p_window_id].window_focused = true;
+ last_focused_window = p_window_id;
alt_mem = false;
control_mem = false;
shift_mem = false;
gr_mem = false;
-
- // Restore mouse mode.
_set_mouse_mode_impl(mouse_mode);
+ if (!IsIconic(windows[p_window_id].hWnd)) {
+ SetFocus(windows[p_window_id].hWnd);
+ }
+ windows[p_window_id].window_focused = true;
+ _send_window_event(windows[p_window_id], WINDOW_EVENT_FOCUS_IN);
} else { // WM_INACTIVE.
Input::get_singleton()->release_pressed_events();
- _send_window_event(windows[p_window_id], WINDOW_EVENT_FOCUS_OUT);
- windows[p_window_id].window_focused = false;
+ track_mouse_leave_event(windows[p_window_id].hWnd);
+ // Release capture unconditionally because it can be set due to dragging, in addition to captured mode.
+ ReleaseCapture();
alt_mem = false;
+ windows[p_window_id].window_focused = false;
+ _send_window_event(windows[p_window_id], WINDOW_EVENT_FOCUS_OUT);
}
if ((tablet_get_current_driver() == "wintab") && wintab_available && windows[p_window_id].wtctx) {
@@ -4731,7 +5014,7 @@ void DisplayServerWindows::_update_tablet_ctx(const String &p_old_driver, const
if ((p_old_driver == "wintab") && wintab_available && wd.wtctx) {
wintab_WTEnable(wd.wtctx, false);
wintab_WTClose(wd.wtctx);
- wd.wtctx = 0;
+ wd.wtctx = nullptr;
}
if ((p_new_driver == "wintab") && wintab_available) {
wintab_WTInfo(WTI_DEFSYSCTX, 0, &wd.wtlc);
@@ -4767,7 +5050,7 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
DWORD dwExStyle;
DWORD dwStyle;
- _get_window_style(window_id_counter == MAIN_WINDOW_ID, (p_mode == WINDOW_MODE_FULLSCREEN || p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN), p_mode != WINDOW_MODE_EXCLUSIVE_FULLSCREEN, p_flags & WINDOW_FLAG_BORDERLESS_BIT, !(p_flags & WINDOW_FLAG_RESIZE_DISABLED_BIT), p_mode == WINDOW_MODE_MAXIMIZED, (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) | (p_flags & WINDOW_FLAG_POPUP), dwStyle, dwExStyle);
+ _get_window_style(window_id_counter == MAIN_WINDOW_ID, (p_mode == WINDOW_MODE_FULLSCREEN || p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN), p_mode != WINDOW_MODE_EXCLUSIVE_FULLSCREEN, p_flags & WINDOW_FLAG_BORDERLESS_BIT, !(p_flags & WINDOW_FLAG_RESIZE_DISABLED_BIT), p_mode == WINDOW_MODE_MAXIMIZED, false, (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) | (p_flags & WINDOW_FLAG_POPUP), dwStyle, dwExStyle);
RECT WindowRect;
@@ -4792,8 +5075,7 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
Rect2i srect = screen_get_usable_rect(rq_screen);
Point2i wpos = p_rect.position;
if (srect != Rect2i()) {
- wpos.x = CLAMP(wpos.x, srect.position.x, srect.position.x + srect.size.width - p_rect.size.width / 3);
- wpos.y = CLAMP(wpos.y, srect.position.y, srect.position.y + srect.size.height - p_rect.size.height / 3);
+ wpos = wpos.clamp(srect.position, srect.position + srect.size - p_rect.size / 3);
}
WindowRect.left = wpos.x;
@@ -4820,8 +5102,6 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
dwExStyle,
L"Engine", L"",
dwStyle,
- // (GetSystemMetrics(SM_CXSCREEN) - WindowRect.right) / 2,
- // (GetSystemMetrics(SM_CYSCREEN) - WindowRect.bottom) / 2,
WindowRect.left,
WindowRect.top,
WindowRect.right - WindowRect.left,
@@ -4939,7 +5219,7 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
print_verbose("WinTab context creation failed.");
}
} else {
- wd.wtctx = 0;
+ wd.wtctx = nullptr;
}
if (p_mode == WINDOW_MODE_MAXIMIZED) {
@@ -4956,9 +5236,36 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
wd.last_pressure_update = 0;
wd.last_tilt = Vector2();
+ IPropertyStore *prop_store;
+ HRESULT hr = SHGetPropertyStoreForWindow(wd.hWnd, IID_IPropertyStore, (void **)&prop_store);
+ if (hr == S_OK) {
+ PROPVARIANT val;
+ String appname;
+ if (Engine::get_singleton()->is_editor_hint()) {
+ appname = "Godot.GodotEditor." + String(VERSION_BRANCH);
+ } else {
+ String name = GLOBAL_GET("application/config/name");
+ String version = GLOBAL_GET("application/config/version");
+ if (version.is_empty()) {
+ version = "0";
+ }
+ String clean_app_name = name.to_pascal_case();
+ for (int i = 0; i < clean_app_name.length(); i++) {
+ if (!is_ascii_alphanumeric_char(clean_app_name[i]) && clean_app_name[i] != '_' && clean_app_name[i] != '.') {
+ clean_app_name[i] = '_';
+ }
+ }
+ clean_app_name = clean_app_name.substr(0, 120 - version.length()).trim_suffix(".");
+ appname = "Godot." + clean_app_name + "." + version;
+ }
+ InitPropVariantFromString((PCWSTR)appname.utf16().get_data(), &val);
+ prop_store->SetValue(PKEY_AppUserModel_ID, val);
+ prop_store->Release();
+ }
+
// IME.
wd.im_himc = ImmGetContext(wd.hWnd);
- ImmAssociateContext(wd.hWnd, (HIMC)0);
+ ImmAssociateContext(wd.hWnd, (HIMC) nullptr);
wd.im_position = Vector2();
@@ -4976,6 +5283,12 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
wd.height = p_rect.size.height;
}
+ // Set size of maximized borderless window (by default it covers the entire screen).
+ if (p_mode == WINDOW_MODE_MAXIMIZED && (p_flags & WINDOW_FLAG_BORDERLESS_BIT)) {
+ Rect2i srect = screen_get_usable_rect(rq_screen);
+ SetWindowPos(wd.hWnd, HWND_TOP, srect.position.x, srect.position.y, srect.size.width, srect.size.height, SWP_NOZORDER | SWP_NOACTIVATE);
+ }
+
window_id_counter++;
}
@@ -5013,17 +5326,17 @@ Vector2i _get_device_ids(const String &p_device_name) {
REFCLSID clsid = CLSID_WbemLocator; // Unmarshaler CLSID
REFIID uuid = IID_IWbemLocator; // Interface UUID
- IWbemLocator *wbemLocator = NULL; // to get the services
- IWbemServices *wbemServices = NULL; // to get the class
- IEnumWbemClassObject *iter = NULL;
+ IWbemLocator *wbemLocator = nullptr; // to get the services
+ IWbemServices *wbemServices = nullptr; // to get the class
+ IEnumWbemClassObject *iter = nullptr;
IWbemClassObject *pnpSDriverObject[1]; // contains driver name, version, etc.
- HRESULT hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, uuid, (LPVOID *)&wbemLocator);
+ HRESULT hr = CoCreateInstance(clsid, nullptr, CLSCTX_INPROC_SERVER, uuid, (LPVOID *)&wbemLocator);
if (hr != S_OK) {
return Vector2i();
}
BSTR resource_name = SysAllocString(L"root\\CIMV2");
- hr = wbemLocator->ConnectServer(resource_name, NULL, NULL, NULL, 0, NULL, NULL, &wbemServices);
+ hr = wbemLocator->ConnectServer(resource_name, nullptr, nullptr, nullptr, 0, nullptr, nullptr, &wbemServices);
SysFreeString(resource_name);
SAFE_RELEASE(wbemLocator) // from now on, use `wbemServices`
@@ -5037,7 +5350,7 @@ Vector2i _get_device_ids(const String &p_device_name) {
const String gpu_device_class_query = vformat("SELECT * FROM Win32_PnPSignedDriver WHERE DeviceName = \"%s\"", p_device_name);
BSTR query = SysAllocString((const WCHAR *)gpu_device_class_query.utf16().get_data());
BSTR query_lang = SysAllocString(L"WQL");
- hr = wbemServices->ExecQuery(query_lang, query, WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY, NULL, &iter);
+ hr = wbemServices->ExecQuery(query_lang, query, WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY, nullptr, &iter);
SysFreeString(query_lang);
SysFreeString(query);
if (hr == S_OK) {
@@ -5048,7 +5361,7 @@ Vector2i _get_device_ids(const String &p_device_name) {
VARIANT did;
VariantInit(&did);
BSTR object_name = SysAllocString(L"DeviceID");
- hr = pnpSDriverObject[0]->Get(object_name, 0, &did, NULL, NULL);
+ hr = pnpSDriverObject[0]->Get(object_name, 0, &did, nullptr, nullptr);
SysFreeString(object_name);
if (hr == S_OK) {
String device_id = String(V_BSTR(&did));
@@ -5162,6 +5475,7 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
if (tts_enabled) {
tts = memnew(TTS_Windows);
}
+ native_menu = memnew(NativeMenuWindows);
// Enforce default keep screen on value.
screen_set_keep_on(GLOBAL_GET("display/window/energy_saving/keep_screen_on"));
@@ -5187,6 +5501,32 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
GetImmersiveColorFromColorSetEx = (GetImmersiveColorFromColorSetExPtr)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(95));
GetImmersiveColorTypeFromName = (GetImmersiveColorTypeFromNamePtr)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(96));
GetImmersiveUserColorSetPreference = (GetImmersiveUserColorSetPreferencePtr)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(98));
+ if (os_ver.dwBuildNumber >= 17763) {
+ AllowDarkModeForAppPtr AllowDarkModeForApp = nullptr;
+ SetPreferredAppModePtr SetPreferredAppMode = nullptr;
+ FlushMenuThemesPtr FlushMenuThemes = nullptr;
+ if (os_ver.dwBuildNumber < 18362) {
+ AllowDarkModeForApp = (AllowDarkModeForAppPtr)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(135));
+ } else {
+ SetPreferredAppMode = (SetPreferredAppModePtr)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(135));
+ FlushMenuThemes = (FlushMenuThemesPtr)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(136));
+ }
+ RefreshImmersiveColorPolicyStatePtr RefreshImmersiveColorPolicyState = (RefreshImmersiveColorPolicyStatePtr)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(104));
+ if (ShouldAppsUseDarkMode) {
+ bool dark_mode = ShouldAppsUseDarkMode();
+ if (SetPreferredAppMode) {
+ SetPreferredAppMode(dark_mode ? APPMODE_ALLOWDARK : APPMODE_DEFAULT);
+ } else if (AllowDarkModeForApp) {
+ AllowDarkModeForApp(dark_mode);
+ }
+ if (RefreshImmersiveColorPolicyState) {
+ RefreshImmersiveColorPolicyState();
+ }
+ if (FlushMenuThemes) {
+ FlushMenuThemes();
+ }
+ }
+ }
ux_theme_available = ShouldAppsUseDarkMode && GetImmersiveColorFromColorSetEx && GetImmersiveColorTypeFromName && GetImmersiveUserColorSetPreference;
if (os_ver.dwBuildNumber >= 18363) {
@@ -5245,6 +5585,23 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
}
}
+ HMODULE comctl32 = LoadLibraryW(L"comctl32.dll");
+ if (comctl32) {
+ typedef BOOL(WINAPI * InitCommonControlsExPtr)(_In_ const INITCOMMONCONTROLSEX *picce);
+ InitCommonControlsExPtr init_common_controls_ex = (InitCommonControlsExPtr)GetProcAddress(comctl32, "InitCommonControlsEx");
+
+ // Fails if the incorrect version was loaded. Probably not a big enough deal to print an error about.
+ if (init_common_controls_ex) {
+ INITCOMMONCONTROLSEX icc = {};
+ icc.dwICC = ICC_STANDARD_CLASSES;
+ icc.dwSize = sizeof(INITCOMMONCONTROLSEX);
+ if (!init_common_controls_ex(&icc)) {
+ WARN_PRINT("Unable to initialize Windows common controls. Native dialogs may not work properly.");
+ }
+ }
+ FreeLibrary(comctl32);
+ }
+
memset(&wc, 0, sizeof(WNDCLASSEXW));
wc.cbSize = sizeof(WNDCLASSEXW);
wc.style = CS_OWNDC | CS_DBLCLKS;
@@ -5295,7 +5652,7 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
if (rendering_driver == "opengl3") {
rendering_driver = "opengl3_angle";
}
-#else
+#elif defined(EGL_STATIC)
bool fallback = GLOBAL_GET("rendering/gl_compatibility/fallback_to_angle");
if (fallback && (rendering_driver == "opengl3")) {
Dictionary gl_info = detect_wgl();
@@ -5354,6 +5711,26 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
}
#endif
+ String appname;
+ if (Engine::get_singleton()->is_editor_hint()) {
+ appname = "Godot.GodotEditor." + String(VERSION_BRANCH);
+ } else {
+ String name = GLOBAL_GET("application/config/name");
+ String version = GLOBAL_GET("application/config/version");
+ if (version.is_empty()) {
+ version = "0";
+ }
+ String clean_app_name = name.to_pascal_case();
+ for (int i = 0; i < clean_app_name.length(); i++) {
+ if (!is_ascii_alphanumeric_char(clean_app_name[i]) && clean_app_name[i] != '_' && clean_app_name[i] != '.') {
+ clean_app_name[i] = '_';
+ }
+ }
+ clean_app_name = clean_app_name.substr(0, 120 - version.length()).trim_suffix(".");
+ appname = "Godot." + clean_app_name + "." + version;
+ }
+ SetCurrentProcessExplicitAppUserModelID((PCWSTR)appname.utf16().get_data());
+
mouse_monitor = SetWindowsHookEx(WH_MOUSE, ::MouseProc, nullptr, GetCurrentThreadId());
Point2i window_position;
@@ -5479,7 +5856,7 @@ DisplayServerWindows::~DisplayServerWindows() {
cursors_cache.clear();
// Destroy all status indicators.
- for (HashMap<IndicatorID, IndicatorData>::Iterator E = indicators.begin(); E;) {
+ for (HashMap<IndicatorID, IndicatorData>::Iterator E = indicators.begin(); E; ++E) {
NOTIFYICONDATAW ndat;
ZeroMemory(&ndat, sizeof(NOTIFYICONDATAW));
ndat.cbSize = sizeof(NOTIFYICONDATAW);
@@ -5501,6 +5878,11 @@ DisplayServerWindows::~DisplayServerWindows() {
// Close power request handle.
screen_set_keep_on(false);
+ if (native_menu) {
+ memdelete(native_menu);
+ native_menu = nullptr;
+ }
+
#ifdef GLES3_ENABLED
// destroy windows .. NYI?
// FIXME wglDeleteContext is never called
@@ -5518,7 +5900,7 @@ DisplayServerWindows::~DisplayServerWindows() {
#endif
if (wintab_available && windows[MAIN_WINDOW_ID].wtctx) {
wintab_WTClose(windows[MAIN_WINDOW_ID].wtctx);
- windows[MAIN_WINDOW_ID].wtctx = 0;
+ windows[MAIN_WINDOW_ID].wtctx = nullptr;
}
DestroyWindow(windows[MAIN_WINDOW_ID].hWnd);
}
@@ -5536,7 +5918,7 @@ DisplayServerWindows::~DisplayServerWindows() {
#endif
if (restore_mouse_trails > 1) {
- SystemParametersInfoA(SPI_SETMOUSETRAILS, restore_mouse_trails, 0, 0);
+ SystemParametersInfoA(SPI_SETMOUSETRAILS, restore_mouse_trails, nullptr, 0);
}
#ifdef GLES3_ENABLED
if (gl_manager_angle) {