diff --git a/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.H b/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.H index ac8786a47..2b042187a 100644 --- a/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.H +++ b/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.H @@ -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 diff --git a/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx b/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx index 5c9539a8c..8f3ac956f 100644 --- a/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx +++ b/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx @@ -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_); diff --git a/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx b/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx index e79c3a86f..a769ae158 100644 --- a/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx +++ b/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx @@ -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; diff --git a/src/drivers/Wayland/fl_wayland_clipboard_dnd.cxx b/src/drivers/Wayland/fl_wayland_clipboard_dnd.cxx index 12c525c46..c72e0bb17 100644 --- a/src/drivers/Wayland/fl_wayland_clipboard_dnd.cxx +++ b/src/drivers/Wayland/fl_wayland_clipboard_dnd.cxx @@ -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);