diff --git a/documentation/src/wayland.dox b/documentation/src/wayland.dox index d1ba01e00..a150ae555 100644 --- a/documentation/src/wayland.dox +++ b/documentation/src/wayland.dox @@ -583,7 +583,7 @@ more frequently than the system can process it. This 2-step mechanism works as follows: - Fl_Wayland_Graphics_Driver::buffer_commit() first calls function \c wl_surface_frame() to obtain a pointer to a struct wl_callback object and stores it as member -\c cb of the surface's \ref wld_buffer. +\c frame_cb of the surface's \ref wld_window. Then it calls \c wl_callback_add_listener() to associate this object to the FLTK-defined, callback function \c surface_frame_done(). It next calls \c wl_surface_commit(). @@ -591,7 +591,7 @@ Together, these 3 calls instruct Wayland to start mapping the buffer content to display and to call \c surface_frame_done() later, when it will have become ready for another mapping operation. - Later, \c surface_frame_done() runs and destroys the \c wl_callback object by -function \c wl_callback_destroy() and sets member \c cb to NULL. +function \c wl_callback_destroy() and sets member \c frame_cb to NULL. Member variable \c draw_buffer_needs_commit of the \ref wld_buffer is also important in this mechanism : it informs FLTK that the graphics buffer has @@ -603,14 +603,14 @@ This procedure ensures that FLTK never changes the surface's Wayland buffer while it's being used by the compositor and never calls \c wl_surface_commit() before Wayland gets ready for a new commit because \c Fl_Wayland_Window_Driver::flush() calls -\c Fl_Wayland_Graphics_Driver::buffer_commit() only if \c cb is NULL. +\c Fl_Wayland_Graphics_Driver::buffer_commit() only if \c frame_cb is NULL. If it's not NULL, the exact content of function \c surface_frame_done() : \code static void surface_frame_done(void *data, struct wl_callback *cb, uint32_t time) { struct wld_window *window = (struct wld_window *)data; wl_callback_destroy(cb); if (window->buffer) { - window->buffer->cb = NULL; + window->frame_cb = NULL; if (window->buffer->draw_buffer_needs_commit) { Fl_Wayland_Graphics_Driver::buffer_commit(window); } @@ -629,14 +629,14 @@ resize is being performed and sends window resize commands at high rate (~60 Hz) client via the socket. Libdecor turns on flag \c LIBDECOR_WINDOW_STATE_RESIZING to inform the client, and runs function \c handle_configure() for each received resize command. Before calling Fl_Group::resize() and later Fl_Window::draw(), -\c handle_configure() tests whether \c window->buffer->cb is NULL. When it's not +\c handle_configure() tests whether \c window->frame_cb is NULL. When it's not because a previous resize operation is being performed, the current resize command is skipped. At the end of the interactive resize, flag \c LIBDECOR_WINDOW_STATE_RESIZING is off and Wayland sends a final resize command which is not skipped. Overall, this ensures the client program resizes its window as frequently as it can without falling behind resize commands sent by the compositor. -To account for a bug in Mutter (issue #878), the \c window->buffer->cb object is +To account for a bug in Mutter (issue #878), the \c window->frame_cb object is not created when a toplevel window is being resized and is entirely covered by one subwindow. @@ -646,16 +646,16 @@ at any time and then calls the FLTK drawing API. This is made possible in function \c Fl_Wayland_Window_Driver::make_current() with \code // to support progressive drawing - if ( (!Fl_Wayland_Window_Driver::in_flush_) && window->buffer && (!window->buffer->cb) + if ( (!Fl_Wayland_Window_Driver::in_flush_) && window->buffer && (!window->frame_cb) && window->buffer->draw_buffer_needs_commit && (!wait_for_expose_value) ) { Fl_Wayland_Graphics_Driver::buffer_commit(window); } \endcode -Thus, \c buffer_commit() runs only when \c cb is NULL. If an app rapidly performs calls +Thus, \c buffer_commit() runs only when \c frame_cb is NULL. If an app rapidly performs calls to \c Fl_Window::make_current() and to drawing functions, FLTK will copy \c draw_buffer to -the Wayland buffer and instruct Wayland to map it to the display when \c cb is NULL +the Wayland buffer and instruct Wayland to map it to the display when \c frame_cb is NULL which means that the compositor is ready to start performing a mapping operation. -This occurs when the progressive drawing operation begins. Later, \c cb is generally found +This occurs when the progressive drawing operation begins. Later, \c frame_cb is generally found non NULL when \c Fl_Wayland_Window_Driver::make_current() runs because the compositor is busy processing the previous Wayland buffer. When the compositor has completed this processing, the client app runs \c surface_frame_done() @@ -1265,6 +1265,7 @@ struct wld_window { Fl_Window *fl_win; struct wl_list outputs; // linked list of displays where part or whole of window maps struct wl_surface *wl_surface; // the window's surface + struct wl_callback *frame_cb; // non-NULL until Wayland can process new surface commit struct Fl_Wayland_Graphics_Driver::wld_buffer *buffer; // see \ref wld_buffer struct xdg_surface *xdg_surface; enum Fl_Wayland_Window_Driver::kind kind; // DECORATED or POPUP or SUBWINDOW or UNFRAMED @@ -1323,7 +1324,6 @@ struct Fl_Wayland_Graphics_Driver::wld_buffer { struct wl_list link; // links all buffers from the same wl_shm_pool struct wl_buffer *wl_buffer; // the Wayland buffer void *data; // address of the beginning of the Wayland buffer's byte array - struct wl_callback *cb; // non-NULL until Wayland can process new buffer commit struct wl_shm_pool *shm_pool; // pter to wl_shm_pool from which this wl_buffer comes bool draw_buffer_needs_commit; // true when draw_buffer has been modified but not yet committed bool in_use; // true while being committed diff --git a/src/drivers/Wayland/Fl_Wayland_Gl_Window_Driver.cxx b/src/drivers/Wayland/Fl_Wayland_Gl_Window_Driver.cxx index aec93283b..473afd810 100644 --- a/src/drivers/Wayland/Fl_Wayland_Gl_Window_Driver.cxx +++ b/src/drivers/Wayland/Fl_Wayland_Gl_Window_Driver.cxx @@ -397,6 +397,18 @@ static void delayed_scissor(Fl_Wayland_Gl_Window_Driver *dr) { }*/ +static void surface_frame_done(void *data, struct wl_callback *cb, uint32_t time) { + struct wld_window *xid = (struct wld_window *)data; + wl_callback_destroy(cb); + xid->frame_cb = NULL; +} + + +static const struct wl_callback_listener surface_frame_listener = { + .done = surface_frame_done, +}; + + void Fl_Wayland_Gl_Window_Driver::resize(int is_a_resize, int W, int H) { if (!egl_window) return; float f = Fl::screen_scale(pWindow->screen_num()); @@ -406,6 +418,11 @@ void Fl_Wayland_Gl_Window_Driver::resize(int is_a_resize, int W, int H) { int W2, H2; wl_egl_window_get_attached_size(egl_window, &W2, &H2); if (W2 != W || H2 != H) { + struct wld_window *xid = fl_wl_xid(pWindow); + if (xid->kind == Fl_Wayland_Window_Driver::DECORATED && !xid->frame_cb) { + xid->frame_cb = wl_surface_frame(xid->wl_surface); + wl_callback_add_listener(xid->frame_cb, &surface_frame_listener, xid); + } wl_egl_window_resize(egl_window, W, H, 0, 0); } /* CONTROL_LEAKING_SUB_GL_WINDOWS diff --git a/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.H b/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.H index 73af80701..b8c7a2a8d 100644 --- a/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.H +++ b/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.H @@ -41,7 +41,6 @@ public: struct wl_list link; // links all buffers from the same wl_shm_pool struct wl_buffer *wl_buffer; void *data; - struct wl_callback *cb; struct wl_shm_pool *shm_pool; bool draw_buffer_needs_commit; bool in_use; // true while being committed diff --git a/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx b/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx index 3ec0ffd38..a5b7c2dfe 100644 --- a/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx +++ b/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx @@ -123,7 +123,7 @@ static void surface_frame_done(void *data, struct wl_callback *cb, uint32_t time struct wld_window *window = (struct wld_window *)data; wl_callback_destroy(cb); if (window->buffer) { // fix for issue #712 - window->buffer->cb = NULL; + window->frame_cb = NULL; if (window->buffer->draw_buffer_needs_commit) { Fl_Wayland_Graphics_Driver::buffer_commit(window); } @@ -177,8 +177,8 @@ void Fl_Wayland_Graphics_Driver::buffer_commit(struct wld_window *window, struct wl_surface_set_buffer_scale( window->wl_surface, Fl_Wayland_Window_Driver::driver(window->fl_win)->wld_scale() ); if (!window->covered) { // see issue #878 - window->buffer->cb = wl_surface_frame(window->wl_surface); - wl_callback_add_listener(window->buffer->cb, &surface_frame_listener, window); + window->frame_cb = wl_surface_frame(window->wl_surface); + wl_callback_add_listener(window->frame_cb, &surface_frame_listener, window); } wl_surface_commit(window->wl_surface); window->buffer->draw_buffer_needs_commit = false; @@ -237,7 +237,7 @@ void Fl_Wayland_Graphics_Driver::buffer_release(struct wld_window *window) { if (window->buffer && !window->buffer->released) { window->buffer->released = true; - if (window->buffer->cb) wl_callback_destroy(window->buffer->cb); + if (window->frame_cb) { wl_callback_destroy(window->frame_cb); window->frame_cb = NULL; } delete[] window->buffer->draw_buffer.buffer; window->buffer->draw_buffer.buffer = NULL; cairo_destroy(window->buffer->draw_buffer.cairo_); diff --git a/src/drivers/Wayland/Fl_Wayland_Window_Driver.H b/src/drivers/Wayland/Fl_Wayland_Window_Driver.H index 680ef70b7..8bc1a10f8 100644 --- a/src/drivers/Wayland/Fl_Wayland_Window_Driver.H +++ b/src/drivers/Wayland/Fl_Wayland_Window_Driver.H @@ -144,6 +144,7 @@ struct wld_window { Fl_Window *fl_win; struct wl_list outputs; // linked list of displays where part or whole of window maps struct wl_surface *wl_surface; + struct wl_callback *frame_cb; struct Fl_Wayland_Graphics_Driver::wld_buffer *buffer; struct xdg_surface *xdg_surface; enum Fl_Wayland_Window_Driver::kind kind; diff --git a/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx b/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx index e32943caa..138ef53d5 100644 --- a/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx +++ b/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx @@ -352,7 +352,7 @@ void Fl_Wayland_Window_Driver::make_current() { } // to support progressive drawing - if ( (!Fl_Wayland_Window_Driver::in_flush_) && window->buffer && (!window->buffer->cb) + if ( (!Fl_Wayland_Window_Driver::in_flush_) && window->buffer && (!window->frame_cb) && window->buffer->draw_buffer_needs_commit && (!wait_for_expose_value) ) { Fl_Wayland_Graphics_Driver::buffer_commit(window); } @@ -415,7 +415,7 @@ void Fl_Wayland_Window_Driver::flush() { Fl_Wayland_Window_Driver::in_flush_ = true; Fl_Window_Driver::flush(); Fl_Wayland_Window_Driver::in_flush_ = false; - if (!window->buffer->cb) Fl_Wayland_Graphics_Driver::buffer_commit(window, r); + if (!window->frame_cb) Fl_Wayland_Graphics_Driver::buffer_commit(window, r); } @@ -909,9 +909,9 @@ static void handle_configure(struct libdecor_frame *frame, #ifndef LIBDECOR_MR131 bool in_decorated_window_resizing = (window->state & LIBDECOR_WINDOW_STATE_RESIZING); #endif - bool condition = in_decorated_window_resizing && window->buffer; + bool condition = in_decorated_window_resizing; if (condition) { // see issue #878 - condition = (window->covered ? window->buffer->in_use : (window->buffer->cb != NULL)); + condition = (window->covered ? (window->buffer && window->buffer->in_use) : (window->frame_cb != NULL)); } if (condition) { // Skip resizing & redrawing. The last resize request won't be skipped because