mirror of
https://github.com/godotengine/godot.git
synced 2026-02-08 03:38:29 +00:00
Merge pull request #114525 from bruvzg/icon_free
[Windows] Fix icon leak.
This commit is contained in:
@@ -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<FileAccess> 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<uint8_t> 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<uint8_t> 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<WindowID, WindowData> &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<Image> &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<Image> img = p_icon;
|
||||
if (img != icon) {
|
||||
img = img->duplicate();
|
||||
img->convert(Image::FORMAT_RGBA8);
|
||||
}
|
||||
Ref<Image> 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<BYTE> 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<Image> &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<WindowID, WindowData> &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<Image>();
|
||||
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<WindowID, WindowData> &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<Texture2D> &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<Image> 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<BYTE> 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<Texture2D> &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<Image> 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<BYTE> 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);
|
||||
}
|
||||
|
||||
@@ -274,6 +274,11 @@ class DisplayServerWindows : public DisplayServer {
|
||||
|
||||
RBMap<int, Vector2> touch_state;
|
||||
|
||||
Vector<BYTE> icon_buffer_big;
|
||||
HICON icon_big = nullptr;
|
||||
Vector<BYTE> 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<WindowID> popup_list;
|
||||
uint64_t time_since_popup = 0;
|
||||
Ref<Image> 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<BYTE> icon_buffer;
|
||||
HICON icon = nullptr;
|
||||
};
|
||||
|
||||
IndicatorID indicator_id_counter = 0;
|
||||
|
||||
Reference in New Issue
Block a user