diff options
Diffstat (limited to 'platform/windows')
-rw-r--r-- | platform/windows/README.md | 2 | ||||
-rw-r--r-- | platform/windows/display_server_windows.cpp | 276 | ||||
-rw-r--r-- | platform/windows/display_server_windows.h | 17 | ||||
-rw-r--r-- | platform/windows/export/export.cpp | 1 | ||||
-rw-r--r-- | platform/windows/export/export_plugin.cpp | 316 | ||||
-rw-r--r-- | platform/windows/export/export_plugin.h | 36 | ||||
-rw-r--r-- | platform/windows/joypad_windows.cpp | 25 | ||||
-rw-r--r-- | platform/windows/logo.png | bin | 1536 -> 0 bytes | |||
-rw-r--r-- | platform/windows/logo.svg | 1 | ||||
-rw-r--r-- | platform/windows/os_windows.cpp | 45 | ||||
-rw-r--r-- | platform/windows/os_windows.h | 5 | ||||
-rw-r--r-- | platform/windows/run_icon.svg | 1 |
12 files changed, 619 insertions, 106 deletions
diff --git a/platform/windows/README.md b/platform/windows/README.md index c04032ae1d..4c775576fe 100644 --- a/platform/windows/README.md +++ b/platform/windows/README.md @@ -7,7 +7,7 @@ used by this platform. ## Documentation -- [Compiling for Windows](https://docs.godotengine.org/en/latest/development/compiling/compiling_for_windows.html) +- [Compiling for Windows](https://docs.godotengine.org/en/latest/contributing/development/compiling/compiling_for_windows.html) - Instructions on building this platform port from source. - [Exporting for Windows](https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_windows.html) - Instructions on using the compiled export templates to export a project. diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index c203f17232..631543763b 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -254,10 +254,10 @@ void DisplayServerWindows::warp_mouse(const Point2i &p_position) { Point2i DisplayServerWindows::mouse_get_position() const { POINT p; GetCursorPos(&p); - return Point2i(p.x, p.y); + return Point2i(p.x, p.y) - _get_screens_origin(); } -MouseButton DisplayServerWindows::mouse_get_button_state() const { +BitField<MouseButtonMask> DisplayServerWindows::mouse_get_button_state() const { return last_button_state; } @@ -346,6 +346,17 @@ typedef struct { HMONITOR monitor; } EnumScreenData; +static BOOL CALLBACK _MonitorEnumProcPrim(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) { + EnumScreenData *data = (EnumScreenData *)dwData; + if ((lprcMonitor->left == 0) && (lprcMonitor->top == 0)) { + data->screen = data->count; + return FALSE; + } + + data->count++; + return TRUE; +} + static BOOL CALLBACK _MonitorEnumProcScreen(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) { EnumScreenData *data = (EnumScreenData *)dwData; if (data->monitor == hMonitor) { @@ -370,6 +381,12 @@ int DisplayServerWindows::get_screen_count() const { return data; } +int DisplayServerWindows::get_primary_screen() const { + EnumScreenData data = { 0, 0, 0 }; + EnumDisplayMonitors(nullptr, nullptr, _MonitorEnumProcPrim, (LPARAM)&data); + return data.screen; +} + typedef struct { int count; int screen; @@ -387,12 +404,39 @@ static BOOL CALLBACK _MonitorEnumProcPos(HMONITOR hMonitor, HDC hdcMonitor, LPRE return TRUE; } +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); + + return TRUE; +} + +Point2i DisplayServerWindows::_get_screens_origin() const { + _THREAD_SAFE_METHOD_ + + EnumPosData data = { 0, 0, Point2() }; + EnumDisplayMonitors(nullptr, nullptr, _MonitorEnumProcOrigin, (LPARAM)&data); + return data.pos; +} + Point2i DisplayServerWindows::screen_get_position(int p_screen) const { _THREAD_SAFE_METHOD_ - EnumPosData data = { 0, p_screen == SCREEN_OF_MAIN_WINDOW ? window_get_current_screen() : p_screen, Point2() }; + switch (p_screen) { + case SCREEN_PRIMARY: { + p_screen = get_primary_screen(); + } break; + case SCREEN_OF_MAIN_WINDOW: { + p_screen = window_get_current_screen(MAIN_WINDOW_ID); + } break; + default: + break; + } + + EnumPosData data = { 0, p_screen, Point2() }; EnumDisplayMonitors(nullptr, nullptr, _MonitorEnumProcPos, (LPARAM)&data); - return data.pos; + return data.pos - _get_screens_origin(); } typedef struct { @@ -427,7 +471,18 @@ static BOOL CALLBACK _MonitorEnumProcSize(HMONITOR hMonitor, HDC hdcMonitor, LPR Size2i DisplayServerWindows::screen_get_size(int p_screen) const { _THREAD_SAFE_METHOD_ - EnumSizeData data = { 0, p_screen == SCREEN_OF_MAIN_WINDOW ? window_get_current_screen() : p_screen, Size2() }; + switch (p_screen) { + case SCREEN_PRIMARY: { + p_screen = get_primary_screen(); + } break; + case SCREEN_OF_MAIN_WINDOW: { + p_screen = window_get_current_screen(MAIN_WINDOW_ID); + } break; + default: + break; + } + + EnumSizeData data = { 0, p_screen, Size2() }; EnumDisplayMonitors(nullptr, nullptr, _MonitorEnumProcSize, (LPARAM)&data); return data.size; } @@ -473,8 +528,20 @@ static BOOL CALLBACK _MonitorEnumProcRefreshRate(HMONITOR hMonitor, HDC hdcMonit Rect2i DisplayServerWindows::screen_get_usable_rect(int p_screen) const { _THREAD_SAFE_METHOD_ - EnumRectData data = { 0, p_screen == SCREEN_OF_MAIN_WINDOW ? window_get_current_screen() : p_screen, Rect2i() }; + switch (p_screen) { + case SCREEN_PRIMARY: { + p_screen = get_primary_screen(); + } break; + case SCREEN_OF_MAIN_WINDOW: { + p_screen = window_get_current_screen(MAIN_WINDOW_ID); + } break; + default: + break; + } + + EnumRectData data = { 0, p_screen, Rect2i() }; EnumDisplayMonitors(nullptr, nullptr, _MonitorEnumProcUsableSize, (LPARAM)&data); + data.rect.position -= _get_screens_origin(); return data.rect; } @@ -549,14 +616,36 @@ static BOOL CALLBACK _MonitorEnumProcDpi(HMONITOR hMonitor, HDC hdcMonitor, LPRE int DisplayServerWindows::screen_get_dpi(int p_screen) const { _THREAD_SAFE_METHOD_ - EnumDpiData data = { 0, p_screen == SCREEN_OF_MAIN_WINDOW ? window_get_current_screen() : p_screen, 72 }; + switch (p_screen) { + case SCREEN_PRIMARY: { + p_screen = get_primary_screen(); + } break; + case SCREEN_OF_MAIN_WINDOW: { + p_screen = window_get_current_screen(MAIN_WINDOW_ID); + } break; + default: + break; + } + + EnumDpiData data = { 0, p_screen, 72 }; EnumDisplayMonitors(nullptr, nullptr, _MonitorEnumProcDpi, (LPARAM)&data); return data.dpi; } float DisplayServerWindows::screen_get_refresh_rate(int p_screen) const { _THREAD_SAFE_METHOD_ - EnumRefreshRateData data = { 0, p_screen == SCREEN_OF_MAIN_WINDOW ? window_get_current_screen() : p_screen, SCREEN_REFRESH_RATE_FALLBACK }; + switch (p_screen) { + case SCREEN_PRIMARY: { + p_screen = get_primary_screen(); + } break; + case SCREEN_OF_MAIN_WINDOW: { + p_screen = window_get_current_screen(MAIN_WINDOW_ID); + } break; + default: + break; + } + + EnumRefreshRateData data = { 0, p_screen, SCREEN_REFRESH_RATE_FALLBACK }; EnumDisplayMonitors(nullptr, nullptr, _MonitorEnumProcRefreshRate, (LPARAM)&data); return data.rate; } @@ -612,9 +701,10 @@ Vector<DisplayServer::WindowID> DisplayServerWindows::get_window_list() const { } DisplayServer::WindowID DisplayServerWindows::get_window_at_screen_position(const Point2i &p_position) const { + Point2i offset = _get_screens_origin(); POINT p; - p.x = p_position.x; - p.y = p_position.y; + p.x = p_position.x + offset.x; + p.y = p_position.y + offset.y; HWND hwnd = WindowFromPoint(p); for (const KeyValue<WindowID, WindowData> &E : windows) { if (E.value.hWnd == hwnd) { @@ -625,10 +715,10 @@ DisplayServer::WindowID DisplayServerWindows::get_window_at_screen_position(cons return INVALID_WINDOW_ID; } -DisplayServer::WindowID DisplayServerWindows::create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect, int p_screen) { +DisplayServer::WindowID DisplayServerWindows::create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect) { _THREAD_SAFE_METHOD_ - WindowID window_id = _create_window(p_mode, p_vsync_mode, p_flags, p_rect, p_screen); + WindowID window_id = _create_window(p_mode, p_vsync_mode, p_flags, p_rect); ERR_FAIL_COND_V_MSG(window_id == INVALID_WINDOW_ID, INVALID_WINDOW_ID, "Failed to create sub window."); WindowData &wd = windows[window_id]; @@ -645,9 +735,23 @@ DisplayServer::WindowID DisplayServerWindows::create_sub_window(WindowMode p_mod if (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) { wd.no_focus = true; } + if (p_flags & WINDOW_FLAG_MOUSE_PASSTHROUGH_BIT) { + wd.mpass = true; + } if (p_flags & WINDOW_FLAG_POPUP_BIT) { wd.is_popup = true; } + if (p_flags & WINDOW_FLAG_TRANSPARENT_BIT) { + DWM_BLURBEHIND bb; + ZeroMemory(&bb, sizeof(bb)); + HRGN hRgn = CreateRectRgn(0, 0, -1, -1); + bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION; + bb.hRgnBlur = hRgn; + bb.fEnable = TRUE; + DwmEnableBlurBehindWindow(wd.hWnd, &bb); + + wd.layered_window = true; + } // Inherit icons from MAIN_WINDOW for all sub windows. HICON mainwindow_icon = (HICON)SendMessage(windows[MAIN_WINDOW_ID].hWnd, WM_GETICON, ICON_SMALL, 0); @@ -685,6 +789,9 @@ void DisplayServerWindows::show_window(WindowID p_id) { SetForegroundWindow(wd.hWnd); // Slightly higher priority. SetFocus(wd.hWnd); // Set keyboard focus. } + if (wd.always_on_top) { + SetWindowPos(wd.hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | ((wd.no_focus || wd.is_popup) ? SWP_NOACTIVATE : 0)); + } } void DisplayServerWindows::delete_sub_window(WindowID p_window) { @@ -828,7 +935,7 @@ void DisplayServerWindows::window_set_mouse_passthrough(const Vector<Vector2> &p void DisplayServerWindows::_update_window_mouse_passthrough(WindowID p_window) { ERR_FAIL_COND(!windows.has(p_window)); - if (windows[p_window].mpath.size() == 0) { + if (windows[p_window].mpass || windows[p_window].mpath.size() == 0) { SetWindowRgn(windows[p_window].hWnd, nullptr, TRUE); } else { POINT *points = (POINT *)memalloc(sizeof(POINT) * windows[p_window].mpath.size()); @@ -870,7 +977,7 @@ void DisplayServerWindows::window_set_current_screen(int p_screen, WindowID p_wi } const WindowData &wd = windows[p_window]; if (wd.fullscreen) { - Point2 pos = screen_get_position(p_screen); + Point2 pos = screen_get_position(p_screen) + _get_screens_origin(); Size2 size = screen_get_size(p_screen); MoveWindow(wd.hWnd, pos.x, pos.y, size.width, size.height, TRUE); @@ -911,7 +1018,7 @@ Point2i DisplayServerWindows::window_get_position(WindowID p_window) const { ClientToScreen(wd.hWnd, &point); - return Point2i(point.x, point.y); + return Point2i(point.x, point.y) - _get_screens_origin(); } Point2i DisplayServerWindows::window_get_position_with_decorations(WindowID p_window) const { @@ -926,7 +1033,7 @@ Point2i DisplayServerWindows::window_get_position_with_decorations(WindowID p_wi RECT r; if (GetWindowRect(wd.hWnd, &r)) { - return Point2i(r.left, r.top); + return Point2i(r.left, r.top) - _get_screens_origin(); } return Point2i(); @@ -956,11 +1063,13 @@ void DisplayServerWindows::window_set_position(const Point2i &p_position, Window return; } + Point2i offset = _get_screens_origin(); + RECT rc; - rc.left = p_position.x; - rc.right = p_position.x + wd.width; - rc.bottom = p_position.y + wd.height; - rc.top = p_position.y; + rc.left = p_position.x + offset.x; + rc.right = p_position.x + wd.width + offset.x; + rc.bottom = p_position.y + wd.height + offset.y; + rc.top = p_position.y + offset.y; const DWORD style = GetWindowLongPtr(wd.hWnd, GWL_STYLE); const DWORD exStyle = GetWindowLongPtr(wd.hWnd, GWL_EXSTYLE); @@ -1296,7 +1405,7 @@ void DisplayServerWindows::window_set_mode(WindowMode p_mode, WindowID p_window) } int cs = window_get_current_screen(p_window); - Point2 pos = screen_get_position(cs); + Point2 pos = screen_get_position(cs) + _get_screens_origin(); Size2 size = screen_get_size(cs); wd.fullscreen = true; @@ -1407,6 +1516,10 @@ void DisplayServerWindows::window_set_flag(WindowFlags p_flag, bool p_enabled, W wd.no_focus = p_enabled; _update_window_style(p_window); } break; + case WINDOW_FLAG_MOUSE_PASSTHROUGH: { + wd.mpass = p_enabled; + _update_window_mouse_passthrough(p_window); + } break; case WINDOW_FLAG_POPUP: { ERR_FAIL_COND_MSG(p_window == MAIN_WINDOW_ID, "Main window can't be popup."); ERR_FAIL_COND_MSG(IsWindowVisible(wd.hWnd) && (wd.is_popup != p_enabled), "Popup flag can't changed while window is opened."); @@ -1438,6 +1551,9 @@ bool DisplayServerWindows::window_get_flag(WindowFlags p_flag, WindowID p_window case WINDOW_FLAG_NO_FOCUS: { return wd.no_focus; } break; + case WINDOW_FLAG_MOUSE_PASSTHROUGH: { + return wd.mpass; + } break; case WINDOW_FLAG_POPUP: { return wd.is_popup; } break; @@ -2277,7 +2393,7 @@ LRESULT DisplayServerWindows::MouseProc(int code, WPARAM wParam, LPARAM lParam) case WM_RBUTTONDOWN: case WM_MBUTTONDOWN: { MOUSEHOOKSTRUCT *ms = (MOUSEHOOKSTRUCT *)lParam; - Point2i pos = Point2i(ms->pt.x, ms->pt.y); + Point2i pos = Point2i(ms->pt.x, ms->pt.y) - _get_screens_origin(); List<WindowID>::Element *C = nullptr; List<WindowID>::Element *E = popup_list.back(); // Find top popup to close. @@ -2372,6 +2488,11 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA // Process window messages. switch (uMsg) { + case WM_NCHITTEST: { + if (windows[window_id].mpass) { + return HTTRANSPARENT; + } + } break; case WM_MOUSEACTIVATE: { if (windows[window_id].no_focus) { return MA_NOACTIVATEANDEAT; // Do not activate, and discard mouse messages. @@ -2451,6 +2572,25 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA return 0; } } break; + case WM_ERASEBKGND: { + Color early_color; + if (!_get_window_early_clear_override(early_color)) { + break; + } + bool must_recreate_brush = !window_bkg_brush || window_bkg_brush_color != early_color.to_argb32(); + if (must_recreate_brush) { + if (window_bkg_brush) { + DeleteObject(window_bkg_brush); + } + window_bkg_brush = CreateSolidBrush(RGB(early_color.get_r8(), early_color.get_g8(), early_color.get_b8())); + } + HDC hdc = (HDC)wParam; + RECT rect = {}; + if (GetUpdateRect(hWnd, &rect, true)) { + FillRect(hdc, &rect, window_bkg_brush); + } + return 1; + } break; case WM_PAINT: { Main::force_redraw(); } break; @@ -3070,9 +3210,9 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA mb->set_alt_pressed(alt_mem); // mb->is_alt_pressed()=(wParam&MK_MENU)!=0; if (mb->is_pressed()) { - last_button_state |= mouse_button_to_mask(mb->get_button_index()); + last_button_state.set_flag(mouse_button_to_mask(mb->get_button_index())); } else { - last_button_state &= ~mouse_button_to_mask(mb->get_button_index()); + last_button_state.clear_flag(mouse_button_to_mask(mb->get_button_index())); } mb->set_button_mask(last_button_state); @@ -3113,7 +3253,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA // Send release for mouse wheel. Ref<InputEventMouseButton> mbd = mb->duplicate(); mbd->set_window_id(window_id); - last_button_state &= ~mouse_button_to_mask(mbd->get_button_index()); + last_button_state.clear_flag(mouse_button_to_mask(mbd->get_button_index())); mbd->set_button_mask(last_button_state); mbd->set_pressed(false); Input::get_singleton()->parse_input_event(mbd); @@ -3130,10 +3270,12 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA ClientToScreen(hWnd, (POINT *)&rect.left); ClientToScreen(hWnd, (POINT *)&rect.right); window_client_rect = Rect2i(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top); + window_client_rect.position -= _get_screens_origin(); RECT wrect; GetWindowRect(hWnd, &wrect); window_rect = Rect2i(wrect.left, wrect.top, wrect.right - wrect.left, wrect.bottom - wrect.top); + window_rect.position -= _get_screens_origin(); } WINDOWPOS *window_pos_params = (WINDOWPOS *)lParam; @@ -3539,11 +3681,11 @@ void DisplayServerWindows::_update_tablet_ctx(const String &p_old_driver, const } } -DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect, int p_screen) { +DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect) { 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, (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) | (p_flags & WINDOW_FLAG_POPUP), dwStyle, dwExStyle); RECT WindowRect; @@ -3552,40 +3694,38 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, WindowRect.top = p_rect.position.y; WindowRect.bottom = p_rect.position.y + p_rect.size.y; + int rq_screen = get_screen_from_rect(p_rect); + if (rq_screen < 0) { + rq_screen = get_primary_screen(); // Requested window rect is outside any screen bounds. + } + if (p_mode == WINDOW_MODE_FULLSCREEN || p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN) { - Rect2i screen_rect = Rect2i(screen_get_position(p_screen), screen_get_size(p_screen)); + Rect2i screen_rect = Rect2i(screen_get_position(rq_screen), screen_get_size(rq_screen)); WindowRect.left = screen_rect.position.x; WindowRect.right = screen_rect.position.x + screen_rect.size.x; WindowRect.top = screen_rect.position.y; WindowRect.bottom = screen_rect.position.y + screen_rect.size.y; } else { - int nearest_area = 0; - int pos_screen = -1; - for (int i = 0; i < get_screen_count(); i++) { - Rect2i r; - r.position = screen_get_position(i); - r.size = screen_get_size(i); - Rect2 inters = r.intersection(p_rect); - int area = inters.size.width * inters.size.height; - if (area > nearest_area) { - pos_screen = i; - nearest_area = area; - } + 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); } - Rect2i srect = screen_get_usable_rect(p_screen); - Point2i wpos = p_rect.position - ((pos_screen >= 0) ? screen_get_position(pos_screen) : Vector2i()); - wpos += srect.position; - 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); - WindowRect.left = wpos.x; WindowRect.right = wpos.x + p_rect.size.x; WindowRect.top = wpos.y; WindowRect.bottom = wpos.y + p_rect.size.y; } + Point2i offset = _get_screens_origin(); + WindowRect.left += offset.x; + WindowRect.right += offset.x; + WindowRect.top += offset.y; + WindowRect.bottom += offset.y; + AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle); WindowID id = window_id_counter; @@ -3794,7 +3934,7 @@ void DisplayServerWindows::tablet_set_current_driver(const String &p_driver) { } } -DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error) { +DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Error &r_error) { drop_events = false; key_event_pos = 0; @@ -3890,7 +4030,7 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win memset(&wc, 0, sizeof(WNDCLASSEXW)); wc.cbSize = sizeof(WNDCLASSEXW); - wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS; + wc.style = CS_OWNDC | CS_DBLCLKS; wc.lpfnWndProc = (WNDPROC)::WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; @@ -3941,15 +4081,17 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win mouse_monitor = SetWindowsHookEx(WH_MOUSE, ::MouseProc, nullptr, GetCurrentThreadId()); - Point2i window_position( - (screen_get_size(0).width - p_resolution.width) / 2, - (screen_get_size(0).height - p_resolution.height) / 2); - + Point2i window_position; if (p_position != nullptr) { window_position = *p_position; + } else { + if (p_screen == SCREEN_OF_MAIN_WINDOW) { + p_screen = SCREEN_PRIMARY; + } + window_position = screen_get_position(p_screen) + (screen_get_size(p_screen) - p_resolution) / 2; } - WindowID main_window = _create_window(p_mode, p_vsync_mode, 0, Rect2i(window_position, p_resolution), 0); + WindowID main_window = _create_window(p_mode, p_vsync_mode, 0, Rect2i(window_position, p_resolution)); ERR_FAIL_COND_MSG(main_window == INVALID_WINDOW_ID, "Failed to create main window."); joypad = new JoypadWindows(&windows[MAIN_WINDOW_ID].hWnd); @@ -4012,23 +4154,25 @@ Vector<String> DisplayServerWindows::get_rendering_drivers_func() { return drivers; } -DisplayServer *DisplayServerWindows::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error) { - DisplayServer *ds = memnew(DisplayServerWindows(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, r_error)); +DisplayServer *DisplayServerWindows::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Error &r_error) { + DisplayServer *ds = memnew(DisplayServerWindows(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, p_screen, r_error)); if (r_error != OK) { if (p_rendering_driver == "vulkan") { String executable_name = OS::get_singleton()->get_executable_path().get_file(); - OS::get_singleton()->alert("Your video card driver does not support the selected Vulkan version.\n" - "Please try updating your GPU driver or try using the OpenGL 3 driver.\n" - "You can enable the OpenGL 3 driver by starting the engine from the\n" - "command line with the command:\n'./" + - executable_name + " --rendering-driver opengl3'.\n " - "If you have updated your graphics drivers recently, try rebooting.", - "Unable to initialize Video driver"); + OS::get_singleton()->alert( + vformat("Your video card drivers seem not to support the required Vulkan version.\n\n" + "If possible, consider updating your video card drivers or using the OpenGL 3 driver.\n\n" + "You can enable the OpenGL 3 driver by starting the engine from the\n" + "command line with the command:\n'%s --rendering-driver opengl3'\n\n" + "If you have recently updated your video card drivers, try rebooting.", + executable_name), + "Unable to initialize Vulkan video driver"); } else { - OS::get_singleton()->alert("Your video card driver does not support the selected OpenGL version.\n" - "Please try updating your GPU driver.\n" - "If you have updated your graphics drivers recently, try rebooting.", - "Unable to initialize Video driver"); + OS::get_singleton()->alert( + "Your video card drivers seem not to support the required OpenGL 3.3 version.\n\n" + "If possible, consider updating your video card drivers.\n\n" + "If you have recently updated your video card drivers, try rebooting.", + "Unable to initialize OpenGL video driver"); } } return ds; diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h index f0171d50ad..ce4b94af59 100644 --- a/platform/windows/display_server_windows.h +++ b/platform/windows/display_server_windows.h @@ -370,6 +370,7 @@ class DisplayServerWindows : public DisplayServer { bool window_has_focus = false; bool exclusive = false; bool context_created = false; + bool mpass = false; // Used to transfer data between events using timer. WPARAM saved_wparam; @@ -426,7 +427,7 @@ class DisplayServerWindows : public DisplayServer { 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, int p_screen); + 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; RBMap<WindowID, WindowData> windows; @@ -446,12 +447,14 @@ class DisplayServerWindows : public DisplayServer { bool shift_mem = false; bool control_mem = false; bool meta_mem = false; - MouseButton last_button_state = MouseButton::NONE; + BitField<MouseButtonMask> last_button_state; bool use_raw_input = false; bool drop_events = false; bool in_dispatch_input_event = false; WNDCLASSEXW wc; + HBRUSH window_bkg_brush = nullptr; + uint32_t window_bkg_brush_color = 0; HCURSOR cursors[CURSOR_MAX] = { nullptr }; CursorShape cursor_shape = CursorShape::CURSOR_ARROW; @@ -476,6 +479,7 @@ class DisplayServerWindows : public DisplayServer { void _dispatch_input_event(const Ref<InputEvent> &p_event); LRESULT _handle_early_window_message(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + Point2i _get_screens_origin() const; public: LRESULT WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); @@ -505,12 +509,13 @@ public: virtual void warp_mouse(const Point2i &p_position) override; virtual Point2i mouse_get_position() const override; - virtual MouseButton mouse_get_button_state() const override; + virtual BitField<MouseButtonMask> mouse_get_button_state() const override; virtual void clipboard_set(const String &p_text) override; virtual String clipboard_get() const override; virtual int get_screen_count() const override; + virtual int get_primary_screen() const override; virtual Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; @@ -522,7 +527,7 @@ public: virtual Vector<DisplayServer::WindowID> get_window_list() const override; - virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i(), int p_screen = 0) override; + virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i()) override; virtual void show_window(WindowID p_window) override; virtual void delete_sub_window(WindowID p_window) override; @@ -623,11 +628,11 @@ public: virtual void set_context(Context p_context) override; - static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error); + static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Error &r_error); static Vector<String> get_rendering_drivers_func(); static void register_windows_driver(); - DisplayServerWindows(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error); + DisplayServerWindows(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Error &r_error); ~DisplayServerWindows(); }; diff --git a/platform/windows/export/export.cpp b/platform/windows/export/export.cpp index b0e2f5a05b..4112bb84b5 100644 --- a/platform/windows/export/export.cpp +++ b/platform/windows/export/export.cpp @@ -51,7 +51,6 @@ void register_windows_exporter() { Ref<EditorExportPlatformWindows> platform; platform.instantiate(); - 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_plugin.cpp b/platform/windows/export/export_plugin.cpp index 7c61a79fc8..bf32b16018 100644 --- a/platform/windows/export/export_plugin.cpp +++ b/platform/windows/export/export_plugin.cpp @@ -34,6 +34,14 @@ #include "core/io/image_loader.h" #include "editor/editor_node.h" #include "editor/editor_paths.h" +#include "editor/editor_scale.h" +#include "platform/windows/logo_svg.gen.h" +#include "platform/windows/run_icon_svg.gen.h" + +#include "modules/modules_enabled.gen.h" // For svg. +#ifdef MODULE_SVG_ENABLED +#include "modules/svg/image_loader_svg.h" +#endif Error EditorExportPlatformWindows::_process_icon(const Ref<EditorExportPreset> &p_preset, const String &p_src_path, const String &p_dst_path) { static const uint8_t icon_size[] = { 16, 32, 48, 64, 128, 0 /*256*/ }; @@ -168,9 +176,39 @@ Error EditorExportPlatformWindows::modify_template(const Ref<EditorExportPreset> } 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"; + bool export_as_zip = p_path.ends_with("zip"); + bool embedded = p_preset->get("binary_format/embed_pck"); + + String pkg_name; + if (String(ProjectSettings::get_singleton()->get("application/config/name")) != "") { + pkg_name = String(ProjectSettings::get_singleton()->get("application/config/name")); + } else { + pkg_name = "Unnamed"; + } + + pkg_name = OS::get_singleton()->get_safe_dir_name(pkg_name); + + // Setup temp folder. + String path = p_path; + String tmp_dir_path = EditorPaths::get_singleton()->get_cache_dir().path_join(pkg_name); + Ref<DirAccess> tmp_app_dir = DirAccess::create_for_path(tmp_dir_path); + if (export_as_zip) { + if (tmp_app_dir.is_null()) { + return ERR_CANT_CREATE; + } + if (DirAccess::exists(tmp_dir_path)) { + if (tmp_app_dir->change_dir(tmp_dir_path) == OK) { + tmp_app_dir->erase_contents_recursive(); + } + } + tmp_app_dir->make_dir_recursive(tmp_dir_path); + path = tmp_dir_path.path_join(p_path.get_file().get_basename() + ".exe"); + } + + // Export project. + String pck_path = path; + if (embedded) { + pck_path = pck_path.get_basename() + ".tmp"; } Error err = EditorExportPlatformPC::export_project(p_preset, p_debug, pck_path, p_flags); if (p_preset->get("codesign/enable") && err == OK) { @@ -181,7 +219,7 @@ Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset> } } - if (p_preset->get("binary_format/embed_pck") && err == OK) { + if (embedded && 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) { @@ -189,6 +227,27 @@ Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset> } } + // ZIP project. + if (export_as_zip) { + if (FileAccess::exists(p_path)) { + OS::get_singleton()->move_to_trash(p_path); + } + + Ref<FileAccess> io_fa_dst; + zlib_filefunc_def io_dst = zipio_create_io(&io_fa_dst); + zipFile zip = zipOpen2(p_path.utf8().get_data(), APPEND_STATUS_CREATE, nullptr, &io_dst); + + zip_folder_recursive(zip, tmp_dir_path, "", pkg_name); + + zipClose(zip, nullptr); + + if (tmp_app_dir->change_dir(tmp_dir_path) == OK) { + tmp_app_dir->erase_contents_recursive(); + tmp_app_dir->change_dir(".."); + tmp_app_dir->remove(pkg_name); + } + } + return err; } @@ -199,6 +258,7 @@ String EditorExportPlatformWindows::get_template_file_name(const String &p_targe List<String> EditorExportPlatformWindows::get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const { List<String> list; list.push_back("exe"); + list.push_back("zip"); return list; } @@ -212,6 +272,7 @@ bool EditorExportPlatformWindows::get_export_option_visibility(const EditorExpor 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,arm64"), "x86_64")); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/enable"), false)); @@ -235,6 +296,29 @@ void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_optio r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/file_description"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/copyright"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/trademarks"), "")); + + String run_script = "Expand-Archive -LiteralPath '{temp_dir}\\{archive_name}' -DestinationPath '{temp_dir}'\n" + "$action = New-ScheduledTaskAction -Execute '{temp_dir}\\{exe_name}' -Argument '{cmd_args}'\n" + "$trigger = New-ScheduledTaskTrigger -Once -At 00:00\n" + "$settings = New-ScheduledTaskSettingsSet\n" + "$task = New-ScheduledTask -Action $action -Trigger $trigger -Settings $settings\n" + "Register-ScheduledTask godot_remote_debug -InputObject $task -Force:$true\n" + "Start-ScheduledTask -TaskName godot_remote_debug\n" + "while (Get-ScheduledTask -TaskName godot_remote_debug | ? State -eq running) { Start-Sleep -Milliseconds 100 }\n" + "Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue"; + + String cleanup_script = "Stop-ScheduledTask -TaskName godot_remote_debug -ErrorAction:SilentlyContinue\n" + "Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue\n" + "Remove-Item -Recurse -Force '{temp_dir}'"; + + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "ssh_remote_deploy/enabled"), false)); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/host"), "user@host_ip")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/port"), "22")); + + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/extra_args_ssh", PROPERTY_HINT_MULTILINE_TEXT), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/extra_args_scp", PROPERTY_HINT_MULTILINE_TEXT), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/run_script", PROPERTY_HINT_MULTILINE_TEXT), run_script)); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/cleanup_script", PROPERTY_HINT_MULTILINE_TEXT), cleanup_script)); } Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset> &p_preset, const String &p_path, bool p_console_icon) { @@ -659,3 +743,227 @@ Error EditorExportPlatformWindows::fixup_embedded_pck(const String &p_path, int6 } return OK; } + +Ref<Texture2D> EditorExportPlatformWindows::get_run_icon() const { + return run_icon; +} + +bool EditorExportPlatformWindows::poll_export() { + Ref<EditorExportPreset> preset; + + for (int i = 0; i < EditorExport::get_singleton()->get_export_preset_count(); i++) { + Ref<EditorExportPreset> ep = EditorExport::get_singleton()->get_export_preset(i); + if (ep->is_runnable() && ep->get_platform() == this) { + preset = ep; + break; + } + } + + int prev = menu_options; + menu_options = (preset.is_valid() && preset->get("ssh_remote_deploy/enabled").operator bool()); + if (ssh_pid != 0 || !cleanup_commands.is_empty()) { + if (menu_options == 0) { + cleanup(); + } else { + menu_options += 1; + } + } + return menu_options != prev; +} + +Ref<ImageTexture> EditorExportPlatformWindows::get_option_icon(int p_index) const { + return p_index == 1 ? stop_icon : EditorExportPlatform::get_option_icon(p_index); +} + +int EditorExportPlatformWindows::get_options_count() const { + return menu_options; +} + +String EditorExportPlatformWindows::get_option_label(int p_index) const { + return (p_index) ? TTR("Stop and uninstall") : TTR("Run on remote Windows system"); +} + +String EditorExportPlatformWindows::get_option_tooltip(int p_index) const { + return (p_index) ? TTR("Stop and uninstall running project from the remote system") : TTR("Run exported project on remote Windows system"); +} + +void EditorExportPlatformWindows::cleanup() { + if (ssh_pid != 0 && OS::get_singleton()->is_process_running(ssh_pid)) { + print_line("Terminating connection..."); + OS::get_singleton()->kill(ssh_pid); + OS::get_singleton()->delay_usec(1000); + } + + if (!cleanup_commands.is_empty()) { + print_line("Stopping and deleting previous version..."); + for (const SSHCleanupCommand &cmd : cleanup_commands) { + if (cmd.wait) { + ssh_run_on_remote(cmd.host, cmd.port, cmd.ssh_args, cmd.cmd_args); + } else { + ssh_run_on_remote_no_wait(cmd.host, cmd.port, cmd.ssh_args, cmd.cmd_args); + } + } + } + ssh_pid = 0; + cleanup_commands.clear(); +} + +Error EditorExportPlatformWindows::run(const Ref<EditorExportPreset> &p_preset, int p_device, int p_debug_flags) { + cleanup(); + if (p_device) { // Stop command, cleanup only. + return OK; + } + + EditorProgress ep("run", TTR("Running..."), 5); + + const String dest = EditorPaths::get_singleton()->get_cache_dir().path_join("windows"); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + if (!da->dir_exists(dest)) { + Error err = da->make_dir_recursive(dest); + if (err != OK) { + EditorNode::get_singleton()->show_warning(TTR("Could not create temp directory:") + "\n" + dest); + return err; + } + } + + String host = p_preset->get("ssh_remote_deploy/host").operator String(); + String port = p_preset->get("ssh_remote_deploy/port").operator String(); + if (port.is_empty()) { + port = "22"; + } + Vector<String> extra_args_ssh = p_preset->get("ssh_remote_deploy/extra_args_ssh").operator String().split(" "); + Vector<String> extra_args_scp = p_preset->get("ssh_remote_deploy/extra_args_scp").operator String().split(" "); + + const String basepath = dest.path_join("tmp_windows_export"); + +#define CLEANUP_AND_RETURN(m_err) \ + { \ + if (da->file_exists(basepath + ".zip")) { \ + da->remove(basepath + ".zip"); \ + } \ + if (da->file_exists(basepath + "_start.ps1")) { \ + da->remove(basepath + "_start.ps1"); \ + } \ + if (da->file_exists(basepath + "_clean.ps1")) { \ + da->remove(basepath + "_clean.ps1"); \ + } \ + return m_err; \ + } \ + ((void)0) + + if (ep.step(TTR("Exporting project..."), 1)) { + return ERR_SKIP; + } + Error err = export_project(p_preset, true, basepath + ".zip", p_debug_flags); + if (err != OK) { + DirAccess::remove_file_or_error(basepath + ".zip"); + return err; + } + + String cmd_args; + { + Vector<String> cmd_args_list; + gen_debug_flags(cmd_args_list, p_debug_flags); + for (int i = 0; i < cmd_args_list.size(); i++) { + if (i != 0) { + cmd_args += " "; + } + cmd_args += cmd_args_list[i]; + } + } + + const bool use_remote = (p_debug_flags & DEBUG_FLAG_REMOTE_DEBUG) || (p_debug_flags & DEBUG_FLAG_DUMB_CLIENT); + int dbg_port = EditorSettings::get_singleton()->get("network/debug/remote_port"); + + print_line("Creating temporary directory..."); + ep.step(TTR("Creating temporary directory..."), 2); + String temp_dir; + err = ssh_run_on_remote(host, port, extra_args_ssh, "powershell -command \\\"\\$tmp = Join-Path \\$Env:Temp \\$(New-Guid); New-Item -Type Directory -Path \\$tmp | Out-Null; Write-Output \\$tmp\\\"", &temp_dir); + if (err != OK || temp_dir.is_empty()) { + CLEANUP_AND_RETURN(err); + } + + print_line("Uploading archive..."); + ep.step(TTR("Uploading archive..."), 3); + err = ssh_push_to_remote(host, port, extra_args_scp, basepath + ".zip", temp_dir); + if (err != OK) { + CLEANUP_AND_RETURN(err); + } + + { + String run_script = p_preset->get("ssh_remote_deploy/run_script"); + run_script = run_script.replace("{temp_dir}", temp_dir); + run_script = run_script.replace("{archive_name}", basepath.get_file() + ".zip"); + run_script = run_script.replace("{exe_name}", basepath.get_file() + ".exe"); + run_script = run_script.replace("{cmd_args}", cmd_args); + + Ref<FileAccess> f = FileAccess::open(basepath + "_start.ps1", FileAccess::WRITE); + if (f.is_null()) { + CLEANUP_AND_RETURN(err); + } + + f->store_string(run_script); + } + + { + String clean_script = p_preset->get("ssh_remote_deploy/cleanup_script"); + clean_script = clean_script.replace("{temp_dir}", temp_dir); + clean_script = clean_script.replace("{archive_name}", basepath.get_file() + ".zip"); + clean_script = clean_script.replace("{exe_name}", basepath.get_file() + ".exe"); + clean_script = clean_script.replace("{cmd_args}", cmd_args); + + Ref<FileAccess> f = FileAccess::open(basepath + "_clean.ps1", FileAccess::WRITE); + if (f.is_null()) { + CLEANUP_AND_RETURN(err); + } + + f->store_string(clean_script); + } + + print_line("Uploading scripts..."); + ep.step(TTR("Uploading scripts..."), 4); + err = ssh_push_to_remote(host, port, extra_args_scp, basepath + "_start.ps1", temp_dir); + if (err != OK) { + CLEANUP_AND_RETURN(err); + } + err = ssh_push_to_remote(host, port, extra_args_scp, basepath + "_clean.ps1", temp_dir); + if (err != OK) { + CLEANUP_AND_RETURN(err); + } + + print_line("Starting project..."); + ep.step(TTR("Starting project..."), 5); + err = ssh_run_on_remote_no_wait(host, port, extra_args_ssh, vformat("powershell -file \"%s\\%s\"", temp_dir, basepath.get_file() + "_start.ps1"), &ssh_pid, (use_remote) ? dbg_port : -1); + if (err != OK) { + CLEANUP_AND_RETURN(err); + } + + cleanup_commands.clear(); + cleanup_commands.push_back(SSHCleanupCommand(host, port, extra_args_ssh, vformat("powershell -file \"%s\\%s\"", temp_dir, basepath.get_file() + "_clean.ps1"))); + + print_line("Project started."); + + CLEANUP_AND_RETURN(OK); +#undef CLEANUP_AND_RETURN +} + +EditorExportPlatformWindows::EditorExportPlatformWindows() { +#ifdef MODULE_SVG_ENABLED + Ref<Image> img = memnew(Image); + const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE); + + ImageLoaderSVG img_loader; + img_loader.create_image_from_string(img, _windows_logo_svg, EDSCALE, upsample, false); + set_logo(ImageTexture::create_from_image(img)); + + img_loader.create_image_from_string(img, _windows_run_icon_svg, EDSCALE, upsample, false); + run_icon = ImageTexture::create_from_image(img); +#endif + + Ref<Theme> theme = EditorNode::get_singleton()->get_editor_theme(); + if (theme.is_valid()) { + stop_icon = theme->get_icon(SNAME("Stop"), SNAME("EditorIcons")); + } else { + stop_icon.instantiate(); + } +} diff --git a/platform/windows/export/export_plugin.h b/platform/windows/export/export_plugin.h index 96608728d3..fa75a17a1f 100644 --- a/platform/windows/export/export_plugin.h +++ b/platform/windows/export/export_plugin.h @@ -35,9 +35,32 @@ #include "core/os/os.h" #include "editor/editor_settings.h" #include "editor/export/editor_export_platform_pc.h" -#include "platform/windows/logo.gen.h" class EditorExportPlatformWindows : public EditorExportPlatformPC { + struct SSHCleanupCommand { + String host; + String port; + Vector<String> ssh_args; + String cmd_args; + bool wait = false; + + SSHCleanupCommand(){}; + SSHCleanupCommand(const String &p_host, const String &p_port, const Vector<String> &p_ssh_arg, const String &p_cmd_args, bool p_wait = false) { + host = p_host; + port = p_port; + ssh_args = p_ssh_arg; + cmd_args = p_cmd_args; + wait = p_wait; + }; + }; + + Ref<ImageTexture> run_icon; + Ref<ImageTexture> stop_icon; + + Vector<SSHCleanupCommand> cleanup_commands; + OS::ProcessID ssh_pid = 0; + int menu_options = 0; + Error _process_icon(const Ref<EditorExportPreset> &p_preset, const String &p_src_path, const String &p_dst_path); Error _rcedit_add_data(const Ref<EditorExportPreset> &p_preset, const String &p_path, bool p_console_icon); Error _code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path); @@ -53,6 +76,17 @@ public: virtual bool get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option, const HashMap<StringName, Variant> &p_options) 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) override; + + virtual Ref<Texture2D> get_run_icon() const override; + virtual bool poll_export() override; + virtual Ref<ImageTexture> get_option_icon(int p_index) const override; + virtual int get_options_count() const override; + virtual String get_option_label(int p_index) const override; + virtual String get_option_tooltip(int p_index) const override; + virtual Error run(const Ref<EditorExportPreset> &p_preset, int p_device, int p_debug_flags) override; + virtual void cleanup() override; + + EditorExportPlatformWindows(); }; #endif // WINDOWS_EXPORT_PLUGIN_H diff --git a/platform/windows/joypad_windows.cpp b/platform/windows/joypad_windows.cpp index aed5f5b8dc..183958cf40 100644 --- a/platform/windows/joypad_windows.cpp +++ b/platform/windows/joypad_windows.cpp @@ -420,38 +420,43 @@ void JoypadWindows::process_joypads() { } void JoypadWindows::post_hat(int p_device, DWORD p_dpad) { - HatMask dpad_val = (HatMask)0; + BitField<HatMask> dpad_val; // Should be -1 when centered, but according to docs: // "Some drivers report the centered position of the POV indicator as 65,535. Determine whether the indicator is centered as follows: // BOOL POVCentered = (LOWORD(dwPOV) == 0xFFFF);" // https://docs.microsoft.com/en-us/previous-versions/windows/desktop/ee416628(v%3Dvs.85)#remarks if (LOWORD(p_dpad) == 0xFFFF) { - dpad_val = (HatMask)HatMask::CENTER; + // Do nothing. + // dpad_val.set_flag(HatMask::CENTER); } if (p_dpad == 0) { - dpad_val = (HatMask)HatMask::UP; + dpad_val.set_flag(HatMask::UP); } else if (p_dpad == 4500) { - dpad_val = (HatMask)(HatMask::UP | HatMask::RIGHT); + dpad_val.set_flag(HatMask::UP); + dpad_val.set_flag(HatMask::RIGHT); } else if (p_dpad == 9000) { - dpad_val = (HatMask)HatMask::RIGHT; + dpad_val.set_flag(HatMask::RIGHT); } else if (p_dpad == 13500) { - dpad_val = (HatMask)(HatMask::RIGHT | HatMask::DOWN); + dpad_val.set_flag(HatMask::RIGHT); + dpad_val.set_flag(HatMask::DOWN); } else if (p_dpad == 18000) { - dpad_val = (HatMask)HatMask::DOWN; + dpad_val.set_flag(HatMask::DOWN); } else if (p_dpad == 22500) { - dpad_val = (HatMask)(HatMask::DOWN | HatMask::LEFT); + dpad_val.set_flag(HatMask::DOWN); + dpad_val.set_flag(HatMask::LEFT); } else if (p_dpad == 27000) { - dpad_val = (HatMask)HatMask::LEFT; + dpad_val.set_flag(HatMask::LEFT); } else if (p_dpad == 31500) { - dpad_val = (HatMask)(HatMask::LEFT | HatMask::UP); + dpad_val.set_flag(HatMask::LEFT); + dpad_val.set_flag(HatMask::UP); } input->joy_hat(p_device, dpad_val); } diff --git a/platform/windows/logo.png b/platform/windows/logo.png Binary files differdeleted file mode 100644 index f06b463850..0000000000 --- a/platform/windows/logo.png +++ /dev/null diff --git a/platform/windows/logo.svg b/platform/windows/logo.svg new file mode 100644 index 0000000000..77a0b20766 --- /dev/null +++ b/platform/windows/logo.svg @@ -0,0 +1 @@ +<svg height="32" width="32" xmlns="http://www.w3.org/2000/svg"><path d="m1 5.132 12.295-1.694v11.879H1zm0 21.736 12.295 1.695V16.83H1zm13.647 1.875L31 31V16.83H14.647zm0-25.486v12.06H31V1z" fill="#00abed"/></svg> diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 2a44a19085..130c5f7b97 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -718,15 +718,23 @@ Error OS_Windows::create_process(const String &p_path, const List<String> &p_arg } Error OS_Windows::kill(const ProcessID &p_pid) { - ERR_FAIL_COND_V(!process_map->has(p_pid), FAILED); + int ret = 0; + if (process_map->has(p_pid)) { + const PROCESS_INFORMATION pi = (*process_map)[p_pid].pi; + process_map->erase(p_pid); - const PROCESS_INFORMATION pi = (*process_map)[p_pid].pi; - process_map->erase(p_pid); + ret = TerminateProcess(pi.hProcess, 0); - const int ret = TerminateProcess(pi.hProcess, 0); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + } else { + HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, false, (DWORD)p_pid); + if (hProcess != NULL) { + ret = TerminateProcess(hProcess, 0); - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); + CloseHandle(hProcess); + } + } return ret != 0 ? OK : FAILED; } @@ -1158,17 +1166,24 @@ String OS_Windows::get_environment(const String &p_var) const { return ""; } -bool OS_Windows::set_environment(const String &p_var, const String &p_value) const { - return (bool)SetEnvironmentVariableW((LPCWSTR)(p_var.utf16().get_data()), (LPCWSTR)(p_value.utf16().get_data())); +void OS_Windows::set_environment(const String &p_var, const String &p_value) const { + ERR_FAIL_COND_MSG(p_var.is_empty() || p_var.contains("="), vformat("Invalid environment variable name '%s', cannot be empty or include '='.", p_var)); + Char16String var = p_var.utf16(); + Char16String value = p_value.utf16(); + ERR_FAIL_COND_MSG(var.length() + value.length() + 2 > 32767, vformat("Invalid definition for environment variable '%s', cannot exceed 32767 characters.", p_var)); + SetEnvironmentVariableW((LPCWSTR)(var.get_data()), (LPCWSTR)(value.get_data())); } -String OS_Windows::get_stdin_string(bool p_block) { - if (p_block) { - WCHAR buff[1024]; - DWORD count = 0; - if (ReadConsoleW(GetStdHandle(STD_INPUT_HANDLE), buff, 1024, &count, nullptr)) { - return String::utf16((const char16_t *)buff, count); - } +void OS_Windows::unset_environment(const String &p_var) const { + ERR_FAIL_COND_MSG(p_var.is_empty() || p_var.contains("="), vformat("Invalid environment variable name '%s', cannot be empty or include '='.", p_var)); + SetEnvironmentVariableW((LPCWSTR)(p_var.utf16().get_data()), nullptr); // Null to delete. +} + +String OS_Windows::get_stdin_string() { + WCHAR buff[1024]; + DWORD count = 0; + if (ReadConsoleW(GetStdHandle(STD_INPUT_HANDLE), buff, 1024, &count, nullptr)) { + return String::utf16((const char16_t *)buff, count); } return String(); diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index 9cb3977030..05110c2614 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -140,7 +140,7 @@ protected: virtual void finalize() override; virtual void finalize_core() override; - virtual String get_stdin_string(bool p_block) override; + virtual String get_stdin_string() override; String _quote_command_line_argument(const String &p_text) const; @@ -186,7 +186,8 @@ public: 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 void set_environment(const String &p_var, const String &p_value) const override; + virtual void unset_environment(const String &p_var) const override; virtual Vector<String> get_system_fonts() const override; virtual String get_system_font_path(const String &p_font_name, int p_weight = 400, int p_stretch = 100, bool p_italic = false) const override; diff --git a/platform/windows/run_icon.svg b/platform/windows/run_icon.svg new file mode 100644 index 0000000000..0897276ef7 --- /dev/null +++ b/platform/windows/run_icon.svg @@ -0,0 +1 @@ +<svg height="16" width="16" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path d="m1.095 2.997 5.66-.78v5.469h-5.66zm0 10.006 5.66.78v-5.4h-5.66zm6.282.863 7.528 1.04V8.381H7.377Zm0-11.732v5.552h7.528V1.095Z" fill="#00abed" style="stroke-width:.460341;fill:#e0e0e0;fill-opacity:1"/></svg> |