Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add error checks and harmonize behavior of the set_icon method. #78437

Merged
merged 1 commit into from
Jul 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions platform/linuxbsd/x11/display_server_x11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4880,6 +4880,8 @@ void DisplayServerX11::set_icon(const Ref<Image> &p_icon) {
Atom net_wm_icon = XInternAtom(x11_display, "_NET_WM_ICON", False);

if (p_icon.is_valid()) {
ERR_FAIL_COND(p_icon->get_width() <= 0 || p_icon->get_height() <= 0);

Ref<Image> img = p_icon->duplicate();
img->convert(Image::FORMAT_RGBA8);

Expand Down
66 changes: 36 additions & 30 deletions platform/macos/display_server_macos.mm
Original file line number Diff line number Diff line change
Expand Up @@ -3603,40 +3603,46 @@
void DisplayServerMacOS::set_icon(const Ref<Image> &p_icon) {
_THREAD_SAFE_METHOD_

Ref<Image> img = p_icon;
img = img->duplicate();
img->convert(Image::FORMAT_RGBA8);
NSBitmapImageRep *imgrep = [[NSBitmapImageRep alloc]
initWithBitmapDataPlanes:nullptr
pixelsWide:img->get_width()
pixelsHigh:img->get_height()
bitsPerSample:8
samplesPerPixel:4
hasAlpha:YES
isPlanar:NO
colorSpaceName:NSDeviceRGBColorSpace
bytesPerRow:img->get_width() * 4
bitsPerPixel:32];
ERR_FAIL_COND(imgrep == nil);
uint8_t *pixels = [imgrep bitmapData];
if (p_icon.is_valid()) {
ERR_FAIL_COND(p_icon->get_width() <= 0 || p_icon->get_height() <= 0);

int len = img->get_width() * img->get_height();
const uint8_t *r = img->get_data().ptr();
Ref<Image> img = p_icon->duplicate();
img->convert(Image::FORMAT_RGBA8);

/* Premultiply the alpha channel */
for (int i = 0; i < len; i++) {
uint8_t alpha = r[i * 4 + 3];
pixels[i * 4 + 0] = (uint8_t)(((uint16_t)r[i * 4 + 0] * alpha) / 255);
pixels[i * 4 + 1] = (uint8_t)(((uint16_t)r[i * 4 + 1] * alpha) / 255);
pixels[i * 4 + 2] = (uint8_t)(((uint16_t)r[i * 4 + 2] * alpha) / 255);
pixels[i * 4 + 3] = alpha;
}
NSBitmapImageRep *imgrep = [[NSBitmapImageRep alloc]
initWithBitmapDataPlanes:nullptr
pixelsWide:img->get_width()
pixelsHigh:img->get_height()
bitsPerSample:8
samplesPerPixel:4
hasAlpha:YES
isPlanar:NO
colorSpaceName:NSDeviceRGBColorSpace
bytesPerRow:img->get_width() * 4
bitsPerPixel:32];
ERR_FAIL_COND(imgrep == nil);
uint8_t *pixels = [imgrep bitmapData];

NSImage *nsimg = [[NSImage alloc] initWithSize:NSMakeSize(img->get_width(), img->get_height())];
ERR_FAIL_COND(nsimg == nil);
int len = img->get_width() * img->get_height();
const uint8_t *r = img->get_data().ptr();

[nsimg addRepresentation:imgrep];
[NSApp setApplicationIconImage:nsimg];
/* Premultiply the alpha channel */
for (int i = 0; i < len; i++) {
uint8_t alpha = r[i * 4 + 3];
pixels[i * 4 + 0] = (uint8_t)(((uint16_t)r[i * 4 + 0] * alpha) / 255);
pixels[i * 4 + 1] = (uint8_t)(((uint16_t)r[i * 4 + 1] * alpha) / 255);
pixels[i * 4 + 2] = (uint8_t)(((uint16_t)r[i * 4 + 2] * alpha) / 255);
pixels[i * 4 + 3] = alpha;
}

NSImage *nsimg = [[NSImage alloc] initWithSize:NSMakeSize(img->get_width(), img->get_height())];
ERR_FAIL_COND(nsimg == nil);

[nsimg addRepresentation:imgrep];
[NSApp setApplicationIconImage:nsimg];
} else {
[NSApp setApplicationIconImage:nil];
}
}

DisplayServer *DisplayServerMacOS::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) {
Expand Down
51 changes: 28 additions & 23 deletions platform/web/display_server_web.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -731,35 +731,40 @@ void DisplayServerWeb::send_window_event_callback(int p_notification) {
}

void DisplayServerWeb::set_icon(const Ref<Image> &p_icon) {
ERR_FAIL_COND(p_icon.is_null());
Ref<Image> icon = p_icon;
if (icon->is_compressed()) {
icon = icon->duplicate();
ERR_FAIL_COND(icon->decompress() != OK);
}
if (icon->get_format() != Image::FORMAT_RGBA8) {
if (icon == p_icon) {
if (p_icon.is_valid()) {
ERR_FAIL_COND(p_icon->get_width() <= 0 || p_icon->get_height() <= 0);

Ref<Image> icon = p_icon;
if (icon->is_compressed()) {
icon = icon->duplicate();
ERR_FAIL_COND(icon->decompress() != OK);
}
if (icon->get_format() != Image::FORMAT_RGBA8) {
if (icon == p_icon) {
icon = icon->duplicate();
}
icon->convert(Image::FORMAT_RGBA8);
}
icon->convert(Image::FORMAT_RGBA8);
}

png_image png_meta;
memset(&png_meta, 0, sizeof png_meta);
png_meta.version = PNG_IMAGE_VERSION;
png_meta.width = icon->get_width();
png_meta.height = icon->get_height();
png_meta.format = PNG_FORMAT_RGBA;
png_image png_meta;
memset(&png_meta, 0, sizeof png_meta);
png_meta.version = PNG_IMAGE_VERSION;
png_meta.width = icon->get_width();
png_meta.height = icon->get_height();
png_meta.format = PNG_FORMAT_RGBA;

PackedByteArray png;
size_t len;
PackedByteArray data = icon->get_data();
ERR_FAIL_COND(!png_image_write_get_memory_size(png_meta, len, 0, data.ptr(), 0, nullptr));
PackedByteArray png;
size_t len;
PackedByteArray data = icon->get_data();
ERR_FAIL_COND(!png_image_write_get_memory_size(png_meta, len, 0, data.ptr(), 0, nullptr));

png.resize(len);
ERR_FAIL_COND(!png_image_write_to_memory(&png_meta, png.ptrw(), &len, 0, data.ptr(), 0, nullptr));
png.resize(len);
ERR_FAIL_COND(!png_image_write_to_memory(&png_meta, png.ptrw(), &len, 0, data.ptr(), 0, nullptr));

godot_js_display_window_icon_set(png.ptr(), len);
godot_js_display_window_icon_set(png.ptr(), len);
} else {
godot_js_display_window_icon_set(nullptr, 0);
}
}

void DisplayServerWeb::_dispatch_input_event(const Ref<InputEvent> &p_event) {
Expand Down
25 changes: 16 additions & 9 deletions platform/web/js/libs/library_godot_display.js
Original file line number Diff line number Diff line change
Expand Up @@ -568,16 +568,23 @@ const GodotDisplay = {
godot_js_display_window_icon_set__sig: 'vii',
godot_js_display_window_icon_set: function (p_ptr, p_len) {
let link = document.getElementById('-gd-engine-icon');
if (link === null) {
link = document.createElement('link');
link.rel = 'icon';
link.id = '-gd-engine-icon';
document.head.appendChild(link);
}
const old_icon = GodotDisplay.window_icon;
const png = new Blob([GodotRuntime.heapSlice(HEAPU8, p_ptr, p_len)], { type: 'image/png' });
GodotDisplay.window_icon = URL.createObjectURL(png);
link.href = GodotDisplay.window_icon;
if (p_ptr) {
if (link === null) {
link = document.createElement('link');
link.rel = 'icon';
link.id = '-gd-engine-icon';
document.head.appendChild(link);
}
const png = new Blob([GodotRuntime.heapSlice(HEAPU8, p_ptr, p_len)], { type: 'image/png' });
GodotDisplay.window_icon = URL.createObjectURL(png);
link.href = GodotDisplay.window_icon;
} else {
if (link) {
link.remove();
}
GodotDisplay.window_icon = null;
}
if (old_icon) {
URL.revokeObjectURL(old_icon);
}
Expand Down
98 changes: 54 additions & 44 deletions platform/windows/display_server_windows.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2194,55 +2194,65 @@ void DisplayServerWindows::set_native_icon(const String &p_filename) {
void DisplayServerWindows::set_icon(const Ref<Image> &p_icon) {
_THREAD_SAFE_METHOD_

ERR_FAIL_COND(!p_icon.is_valid());
if (icon != p_icon) {
icon = p_icon->duplicate();
if (icon->get_format() != Image::FORMAT_RGBA8) {
icon->convert(Image::FORMAT_RGBA8);
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);
}
}
int w = icon->get_width();
int h = icon->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();

encode_uint32(40, &icon_bmp[0]);
encode_uint32(w, &icon_bmp[4]);
encode_uint32(h * 2, &icon_bmp[8]);
encode_uint16(1, &icon_bmp[12]);
encode_uint16(32, &icon_bmp[14]);
encode_uint32(BI_RGB, &icon_bmp[16]);
encode_uint32(w * h * 4, &icon_bmp[20]);
encode_uint32(0, &icon_bmp[24]);
encode_uint32(0, &icon_bmp[28]);
encode_uint32(0, &icon_bmp[32]);
encode_uint32(0, &icon_bmp[36]);

uint8_t *wr = &icon_bmp[40];
const uint8_t *r = icon->get_data().ptr();

for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
const uint8_t *rpx = &r[((h - i - 1) * w + j) * 4];
uint8_t *wpx = &wr[(i * w + j) * 4];
wpx[0] = rpx[2];
wpx[1] = rpx[1];
wpx[2] = rpx[0];
wpx[3] = rpx[3];

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();

encode_uint32(40, &icon_bmp[0]);
encode_uint32(w, &icon_bmp[4]);
encode_uint32(h * 2, &icon_bmp[8]);
encode_uint16(1, &icon_bmp[12]);
encode_uint16(32, &icon_bmp[14]);
encode_uint32(BI_RGB, &icon_bmp[16]);
encode_uint32(w * h * 4, &icon_bmp[20]);
encode_uint32(0, &icon_bmp[24]);
encode_uint32(0, &icon_bmp[28]);
encode_uint32(0, &icon_bmp[32]);
encode_uint32(0, &icon_bmp[36]);

uint8_t *wr = &icon_bmp[40];
const uint8_t *r = img->get_data().ptr();

for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
const uint8_t *rpx = &r[((h - i - 1) * w + j) * 4];
uint8_t *wpx = &wr[(i * w + j) * 4];
wpx[0] = rpx[2];
wpx[1] = rpx[1];
wpx[2] = rpx[0];
wpx[3] = rpx[3];
}
}
}

HICON hicon = CreateIconFromResource(icon_bmp, icon_len, TRUE, 0x00030000);
HICON hicon = CreateIconFromResource(icon_bmp, icon_len, TRUE, 0x00030000);
ERR_FAIL_COND(!hicon);

icon = img;

// Set the icon for the window.
SendMessage(windows[MAIN_WINDOW_ID].hWnd, WM_SETICON, ICON_SMALL, (LPARAM)hicon);
// 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);
// Set the icon in the task manager (should we do this?).
SendMessage(windows[MAIN_WINDOW_ID].hWnd, WM_SETICON, ICON_BIG, (LPARAM)hicon);
} else {
icon = Ref<Image>();
SendMessage(windows[MAIN_WINDOW_ID].hWnd, WM_SETICON, ICON_SMALL, NULL);
SendMessage(windows[MAIN_WINDOW_ID].hWnd, WM_SETICON, ICON_BIG, NULL);
}
}

void DisplayServerWindows::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) {
Expand Down