diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index 6b04879047..6d69e658be 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -1989,7 +1989,7 @@ Size2i DisplayServerWindows::window_get_title_size(const String &p_title, Window size.y = MAX(size.y, rect.bottom - rect.top); } } - if (icon.is_valid()) { + if (icon_big) { size.x += 32; } else { size.x += 16; @@ -2451,8 +2451,16 @@ void DisplayServerWindows::_update_window_style(WindowID p_window, bool p_repain SetWindowLongPtr(wd.hWnd, GWL_STYLE, style); SetWindowLongPtr(wd.hWnd, GWL_EXSTYLE, style_ex); - if (icon.is_valid()) { - set_icon(icon); + if (icon_big && !icon_small) { + SendMessage(wd.hWnd, WM_SETICON, ICON_BIG, (LPARAM)icon_big); + SendMessage(wd.hWnd, WM_SETICON, ICON_SMALL, (LPARAM)icon_big); + } else { + if (icon_big) { + SendMessage(wd.hWnd, WM_SETICON, ICON_BIG, (LPARAM)icon_big); + } + if (icon_small) { + SendMessage(wd.hWnd, WM_SETICON, ICON_SMALL, (LPARAM)icon_small); + } } SetWindowPos(wd.hWnd, _is_always_on_top_recursive(p_window) ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | ((wd.no_focus || wd.is_popup) ? SWP_NOACTIVATE : 0)); @@ -3922,6 +3930,17 @@ void DisplayServerWindows::swap_buffers() { void DisplayServerWindows::set_native_icon(const String &p_filename) { _THREAD_SAFE_METHOD_ + if (icon_big) { + DestroyIcon(icon_big); + icon_buffer_big.clear(); + icon_big = nullptr; + } + if (icon_small) { + DestroyIcon(icon_small); + icon_buffer_small.clear(); + icon_small = nullptr; + } + Ref f = FileAccess::open(p_filename, FileAccess::READ); ERR_FAIL_COND_MSG(f.is_null(), "Cannot open file with icon '" + p_filename + "'."); @@ -3979,59 +3998,60 @@ void DisplayServerWindows::set_native_icon(const String &p_filename) { // Read the big icon. DWORD bytecount_big = icon_dir->idEntries[big_icon_index].dwBytesInRes; - Vector data_big; - data_big.resize(bytecount_big); + icon_buffer_big.resize(bytecount_big); pos = icon_dir->idEntries[big_icon_index].dwImageOffset; f->seek(pos); - f->get_buffer((uint8_t *)&data_big.write[0], bytecount_big); - HICON icon_big = CreateIconFromResource((PBYTE)&data_big.write[0], bytecount_big, TRUE, 0x00030000); + f->get_buffer((uint8_t *)&icon_buffer_big.write[0], bytecount_big); + icon_big = CreateIconFromResourceEx((PBYTE)&icon_buffer_big.write[0], bytecount_big, TRUE, 0x00030000, 0, 0, LR_DEFAULTSIZE); ERR_FAIL_NULL_MSG(icon_big, "Could not create " + itos(big_icon_width) + "x" + itos(big_icon_width) + " @" + itos(big_icon_cc) + " icon, error: " + format_error_message(GetLastError()) + "."); // Read the small icon. DWORD bytecount_small = icon_dir->idEntries[small_icon_index].dwBytesInRes; - Vector data_small; - data_small.resize(bytecount_small); + icon_buffer_small.resize(bytecount_small); pos = icon_dir->idEntries[small_icon_index].dwImageOffset; f->seek(pos); - f->get_buffer((uint8_t *)&data_small.write[0], bytecount_small); - HICON icon_small = CreateIconFromResource((PBYTE)&data_small.write[0], bytecount_small, TRUE, 0x00030000); + f->get_buffer((uint8_t *)&icon_buffer_small.write[0], bytecount_small); + icon_small = CreateIconFromResourceEx((PBYTE)&icon_buffer_small.write[0], bytecount_small, TRUE, 0x00030000, 0, 0, LR_DEFAULTSIZE); ERR_FAIL_NULL_MSG(icon_small, "Could not create 16x16 @" + itos(small_icon_cc) + " icon, error: " + format_error_message(GetLastError()) + "."); // Online tradition says to be sure last error is cleared and set the small icon first. int err = 0; SetLastError(err); - SendMessage(windows[MAIN_WINDOW_ID].hWnd, WM_SETICON, ICON_SMALL, (LPARAM)icon_small); - err = GetLastError(); - ERR_FAIL_COND_MSG(err, "Error setting ICON_SMALL: " + format_error_message(err) + "."); - - SendMessage(windows[MAIN_WINDOW_ID].hWnd, WM_SETICON, ICON_BIG, (LPARAM)icon_big); - err = GetLastError(); - ERR_FAIL_COND_MSG(err, "Error setting ICON_BIG: " + format_error_message(err) + "."); - + for (const KeyValue &E : windows) { + SendMessage(E.value.hWnd, WM_SETICON, ICON_SMALL, (LPARAM)icon_small); + SendMessage(E.value.hWnd, WM_SETICON, ICON_BIG, (LPARAM)icon_big); + } memdelete(icon_dir); } void DisplayServerWindows::set_icon(const Ref &p_icon) { _THREAD_SAFE_METHOD_ + if (icon_big) { + DestroyIcon(icon_big); + icon_buffer_big.clear(); + icon_big = nullptr; + } + if (icon_small) { + DestroyIcon(icon_small); + icon_buffer_small.clear(); + icon_small = nullptr; + } + if (p_icon.is_valid()) { ERR_FAIL_COND(p_icon->get_width() <= 0 || p_icon->get_height() <= 0); - Ref img = p_icon; - if (img != icon) { - img = img->duplicate(); - img->convert(Image::FORMAT_RGBA8); - } + Ref img = p_icon->duplicate(); + img->convert(Image::FORMAT_RGBA8); int w = img->get_width(); int h = img->get_height(); // Create temporary bitmap buffer. int icon_len = 40 + h * w * 4; - Vector v; - v.resize(icon_len); - BYTE *icon_bmp = v.ptrw(); + icon_buffer_big.resize(icon_len); + BYTE *icon_bmp = icon_buffer_big.ptrw(); encode_uint32(40, &icon_bmp[0]); encode_uint32(w, &icon_bmp[4]); @@ -4058,26 +4078,23 @@ void DisplayServerWindows::set_icon(const Ref &p_icon) { wpx[3] = rpx[3]; } } + icon_big = CreateIconFromResourceEx(icon_bmp, icon_len, TRUE, 0x00030000, 0, 0, LR_DEFAULTSIZE); + ERR_FAIL_NULL(icon_big); - HICON hicon = CreateIconFromResource(icon_bmp, icon_len, TRUE, 0x00030000); - ERR_FAIL_NULL(hicon); - - icon = img; - - // Set the icon for the window. - SendMessage(windows[MAIN_WINDOW_ID].hWnd, WM_SETICON, ICON_SMALL, (LPARAM)hicon); - - // Set the icon in the task manager (should we do this?). - SendMessage(windows[MAIN_WINDOW_ID].hWnd, WM_SETICON, ICON_BIG, (LPARAM)hicon); + for (const KeyValue &E : windows) { + SendMessage(E.value.hWnd, WM_SETICON, ICON_SMALL, (LPARAM)icon_big); + SendMessage(E.value.hWnd, WM_SETICON, ICON_BIG, (LPARAM)icon_big); + } } else { - icon = Ref(); - SendMessage(windows[MAIN_WINDOW_ID].hWnd, WM_SETICON, ICON_SMALL, 0); - SendMessage(windows[MAIN_WINDOW_ID].hWnd, WM_SETICON, ICON_BIG, 0); + for (const KeyValue &E : windows) { + SendMessage(E.value.hWnd, WM_SETICON, ICON_SMALL, 0); + SendMessage(E.value.hWnd, WM_SETICON, ICON_BIG, 0); + } } } DisplayServer::IndicatorID DisplayServerWindows::create_status_indicator(const Ref &p_icon, const String &p_tooltip, const Callable &p_callback) { - HICON hicon = nullptr; + IndicatorData idat; if (p_icon.is_valid() && p_icon->get_width() > 0 && p_icon->get_height() > 0 && p_icon->get_image().is_valid()) { Ref img = p_icon->get_image(); img = img->duplicate(); @@ -4091,9 +4108,8 @@ DisplayServer::IndicatorID DisplayServerWindows::create_status_indicator(const R // Create temporary bitmap buffer. int icon_len = 40 + h * w * 4; - Vector v; - v.resize(icon_len); - BYTE *icon_bmp = v.ptrw(); + idat.icon_buffer.resize(icon_len); + BYTE *icon_bmp = idat.icon_buffer.ptrw(); encode_uint32(40, &icon_bmp[0]); encode_uint32(w, &icon_bmp[4]); @@ -4121,10 +4137,9 @@ DisplayServer::IndicatorID DisplayServerWindows::create_status_indicator(const R } } - hicon = CreateIconFromResource(icon_bmp, icon_len, TRUE, 0x00030000); + idat.icon = CreateIconFromResourceEx(icon_bmp, icon_len, TRUE, 0x00030000, 0, 0, LR_DEFAULTSIZE); } - IndicatorData idat; idat.callback = p_callback; NOTIFYICONDATAW ndat; @@ -4134,7 +4149,7 @@ DisplayServer::IndicatorID DisplayServerWindows::create_status_indicator(const R ndat.uID = indicator_id_counter; ndat.uFlags = NIF_ICON | NIF_TIP | NIF_MESSAGE; ndat.uCallbackMessage = WM_INDICATOR_CALLBACK_MESSAGE; - ndat.hIcon = hicon; + ndat.hIcon = idat.icon; memcpy(ndat.szTip, p_tooltip.utf16().get_data(), MIN(p_tooltip.utf16().length(), 127) * sizeof(WCHAR)); ndat.uVersion = NOTIFYICON_VERSION; @@ -4150,7 +4165,14 @@ DisplayServer::IndicatorID DisplayServerWindows::create_status_indicator(const R void DisplayServerWindows::status_indicator_set_icon(IndicatorID p_id, const Ref &p_icon) { ERR_FAIL_COND(!indicators.has(p_id)); - HICON hicon = nullptr; + IndicatorData &idat = indicators[p_id]; + + if (idat.icon) { + DestroyIcon(idat.icon); + idat.icon_buffer.clear(); + idat.icon = nullptr; + } + if (p_icon.is_valid() && p_icon->get_width() > 0 && p_icon->get_height() > 0 && p_icon->get_image().is_valid()) { Ref img = p_icon->get_image(); img = img->duplicate(); @@ -4164,9 +4186,8 @@ void DisplayServerWindows::status_indicator_set_icon(IndicatorID p_id, const Ref // Create temporary bitmap buffer. int icon_len = 40 + h * w * 4; - Vector v; - v.resize(icon_len); - BYTE *icon_bmp = v.ptrw(); + idat.icon_buffer.resize(icon_len); + BYTE *icon_bmp = idat.icon_buffer.ptrw(); encode_uint32(40, &icon_bmp[0]); encode_uint32(w, &icon_bmp[4]); @@ -4194,7 +4215,7 @@ void DisplayServerWindows::status_indicator_set_icon(IndicatorID p_id, const Ref } } - hicon = CreateIconFromResource(icon_bmp, icon_len, TRUE, 0x00030000); + idat.icon = CreateIconFromResourceEx(icon_bmp, icon_len, TRUE, 0x00030000, 0, 0, LR_DEFAULTSIZE); } NOTIFYICONDATAW ndat; @@ -4203,7 +4224,7 @@ void DisplayServerWindows::status_indicator_set_icon(IndicatorID p_id, const Ref ndat.hWnd = windows[MAIN_WINDOW_ID].hWnd; ndat.uID = p_id; ndat.uFlags = NIF_ICON; - ndat.hIcon = hicon; + ndat.hIcon = idat.icon; ndat.uVersion = NOTIFYICON_VERSION; Shell_NotifyIconW(NIM_MODIFY, &ndat); @@ -4263,6 +4284,13 @@ Rect2 DisplayServerWindows::status_indicator_get_rect(IndicatorID p_id) const { void DisplayServerWindows::delete_status_indicator(IndicatorID p_id) { ERR_FAIL_COND(!indicators.has(p_id)); + IndicatorData &idat = indicators[p_id]; + if (idat.icon) { + DestroyIcon(idat.icon); + idat.icon_buffer.clear(); + idat.icon = nullptr; + } + NOTIFYICONDATAW ndat; ZeroMemory(&ndat, sizeof(NOTIFYICONDATAW)); ndat.cbSize = sizeof(NOTIFYICONDATAW); @@ -7653,6 +7681,12 @@ DisplayServerWindows::~DisplayServerWindows() { ndat.uID = E->key; ndat.uVersion = NOTIFYICON_VERSION; + if (E->value.icon) { + DestroyIcon(E->value.icon); + E->value.icon_buffer.clear(); + E->value.icon = nullptr; + } + Shell_NotifyIconW(NIM_DELETE, &ndat); } @@ -7702,6 +7736,17 @@ DisplayServerWindows::~DisplayServerWindows() { } #endif + if (icon_big) { + DestroyIcon(icon_big); + icon_buffer_big.clear(); + icon_big = nullptr; + } + if (icon_small) { + DestroyIcon(icon_small); + icon_buffer_small.clear(); + icon_small = nullptr; + } + if (restore_mouse_trails > 1) { SystemParametersInfoA(SPI_SETMOUSETRAILS, restore_mouse_trails, nullptr, 0); } diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h index ea7fc02dfa..11885e6bd0 100644 --- a/platform/windows/display_server_windows.h +++ b/platform/windows/display_server_windows.h @@ -274,6 +274,11 @@ class DisplayServerWindows : public DisplayServer { RBMap touch_state; + Vector icon_buffer_big; + HICON icon_big = nullptr; + Vector icon_buffer_small; + HICON icon_small = nullptr; + int pressrc; HINSTANCE hInstance; // Holds The Instance Of The Application String rendering_driver; @@ -387,7 +392,6 @@ class DisplayServerWindows : public DisplayServer { HHOOK mouse_monitor = nullptr; List popup_list; uint64_t time_since_popup = 0; - Ref icon; Error _create_window(WindowID p_window_id, WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect, bool p_exclusive, WindowID p_transient_parent, HWND p_parent_hwnd, bool p_no_redirection_bitmap); void _destroy_window(WindowID p_window_id); // Destroys only what was needed to be created for the main window. Does not destroy transient parent dependencies or GL/rendering context windows. @@ -413,6 +417,8 @@ class DisplayServerWindows : public DisplayServer { struct IndicatorData { RID menu_rid; Callable callback; + Vector icon_buffer; + HICON icon = nullptr; }; IndicatorID indicator_id_counter = 0;