summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHein-Pieter van Braam <hp@tmm.cx>2018-08-26 23:07:15 +0200
committerHein-Pieter van Braam <hp@tmm.cx>2018-08-27 01:28:11 +0200
commit3d4b7c6c5f1ace54d28ae23a2d5fa4c44780ac2f (patch)
tree81ded50124f5ddab38d869d1351f5d291a9542e9
parentdb55d8a4b6ad6c14f2131e02b50689eb8380276f (diff)
When setting an X11 icon fails, try halving the size
When setting an icon that is too large previously Godot would die with a X Error of failed request: BadLength error. To avoid this we install an error handler right before we set an icon. If the error handler triggers we halve the icon size until it works or until we've reached a 0 size on either width or height. We print a warning when this happens to alert developers. This fixes #19716
-rw-r--r--platform/x11/os_x11.cpp75
1 files changed, 58 insertions, 17 deletions
diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp
index ca9fd68412..e4a72e0715 100644
--- a/platform/x11/os_x11.cpp
+++ b/platform/x11/os_x11.cpp
@@ -2628,41 +2628,82 @@ void OS_X11::alert(const String &p_alert, const String &p_title) {
return;
}
+bool g_set_icon_error = false;
+int set_icon_errorhandler(Display *dpy, XErrorEvent *ev) {
+ g_set_icon_error = true;
+ return 0;
+}
+
void OS_X11::set_icon(const Ref<Image> &p_icon) {
+ int (*oldHandler)(Display *, XErrorEvent *) = XSetErrorHandler(&set_icon_errorhandler);
+
Atom net_wm_icon = XInternAtom(x11_display, "_NET_WM_ICON", False);
if (p_icon.is_valid()) {
Ref<Image> img = p_icon->duplicate();
img->convert(Image::FORMAT_RGBA8);
- int w = img->get_width();
- int h = img->get_height();
+ while (true) {
+ int w = img->get_width();
+ int h = img->get_height();
- // We're using long to have wordsize (32Bit build -> 32 Bits, 64 Bit build -> 64 Bits
- Vector<long> pd;
+ if (g_set_icon_error) {
+ g_set_icon_error = false;
- pd.resize(2 + w * h);
+ WARN_PRINT("Icon too large, attempting to resize icon.");
- pd.write[0] = w;
- pd.write[1] = h;
+ int new_width, new_height;
+ if (w > h) {
+ new_width = w / 2;
+ new_height = h * new_width / w;
+ } else {
+ new_height = h / 2;
+ new_width = w * new_height / h;
+ }
- PoolVector<uint8_t>::Read r = img->get_data().read();
+ w = new_width;
+ h = new_height;
- long *wr = &pd.write[2];
- uint8_t const *pr = r.ptr();
+ if (!w || !h) {
+ WARN_PRINT("Unable to set icon.");
+ break;
+ }
+
+ img->resize(w, h, Image::INTERPOLATE_CUBIC);
+ }
- for (int i = 0; i < w * h; i++) {
- long v = 0;
- // A R G B
- v |= pr[3] << 24 | pr[0] << 16 | pr[1] << 8 | pr[2];
- *wr++ = v;
- pr += 4;
+ // We're using long to have wordsize (32Bit build -> 32 Bits, 64 Bit build -> 64 Bits
+ Vector<long> pd;
+
+ pd.resize(2 + w * h);
+
+ pd.write[0] = w;
+ pd.write[1] = h;
+
+ PoolVector<uint8_t>::Read r = img->get_data().read();
+
+ long *wr = &pd.write[2];
+ uint8_t const *pr = r.ptr();
+
+ for (int i = 0; i < w * h; i++) {
+ long v = 0;
+ // A R G B
+ v |= pr[3] << 24 | pr[0] << 16 | pr[1] << 8 | pr[2];
+ *wr++ = v;
+ pr += 4;
+ }
+
+ XChangeProperty(x11_display, x11_window, net_wm_icon, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)pd.ptr(), pd.size());
+
+ if (!g_set_icon_error)
+ break;
}
- XChangeProperty(x11_display, x11_window, net_wm_icon, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)pd.ptr(), pd.size());
} else {
XDeleteProperty(x11_display, x11_window, net_wm_icon);
}
+
XFlush(x11_display);
+ XSetErrorHandler(oldHandler);
}
void OS_X11::force_process_input() {