Add error checks and harmonize behavior of the set_icon method.
This commit is contained in:
parent
46424488ed
commit
9c5a0c6c10
5 changed files with 138 additions and 108 deletions
|
@ -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);
|
||||
|
||||
|
|
|
@ -3603,40 +3603,46 @@ void DisplayServerMacOS::set_native_icon(const String &p_filename) {
|
|||
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];
|
||||
|
||||
int len = img->get_width() * img->get_height();
|
||||
const uint8_t *r = img->get_data().ptr();
|
||||
|
||||
/* 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];
|
||||
}
|
||||
|
||||
NSImage *nsimg = [[NSImage alloc] initWithSize:NSMakeSize(img->get_width(), img->get_height())];
|
||||
ERR_FAIL_COND(nsimg == nil);
|
||||
|
||||
[nsimg addRepresentation:imgrep];
|
||||
[NSApp setApplicationIconImage:nsimg];
|
||||
}
|
||||
|
||||
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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
icon->convert(Image::FORMAT_RGBA8);
|
||||
if (icon->get_format() != Image::FORMAT_RGBA8) {
|
||||
if (icon == p_icon) {
|
||||
icon = icon->duplicate();
|
||||
}
|
||||
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;
|
||||
|
||||
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));
|
||||
|
||||
godot_js_display_window_icon_set(png.ptr(), len);
|
||||
} else {
|
||||
godot_js_display_window_icon_set(nullptr, 0);
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void DisplayServerWeb::_dispatch_input_event(const Ref<InputEvent> &p_event) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
int w = img->get_width();
|
||||
int h = img->get_height();
|
||||
|
||||
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]);
|
||||
// Create temporary bitmap buffer.
|
||||
int icon_len = 40 + h * w * 4;
|
||||
Vector<BYTE> v;
|
||||
v.resize(icon_len);
|
||||
BYTE *icon_bmp = v.ptrw();
|
||||
|
||||
uint8_t *wr = &icon_bmp[40];
|
||||
const uint8_t *r = icon->get_data().ptr();
|
||||
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]);
|
||||
|
||||
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];
|
||||
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);
|
||||
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 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);
|
||||
}
|
||||
|
||||
HICON hicon = CreateIconFromResource(icon_bmp, icon_len, TRUE, 0x00030000);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
void DisplayServerWindows::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) {
|
||||
|
|
Loading…
Reference in a new issue