Fix: Wayland crashes when dragging window from 100% to 200% scale factors (#1428)
Build and Test / build-linux (push) Has been cancelled
Build and Test / build-wayland (push) Has been cancelled
Build and Test / build-macos (push) Has been cancelled
Build and Test / build-windows (push) Has been cancelled

This commit is contained in:
ManoloFLTK
2026-05-10 12:45:24 +02:00
parent 300d3cf692
commit 1cafc6a0d2
4 changed files with 21 additions and 8 deletions
@@ -42,6 +42,7 @@ public:
struct wl_buffer *wl_buffer; struct wl_buffer *wl_buffer;
void *data; void *data;
struct wl_shm_pool *shm_pool; struct wl_shm_pool *shm_pool;
int allowed_wld_scale; // the wld_scale active when this buffer was sized
bool draw_buffer_needs_commit; bool draw_buffer_needs_commit;
bool in_use; // true while being committed bool in_use; // true while being committed
bool released; // true after buffer_release() was called bool released; // true after buffer_release() was called
@@ -57,7 +58,7 @@ public:
void copy_offscreen(int x, int y, int w, int h, Fl_Offscreen osrc, void copy_offscreen(int x, int y, int w, int h, Fl_Offscreen osrc,
int srcx, int srcy) FL_OVERRIDE; int srcx, int srcy) FL_OVERRIDE;
void cache_size(Fl_Image *img, int &width, int &height) FL_OVERRIDE; void cache_size(Fl_Image *img, int &width, int &height) FL_OVERRIDE;
static struct wld_buffer *create_wld_buffer(int width, int height, bool with_shm = true); static struct wld_buffer *create_wld_buffer(int width, int height, bool with_shm, int wld_s);
static void create_shm_buffer(wld_buffer *buffer); static void create_shm_buffer(wld_buffer *buffer);
static void buffer_release(struct wld_window *window); static void buffer_release(struct wld_window *window);
static void buffer_commit(struct wld_window *window, cairo_region_t *r = NULL); static void buffer_commit(struct wld_window *window, cairo_region_t *r = NULL);
@@ -66,7 +67,7 @@ public:
// used by class Fl_Wayland_Gl_Window_Driver // used by class Fl_Wayland_Gl_Window_Driver
static FL_EXPORT struct draw_buffer *offscreen_buffer(Fl_Offscreen); static FL_EXPORT struct draw_buffer *offscreen_buffer(Fl_Offscreen);
static const cairo_user_data_key_t key; static const cairo_user_data_key_t key;
static Fl_Image_Surface *custom_offscreen(int w, int h, struct wld_buffer **buffer); static Fl_Image_Surface *custom_offscreen(int w, int h, struct wld_buffer **buffer, int scale);
}; };
#endif // FL_WAYLAND_GRAPHICS_DRIVER_H #endif // FL_WAYLAND_GRAPHICS_DRIVER_H
@@ -108,12 +108,13 @@ void Fl_Wayland_Graphics_Driver::create_shm_buffer(Fl_Wayland_Graphics_Driver::w
struct Fl_Wayland_Graphics_Driver::wld_buffer * struct Fl_Wayland_Graphics_Driver::wld_buffer *
Fl_Wayland_Graphics_Driver::create_wld_buffer(int width, int height, bool with_shm) { Fl_Wayland_Graphics_Driver::create_wld_buffer(int width, int height, bool with_shm, int wld_s) {
struct wld_buffer *buffer = (struct wld_buffer*)calloc(1, sizeof(struct wld_buffer)); struct wld_buffer *buffer = (struct wld_buffer*)calloc(1, sizeof(struct wld_buffer));
int stride = cairo_format_stride_for_width(cairo_format, width); int stride = cairo_format_stride_for_width(cairo_format, width);
cairo_init(&buffer->draw_buffer, width, height, stride, cairo_format); cairo_init(&buffer->draw_buffer, width, height, stride, cairo_format);
buffer->draw_buffer_needs_commit = true; buffer->draw_buffer_needs_commit = true;
if (with_shm) create_shm_buffer(buffer); if (with_shm) create_shm_buffer(buffer);
buffer->allowed_wld_scale = wld_s;
return buffer; return buffer;
} }
@@ -173,6 +174,17 @@ static void copy_region(struct wld_window *window, cairo_region_t *r) {
void Fl_Wayland_Graphics_Driver::buffer_commit(struct wld_window *window, cairo_region_t *r) void Fl_Wayland_Graphics_Driver::buffer_commit(struct wld_window *window, cairo_region_t *r)
{ {
if (!window->buffer->wl_buffer) create_shm_buffer(window->buffer); if (!window->buffer->wl_buffer) create_shm_buffer(window->buffer);
if (window->buffer->allowed_wld_scale != Fl_Wayland_Window_Driver::driver(window->fl_win)->wld_scale()) {
// surface_enter has updated wld_scale() but the buffer was sized for the
// old scale. Committing now would violate the Wayland protocol (buffer
// dimensions must be multiples of buffer_scale). Let delayed_rescale
// rebuild the buffer at the correct size first. (#1428)
buffer_release(window);
window->fl_win->redraw();
return;
}
cairo_surface_t *surf = cairo_get_target(window->buffer->draw_buffer.cairo_); cairo_surface_t *surf = cairo_get_target(window->buffer->draw_buffer.cairo_);
cairo_surface_flush(surf); cairo_surface_flush(surf);
if (r) copy_region(window, r); if (r) copy_region(window, r);
@@ -295,8 +307,8 @@ Fl_Wayland_Graphics_Driver::offscreen_buffer(Fl_Offscreen offscreen) {
Fl_Image_Surface *Fl_Wayland_Graphics_Driver::custom_offscreen(int w, int h, Fl_Image_Surface *Fl_Wayland_Graphics_Driver::custom_offscreen(int w, int h,
struct Fl_Wayland_Graphics_Driver::wld_buffer **p_off) { struct Fl_Wayland_Graphics_Driver::wld_buffer **p_off, int scale) {
struct wld_buffer *off = create_wld_buffer(w, h); struct wld_buffer *off = create_wld_buffer(w, h, true, scale);
*p_off = off; *p_off = off;
cairo_set_user_data(off->draw_buffer.cairo_, &key, &off->draw_buffer, NULL); cairo_set_user_data(off->draw_buffer.cairo_, &key, &off->draw_buffer, NULL);
return new Fl_Image_Surface(w, h, 0, (Fl_Offscreen)off->draw_buffer.cairo_); return new Fl_Image_Surface(w, h, 0, (Fl_Offscreen)off->draw_buffer.cairo_);
@@ -370,7 +370,7 @@ void Fl_Wayland_Window_Driver::make_current() {
int wld_s = wld_scale(); int wld_s = wld_scale();
if (!window->buffer) { if (!window->buffer) {
window->buffer = Fl_Wayland_Graphics_Driver::create_wld_buffer( window->buffer = Fl_Wayland_Graphics_Driver::create_wld_buffer(
int(pWindow->w() * f) * wld_s, int(pWindow->h() * f) * wld_s, false); int(pWindow->w() * f) * wld_s, int(pWindow->h() * f) * wld_s, false, wld_s);
((Fl_Cairo_Graphics_Driver*)fl_graphics_driver)->needs_commit_tag( ((Fl_Cairo_Graphics_Driver*)fl_graphics_driver)->needs_commit_tag(
&window->buffer->draw_buffer_needs_commit); &window->buffer->draw_buffer_needs_commit);
} }
@@ -1872,7 +1872,7 @@ int Fl_Wayland_Window_Driver::set_cursor_4args(const Fl_RGB_Image *rgb, int hotx
//create a Wayland buffer and have it used as an image of the new cursor //create a Wayland buffer and have it used as an image of the new cursor
struct Fl_Wayland_Graphics_Driver::wld_buffer *offscreen; struct Fl_Wayland_Graphics_Driver::wld_buffer *offscreen;
Fl_Image_Surface *img_surf = Fl_Wayland_Graphics_Driver::custom_offscreen( Fl_Image_Surface *img_surf = Fl_Wayland_Graphics_Driver::custom_offscreen(
new_image->image.width, new_image->image.height, &offscreen); new_image->image.width, new_image->image.height, &offscreen, scale);
new_image->buffer = offscreen->wl_buffer; new_image->buffer = offscreen->wl_buffer;
wl_buffer_set_user_data(new_image->buffer, offscreen); wl_buffer_set_user_data(new_image->buffer, offscreen);
new_cursor->image_count = 1; new_cursor->image_count = 1;
@@ -215,7 +215,7 @@ static struct Fl_Wayland_Graphics_Driver::wld_buffer *offscreen_from_text(const
height = ceil(height/float(scale)) * scale; height = ceil(height/float(scale)) * scale;
struct Fl_Wayland_Graphics_Driver::wld_buffer *off; struct Fl_Wayland_Graphics_Driver::wld_buffer *off;
Fl_Image_Surface *surf = Fl_Wayland_Graphics_Driver::custom_offscreen( Fl_Image_Surface *surf = Fl_Wayland_Graphics_Driver::custom_offscreen(
width, height, &off); width, height, &off, scale);
Fl_Surface_Device::push_current(surf); Fl_Surface_Device::push_current(surf);
p = text; p = text;
fl_font(FL_HELVETICA, 10 * scale); fl_font(FL_HELVETICA, 10 * scale);