summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com>2026-01-22 14:27:13 +0100
committerManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com>2026-01-22 14:27:13 +0100
commit05a3f82a5c385e7f00aa2bb8c1971e1cc99225a3 (patch)
tree6d9a37921c572d108b9ff75f5728e9a1654b1306
parent14a5f705c8e3385a637be3377f0800b30c38e589 (diff)
Fix "Setting window custom cursor from SVG image crashes" (#1363)
-rw-r--r--FL/Fl_Image.H5
-rw-r--r--FL/Fl_SVG_Image.H1
-rw-r--r--src/Fl_cocoa.mm6
-rw-r--r--src/Fl_win32.cxx1
-rw-r--r--src/Fl_x.cxx6
-rw-r--r--src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx22
6 files changed, 31 insertions, 10 deletions
diff --git a/FL/Fl_Image.H b/FL/Fl_Image.H
index d8fac1883..b342bad83 100644
--- a/FL/Fl_Image.H
+++ b/FL/Fl_Image.H
@@ -392,9 +392,12 @@ public:
\sa void Fl_RGB_Image::max_size(size_t)
*/
static size_t max_size() {return max_size_;}
- /** Returns whether an image is an Fl_SVG_Image or not.
+ /** Returns whether an RGB image is an Fl_SVG_Image or not.
This virtual method returns a pointer to the Fl_SVG_Image if this object is an instance of Fl_SVG_Image or NULL if not. */
virtual Fl_SVG_Image *as_svg_image() { return NULL; }
+ /** Returns whether an RGB image is an Fl_SVG_Image or not.
+ This virtual method returns a pointer to the Fl_SVG_Image if this object is an instance of const Fl_SVG_Image or NULL if not. */
+ virtual const Fl_SVG_Image *as_svg_image() const { return NULL; }
/** Makes sure the object is fully initialized.
In particular, makes sure member variable \ref array is non-null. */
virtual void normalize() {}
diff --git a/FL/Fl_SVG_Image.H b/FL/Fl_SVG_Image.H
index f1dd7095e..d49d1db59 100644
--- a/FL/Fl_SVG_Image.H
+++ b/FL/Fl_SVG_Image.H
@@ -170,6 +170,7 @@ public:
void draw(int X, int Y, int W, int H, int cx = 0, int cy = 0) override;
void draw(int X, int Y) { draw(X, Y, w(), h(), 0, 0); }
Fl_SVG_Image *as_svg_image() override { return this; }
+ const Fl_SVG_Image *as_svg_image() const override { return this; }
void normalize() override;
};
diff --git a/src/Fl_cocoa.mm b/src/Fl_cocoa.mm
index 66d5227fd..7f12390d2 100644
--- a/src/Fl_cocoa.mm
+++ b/src/Fl_cocoa.mm
@@ -4161,6 +4161,11 @@ int Fl_Cocoa_Window_Driver::set_cursor(const Fl_RGB_Image *image, int hotx, int
if ((hoty < 0) || (hoty >= image->h()))
return 0;
+ if (image->as_svg_image()) {
+ Fl_RGB_Image *image2 = (Fl_RGB_Image*)image->copy();
+ image2->normalize();
+ image = image2;
+ }
// OS X >= 10.6 can create a NSImage from a CGImage, but we need to
// support older versions, hence this pesky handling.
@@ -4220,6 +4225,7 @@ int Fl_Cocoa_Window_Driver::set_cursor(const Fl_RGB_Image *image, int hotx, int
[bitmap release];
[nsimage release];
+ if (image->as_svg_image()) delete image;
return 1;
}
diff --git a/src/Fl_win32.cxx b/src/Fl_win32.cxx
index f0a489f22..b5aca1c78 100644
--- a/src/Fl_win32.cxx
+++ b/src/Fl_win32.cxx
@@ -2770,6 +2770,7 @@ int Fl_WinAPI_Window_Driver::set_cursor(Fl_Cursor c) {
int Fl_WinAPI_Window_Driver::set_cursor(const Fl_RGB_Image *image, int hotx, int hoty) {
HCURSOR new_cursor;
Fl_RGB_Image *scaled_image = (Fl_RGB_Image*)image->copy();
+ scaled_image->normalize();
new_cursor = image_to_icon(scaled_image, false, hotx, hoty);
delete scaled_image;
if (new_cursor == NULL)
diff --git a/src/Fl_x.cxx b/src/Fl_x.cxx
index c690e750b..2afa2e9ae 100644
--- a/src/Fl_x.cxx
+++ b/src/Fl_x.cxx
@@ -3142,11 +3142,13 @@ int Fl_X11_Window_Driver::set_cursor(const Fl_RGB_Image *image, int hotx, int ho
if ((hoty < 0) || (hoty >= image->h()))
return 0;
- cursor = XcursorImageCreate(image->w(), image->h());
+ float s = image->as_svg_image() ? Fl::screen_scale(pWindow->screen_num()) : 1;
+ cursor = XcursorImageCreate(image->w() * s, image->h() * s);
if (!cursor)
return 0;
- image = (Fl_RGB_Image*)image->copy();
+ image = (Fl_RGB_Image*)image->copy(image->w() * s, image->h() * s);
+ ((Fl_RGB_Image*)image)->normalize();
const int extra_data = image->ld() ? (image->ld()-image->w()*image->d()) : 0;
const uchar *i = (const uchar*)*image->data();
XcursorPixel *o = cursor->pixels;
diff --git a/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx b/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx
index 1c42da2a1..0495fb7bc 100644
--- a/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx
+++ b/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx
@@ -1824,13 +1824,21 @@ int Fl_Wayland_Window_Driver::set_cursor(const Fl_RGB_Image *rgb, int hotx, int
int Fl_Wayland_Window_Driver::set_cursor_4args(const Fl_RGB_Image *rgb, int hotx, int hoty,
bool keep_copy) {
if (keep_copy) {
- int ld = rgb->ld() ? rgb->ld() : rgb->data_w() * rgb->d();
- uchar *data = new uchar[ld * rgb->data_h()];
- memcpy(data, rgb->array, ld * rgb->data_h());
- Fl_RGB_Image *rgb2 = new Fl_RGB_Image(data, rgb->data_w(), rgb->data_h(), rgb->d(), rgb->ld());
- rgb2->alloc_array = 1;
- rgb2->scale(rgb->w(), rgb->h(), 0, 1);
- rgb = rgb2;
+ if (rgb->as_svg_image()) {
+ int scale = wld_scale();
+ Fl_RGB_Image *svg = (Fl_RGB_Image*)rgb->copy(rgb->w() * scale, rgb->h() * scale);
+ svg->normalize();
+ svg->scale(rgb->w(), rgb->h(), 0, 1);
+ rgb = svg;
+ } else {
+ int ld = rgb->ld() ? rgb->ld() : rgb->data_w() * rgb->d();
+ uchar *data = new uchar[ld * rgb->data_h()];
+ memcpy(data, rgb->array, ld * rgb->data_h());
+ Fl_RGB_Image *rgb2 = new Fl_RGB_Image(data, rgb->data_w(), rgb->data_h(), rgb->d(), rgb->ld());
+ rgb2->alloc_array = 1;
+ rgb2->scale(rgb->w(), rgb->h(), 0, 1);
+ rgb = rgb2;
+ }
}
// build a new wl_cursor and its image
struct wld_window *xid = (struct wld_window *)Fl_Window_Driver::xid(pWindow);