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;
void *data;
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 in_use; // true while being committed
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,
int srcx, int srcy) 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 buffer_release(struct wld_window *window);
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
static FL_EXPORT struct draw_buffer *offscreen_buffer(Fl_Offscreen);
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
@@ -108,12 +108,13 @@ void Fl_Wayland_Graphics_Driver::create_shm_buffer(Fl_Wayland_Graphics_Driver::w
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));
int stride = cairo_format_stride_for_width(cairo_format, width);
cairo_init(&buffer->draw_buffer, width, height, stride, cairo_format);
buffer->draw_buffer_needs_commit = true;
if (with_shm) create_shm_buffer(buffer);
buffer->allowed_wld_scale = wld_s;
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)
{
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_flush(surf);
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,
struct Fl_Wayland_Graphics_Driver::wld_buffer **p_off) {
struct wld_buffer *off = create_wld_buffer(w, h);
struct Fl_Wayland_Graphics_Driver::wld_buffer **p_off, int scale) {
struct wld_buffer *off = create_wld_buffer(w, h, true, scale);
*p_off = off;
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_);
@@ -370,7 +370,7 @@ void Fl_Wayland_Window_Driver::make_current() {
int wld_s = wld_scale();
if (!window->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(
&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
struct Fl_Wayland_Graphics_Driver::wld_buffer *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;
wl_buffer_set_user_data(new_image->buffer, offscreen);
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;
struct Fl_Wayland_Graphics_Driver::wld_buffer *off;
Fl_Image_Surface *surf = Fl_Wayland_Graphics_Driver::custom_offscreen(
width, height, &off);
width, height, &off, scale);
Fl_Surface_Device::push_current(surf);
p = text;
fl_font(FL_HELVETICA, 10 * scale);