diff options
| author | ManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com> | 2023-06-05 11:00:33 +0200 |
|---|---|---|
| committer | ManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com> | 2023-06-05 11:00:33 +0200 |
| commit | 5be3fbf913210a8b81fe101c3927c141432fa724 (patch) | |
| tree | b79a0e6844573483dda34751ea47b60e130db308 | |
| parent | 5dfa51a8201ce0111220575956d2fb0db989fe90 (diff) | |
Improve re-use of client/compositor shared memory by Wayland buffers
| -rw-r--r-- | documentation/src/wayland.dox | 131 | ||||
| -rw-r--r-- | src/drivers/Wayland/Fl_Wayland_Graphics_Driver.H | 41 | ||||
| -rw-r--r-- | src/drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx | 68 | ||||
| -rw-r--r-- | src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx | 46 |
4 files changed, 128 insertions, 158 deletions
diff --git a/documentation/src/wayland.dox b/documentation/src/wayland.dox index 5eba86156..c3f33fc79 100644 --- a/documentation/src/wayland.dox +++ b/documentation/src/wayland.dox @@ -486,6 +486,12 @@ Each of these two objects encapsulates a byte array of the same size and the sam destined to contain the Fl_Window's graphics. The Cairo surface object is where FLTK draws. The Wayland buffer is what Wayland maps on the display. FLTK copies the Cairo surface's byte array to the Wayland buffer's byte array before beginning the mapping operation. +If \c width and \c height are a window's dimensions in pixels, +\code + int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); + int size = stride * height; +\endcode +give \c size, the common size of both byte arrays. Section \ref wayland-buffer-factory below details how FLTK creates \c wl_buffer objects. @@ -552,75 +558,72 @@ Wayland names <em>buffer factory</em> a software procedure that constructs objec <tt>struct wl_buffer</tt> for use by a client application. FLTK creates a \c wl_buffer object each time an Fl_Window is mapped on a display or resized. That's done by member function \c Fl_Wayland_Graphics_Driver::create_shm_buffer() -which follows this 3-step procedure to create a "buffer factory" for FLTK and construct +which follows this 3-step procedure to create a "buffer factory" for FLTK and to construct Wayland buffers from it: -- Libdecor function <tt>os_create_anonymous_file(off_t size)</tt> creates an adequate file and mmap's -it. This file lives in RAM because it is created by function \c memfd_create(). -FLTK initially sets this file size to \c pool_size = 10 MB. This size will be increased when and -if necessary. -FLTK stores in variable \c pool_memory the address of the beginning of the mmap'ed memory structure. +- Libdecor function <tt>os_create_anonymous_file(off_t size)</tt> creates an adequate file +and mmap's it. This file lives in RAM because it is created by function \c memfd_create(). +FLTK sets this file size to 10 MB unless the size of the buffer to be created +is larger; in that case the anonymous file is sized to twice the buffer size. - Wayland function \c wl_shm_create_pool() shares this mmap'ed memory with the -Wayland compositor and returns an object of type <tt>struct wl_shm_pool</tt> which encapsulates -this memory. FLTK initializes -to 0 a variable called \c chunk_offset that represents the offset inside the mmap'ed memory available -for further \c wl_buffer objects. -- Wayland function \c wl_shm_pool_create_buffer() creates from the \c wl_shm_pool object a -\c wl_buffer object which encapsulates a section of a given size of the shared memory structure -beginning at offset \c chunk_offset in it. This function returns a pointer to the resulting -\c wl_buffer object. Quantity <tt>pool_memory + chunk_offset</tt> is therefore the address of the +Wayland compositor and returns an object of type <tt>struct wl_shm_pool</tt> which +encapsulates this memory. A record of type +<tt>struct Fl_Wayland_Graphics_Driver::wld_shm_pool_data</tt> is created and associated to +the newly created \c wl_shm_pool by \c wl_shm_pool_set_user_data(). This record stores +the starting address (\c pool_memory) and size (\c pool_size) of the pool's encapsulated +memory. The record also contains member \c buffers of type <tt>struct wl_list</tt> which +stores the access point to the linked list of \c wl_buffer objects that will be created from +the \c wl_shm_pool. +- A variable named \c chunk_offset represents the offset within the pool's shared +memory available for the buffer being constructed. It equals 0 when the pool has just been +created and is updated as detailed below when one or more buffers have been previously created +from the pool. A record of type <tt>struct fl_wld_buffer</tt> is created. This record will +contain (member \c wl_buffer) the address of a \c wl_buffer object that's created by function +\c wl_shm_pool_create_buffer(). This \c wl_buffer object encapsulates a section of a given +size of the pool's shared memory beginning at offset \c chunk_offset in it. +Quantity <tt>pool_memory + chunk_offset</tt> is therefore the address of the beginning of the mmap'ed memory section encapsulated by this \c wl_buffer. -Variable \c chunk_offset is then increased by the length of this section. - -A window's \c wl_buffer is re-used each time the window gets redrawn, and is destroyed by function -\c Fl_Wayland_Graphics_Driver::buffer_release() which calls \c wl_buffer_destroy() when -\c Fl_Window::hide() runs or the window is resized. - -If \c width and \c height are a window's dimensions in pixels, -\code - int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); - int size = stride * height; -\endcode -give \c size, the size in bytes of a memory buffer needed to store the window's graphics. -If <tt>chunk_offset + size > pool_size</tt> holds when function \c create_shm_buffer() attempts to -create a new \c wl_buffer object, \c chunk_offset is reset to 0, -function \c wl_shm_pool_destroy() is called to destroy -the current \c wl_shm_pool object, and a new \c wl_shm_pool object is created and used by FLTK's -"buffer factory". If <tt>size > pool_size</tt> holds at that step, the value of \c pool_size -is increased to <tt>2 * size</tt>. This mechanism allows to access new mmap'ed memory when -\c chunk_offset reaches the end of the previous mmap'ed section, and to enlarge the size of the -mmap'ed memory when necessary. - -To free the memory used by a \c wl_shm_pool object, it's not enough to destroy -all \c wl_buffer objects built from this \c wl_shm_pool object and to call -\c wl_shm_pool_destroy(). It's also necessary to call \c munmap() on the mmap'ed memory -shared between the client and the compositor and encapsulated by the \c wl_shm_pool. -This explains this type definition inside class \c Fl_Wayland_Graphics_Driver: +Member \c shm_pool of the newly constructed \c fl_wld_buffer object is set to the address of +the current \c wl_shm_pool object. This record is added to the head of the linked list of +current pool's buffers by a call to \c wl_list_insert(). +At that point, a <tt>struct fl_wld_buffer</tt> record is part of the linked list of all +such records corresponding to \c wl_buffer objects created from the same \c wl_shm_pool +object, and member \c shm_pool of this record gives the address of this \c wl_shm_pool. +When a new <tt>struct fl_wld_buffer</tt> record is to be created, \code - struct wld_shm_pool_data { // attached to wl_shm_pool objects - char *pool_memory; // start of mmap'ed memory encapsulated by the wl_shm_pool - int pool_size; // size of encapsulated memory - int use_count; // nber of active wl_buffer objects in this wl_shm_pool - bool destroyed; // true after the wl_shm_pool was destroyed - }; + struct wld_shm_pool_data *pool_data = + (struct wld_shm_pool_data *)wl_shm_pool_get_user_data(pool); + struct fl_wld_buffer *record = wl_container_of(pool_data->buffers.next, record, link); + int chunk_offset = ((char*)record->data - pool_data->pool_memory) + record->data_size; \endcode -A record of this type is created for each \c wl_shm_pool object and attached to it with -a call to \c wl_shm_pool_set_user_data(). This record contains the starting address -and the size of the mmap'ed memory section necessary for a future \c munmap() call. -Member \c destroyed is turned to \c true after the call to \c wl_shm_pool_destroy(). -Member \c use_count starts at 0, is incremented each time a \c wl_buffer is created from -this \c wl_shm_pool and decremented each time a \c wl_buffer is destroyed. -The same record is also associated to each \c wl_buffer object created from -this \c wl_shm_pool by \c wl_buffer_set_user_data(). -Overall, this allows FLTK to detect when all \c wl_buffer objects -from a \c wl_shm_pool have been destroyed and to call \c munmap() to complete the release -of that pool's memory resources. - -Wayland uses also \c wl_buffer objects to support cursors, and -FLTK uses the "buffer factory" described here also when creating custom cursors (see -\ref custom-cursor) with -function <tt>Fl_Wayland_Window_Driver::set_cursor(const Fl_RGB_Image *,…)</tt> because -\c create_shm_buffer() runs as well. In contrast, standard shaped-cursors (e.g., FL_CURSOR_INSERT) -use their own "buffer factory" inside Wayland functions such as \c wl_cursor_theme_get_cursor(). +gives the offset within the current pool's mmap'ed memory available for a new \c wl_buffer. +Macro \c wl_container_of() gives the address of a record belonging to a linked list of +records of the same type. + +A window's \c wl_buffer is re-used each time the window gets redrawn, and is destroyed by +function \c Fl_Wayland_Graphics_Driver::buffer_release() when \c Fl_Window::hide() runs or +the window is resized. Function \c Fl_Wayland_Graphics_Driver::buffer_release() destroys the +\c wl_buffer with \c wl_buffer_destroy() and removes the corresponding +\c fl_wld_buffer record from the linked list of buffers from the same \c wl_shm_pool. +Since new \c fl_wld_buffer records are added at the head of the linked list, and since +the record at the head of this list is used to compute the offset within the pool's mmap'ed +memory available for a new \c wl_buffer, destruction of the last created \c wl_buffer +allows to re-use the destroyed buffer's pool's memory for a new \c wl_buffer. +When the linked list results empty, the \c wl_shm_pool is destroyed by +\c wl_shm_pool_destroy(), the pool's mmap'ed memory is munmap'ed, and the pool's associated +<tt>struct wld_shm_pool_data</tt> is freed. + +If the sum of \c chunk_offset plus the buffer size is larger than the current pool's size +when function \c create_shm_buffer() is called, \c chunk_offset is reset +to 0, and a new \c wl_shm_pool object is created and used by FLTK's "buffer factory". +This mechanism allows to access new mmap'ed memory when \c chunk_offset reaches the end of +the previous mmap'ed section. + +Wayland uses also \c wl_buffer objects to support cursors. FLTK uses the "buffer factory" +described here when creating custom cursors (see \ref custom-cursor) with +function <tt>Fl_Wayland_Window_Driver::set_cursor(const Fl_RGB_Image *,…)</tt> which calls +\c create_shm_buffer(). In contrast, standard shaped-cursors (e.g., FL_CURSOR_INSERT) +use their own "buffer factory" inside Wayland functions such as +\c wl_cursor_theme_get_cursor(). Therefore, the fact that the \c wl_buffer objects behind standard cursors are never destroyed doesn't prevent disused <tt>struct wl_shm_pool</tt> objects from being freed because those buffers come from a distinct "buffer factory". diff --git a/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.H b/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.H index b6697df40..81a3dbf8f 100644 --- a/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.H +++ b/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.H @@ -1,7 +1,7 @@ // // Definition of class Fl_Wayland_Graphics_Driver. // -// Copyright 2021-2022 by Bill Spitzak and others. +// Copyright 2021-2023 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this @@ -22,37 +22,10 @@ #ifndef FL_WAYLAND_GRAPHICS_DRIVER_H #define FL_WAYLAND_GRAPHICS_DRIVER_H - -/* Implementation note about buffers FLTK uses to support display graphics under Wayland. - - Each window is associated to an FLTK-defined object of type struct wld_window - containing itself an FLTK-defined struct fl_wld_buffer object holding all graphics data. - Among members of this latter structure are: - - struct wl_buffer wl_buffer - is a Wayland-defined type for a graphics buffer able to be attached to a wl_surface; - - void *data - points to the beginning of the memory zone where wl_buffer stores its graphics data; - - unsigned char *draw_buffer - contains a graphics buffer to which all Cairo drawings are directed; - draw_buffer and data both have the same organization called CAIRO_FORMAT_ARGB32 in Cairo parlance - and WL_SHM_FORMAT_ARGB8888 in Wayland parlance which means BGRA byte order. - - int width - gives the pixel width of the graphics buffer; - - int stride - gives the stride of this buffer; - - size_t data_size - gives the total buffer size in bytes (thus, data_size / stride gives the buffer height); - - struct wl_callback *cb - is used to synchronize drawing with the compositor during progressive drawing. - - When a graphics scene is to be committed, the data_size bytes of draw_buffer are copied by memcpy() - starting at data, and wl_buffer is attached to the wl_surface which is committed for display - by wl_surface_commit(). - */ - - #include "../Cairo/Fl_Cairo_Graphics_Driver.H" #include <stdint.h> // for uint32_t +#include <wayland-client.h> // for wl_list + struct fl_wld_buffer { struct wl_buffer *wl_buffer; @@ -64,19 +37,19 @@ struct fl_wld_buffer { struct wl_callback *cb; bool draw_buffer_needs_commit; cairo_t *cairo_; + struct wl_shm_pool *shm_pool; + struct wl_list link; // links all buffers from the same wl_shm_pool }; -struct wld_window; class Fl_Wayland_Graphics_Driver : public Fl_Cairo_Graphics_Driver { private: struct fl_wld_buffer *buffer_; public: - struct wld_shm_pool_data { // attached to wl_shm_pool objects + struct wld_shm_pool_data { // one record attached to each wl_shm_pool object char *pool_memory; // start of mmap'ed memory encapsulated by the wl_shm_pool int pool_size; // size of encapsulated memory - int use_count; // nber of active wl_buffer objects in this wl_shm_pool - bool destroyed; // true after the wl_shm_pool was destroyed + struct wl_list buffers; // to list of fl_wld_buffer's from this pool }; Fl_Wayland_Graphics_Driver(); static const uint32_t wld_format; diff --git a/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx b/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx index cfe1ff494..4a5351701 100644 --- a/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx +++ b/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx @@ -27,53 +27,56 @@ extern "C" { # include "../../../libdecor/src/os-compatibility.h" // for os_create_anonymous_file() } +// used by create_shm_buffer and buffer_release +static struct wl_shm_pool *pool = NULL; // the current pool + struct fl_wld_buffer *Fl_Wayland_Graphics_Driver::create_shm_buffer(int width, int height) { struct fl_wld_buffer *buffer; int stride = cairo_format_stride_for_width(Fl_Cairo_Graphics_Driver::cairo_format, width); int size = stride * height; - static int pool_size = 10000000; // gets increased if necessary - static int chunk_offset = pool_size; - static int fd = -1; - static struct wl_shm_pool *pool = NULL; - if (chunk_offset + size > pool_size) { + const int default_pool_size = 10000000; // larger pools are possible if needed + int chunk_offset = 0; // offset to start of available memory in pool + struct wld_shm_pool_data *pool_data = pool ? // data record attached to current pool + (struct wld_shm_pool_data *)wl_shm_pool_get_user_data(pool) : NULL; + int pool_size = pool ? pool_data->pool_size : default_pool_size; // current pool size + if (pool) { + // last fl_wld_buffer created from current pool + struct fl_wld_buffer *record = wl_container_of(pool_data->buffers.next, record, link); + chunk_offset = ((char*)record->data - pool_data->pool_memory) + record->data_size; + } + if (!pool || chunk_offset + size > pool_size) { // if true, a new pool is needed chunk_offset = 0; - if (pool) { - struct wld_shm_pool_data *pool_data = - (struct wld_shm_pool_data *)wl_shm_pool_get_user_data(pool); - wl_shm_pool_destroy(pool); - close(fd); - pool_data->destroyed = true; - if (pool_data->use_count == 0) { - /*int err =*/ munmap(pool_data->pool_memory, pool_data->pool_size); -//printf("munmap(%p)->%d\n", pool_data->pool_memory, err); - free(pool_data); - } + pool_size = default_pool_size; + if (size > pool_size) pool_size = 2 * size; // a larger pool is needed + int fd = os_create_anonymous_file(pool_size); + if (fd < 0) { + Fl::fatal("os_create_anonymous_file failed: %s\n", strerror(errno)); } - if (size > pool_size) pool_size = 2 * size; - fd = os_create_anonymous_file(pool_size); - struct wld_shm_pool_data *pool_data = (struct wld_shm_pool_data*) - calloc(1, sizeof(struct wld_shm_pool_data)); - pool_data->pool_memory = (char*)mmap(NULL, pool_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + pool_data = (struct wld_shm_pool_data*)calloc(1, sizeof(struct wld_shm_pool_data)); + pool_data->pool_memory = (char*)mmap(NULL, pool_size, PROT_READ | PROT_WRITE, + MAP_SHARED, fd, 0); if (pool_data->pool_memory == MAP_FAILED) { close(fd); Fl::fatal("mmap failed: %s\n", strerror(errno)); } Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); pool = wl_shm_create_pool(scr_driver->wl_shm, fd, pool_size); + close(fd); // does not prevent the mmap'ed memory from being used +//puts("wl_shm_create_pool"); pool_data->pool_size = pool_size; + wl_list_init(&pool_data->buffers); wl_shm_pool_set_user_data(pool, pool_data); } buffer = (struct fl_wld_buffer*)calloc(1, sizeof(struct fl_wld_buffer)); buffer->stride = stride; buffer->wl_buffer = wl_shm_pool_create_buffer(pool, chunk_offset, width, height, stride, Fl_Wayland_Graphics_Driver::wld_format); - struct wld_shm_pool_data *pool_data = - (struct wld_shm_pool_data *)wl_shm_pool_get_user_data(pool); - pool_data->use_count++; - wl_buffer_set_user_data(buffer->wl_buffer, pool_data); + // add this buffer to head of list of current pool's buffers + wl_list_insert(&pool_data->buffers, &buffer->link); + buffer->shm_pool = pool; buffer->data = (void*)(pool_data->pool_memory + chunk_offset); - chunk_offset += size; +//fprintf(stderr, "last=%p chunk_offset=%d ", pool_data->buffers.next, chunk_offset); buffer->data_size = size; buffer->width = width; buffer->draw_buffer = new uchar[buffer->data_size]; @@ -174,15 +177,20 @@ void Fl_Wayland_Graphics_Driver::buffer_release(struct wld_window *window) { if (window->buffer) { if (window->buffer->cb) wl_callback_destroy(window->buffer->cb); + struct wl_shm_pool *my_pool = window->buffer->shm_pool; struct wld_shm_pool_data *pool_data = - (struct wld_shm_pool_data *)wl_buffer_get_user_data(window->buffer->wl_buffer); + (struct wld_shm_pool_data*)wl_shm_pool_get_user_data(my_pool); wl_buffer_destroy(window->buffer->wl_buffer); //printf("wl_buffer_destroy(%p)\n",window->buffer->wl_buffer); - pool_data->use_count--; - if (pool_data->destroyed && pool_data->use_count == 0) { - /*int err =*/ munmap(pool_data->pool_memory, pool_data->pool_size); + // remove fl_wld_buffer from list of pool's buffers + wl_list_remove(&window->buffer->link); +//printf("last=%p\n", wl_list_empty(&pool_data->buffers) ? NULL : pool_data->buffers.next); + if (wl_list_empty(&pool_data->buffers)) { // all buffers from pool are gone + wl_shm_pool_destroy(my_pool); + /*int err = */munmap(pool_data->pool_memory, pool_data->pool_size); //printf("munmap(%p)->%d\n", pool_data->pool_memory, err); free(pool_data); + if (my_pool == pool) pool = NULL; } delete[] window->buffer->draw_buffer; window->buffer->draw_buffer = NULL; diff --git a/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx b/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx index dbd6acf32..735d8b527 100644 --- a/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx +++ b/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx @@ -71,22 +71,12 @@ Fl_Wayland_Window_Driver::Fl_Wayland_Window_Driver(Fl_Window *win) : Fl_Window_D } -struct custom_cursor_data { - struct fl_wld_buffer *offscreen; - struct Fl_Wayland_Graphics_Driver::wld_shm_pool_data *buf_data; -}; - - void Fl_Wayland_Window_Driver::delete_cursor_(struct wld_window *xid, bool delete_rgb) { struct wld_window::custom_cursor_ *custom = xid->custom_cursor; if (custom) { struct wl_cursor *wl_cursor = custom->wl_cursor; struct cursor_image *new_image = (struct cursor_image*)wl_cursor->images[0]; - custom_cursor_data *buf_data = - (custom_cursor_data *)wl_buffer_get_user_data(new_image->buffer); - struct fl_wld_buffer *offscreen = buf_data->offscreen; - wl_buffer_set_user_data(new_image->buffer, buf_data->buf_data); - free(buf_data); + struct fl_wld_buffer *offscreen = (struct fl_wld_buffer *)wl_buffer_get_user_data(new_image->buffer); struct wld_window fake_xid; fake_xid.buffer = offscreen; Fl_Wayland_Graphics_Driver::buffer_release(&fake_xid); @@ -676,13 +666,13 @@ static void surface_enter(void *data, struct wl_surface *wl_surface, struct wl_o i++; } } - if (window->kind == Fl_Wayland_Window_Driver::POPUP) { - Fl_Wayland_Graphics_Driver::buffer_release(window); - window->fl_win->redraw(); - } else { - float post_scale = Fl::screen_scale(win_driver->screen_num()) * output->wld_scale; - //printf("pre_scale=%.1f post_scale=%.1f\n", pre_scale, post_scale); - if (window->fl_win->as_gl_window() || post_scale != pre_scale) { + float post_scale = Fl::screen_scale(win_driver->screen_num()) * output->wld_scale; + //printf("pre_scale=%.1f post_scale=%.1f\n", pre_scale, post_scale); + if (window->fl_win->as_gl_window() || post_scale != pre_scale) { + if (window->kind == Fl_Wayland_Window_Driver::POPUP) { + Fl_Wayland_Graphics_Driver::buffer_release(window); + window->fl_win->redraw(); + } else { win_driver->is_a_rescale(true); window->fl_win->size(window->fl_win->w(), window->fl_win->h()); win_driver->is_a_rescale(false); @@ -691,16 +681,17 @@ static void surface_enter(void *data, struct wl_surface *wl_surface, struct wl_o win_driver->Fl_Window_Driver::flush(); Fl::add_timeout(0.01, (Fl_Timeout_Handler)delayed_redraw, window->fl_win); } - } else if (window->buffer) { - if (!window->buffer->cb) { - Fl_Wayland_Graphics_Driver::buffer_commit(window); - } } - if (window->fl_win->as_gl_window()) - wl_surface_set_buffer_scale(window->wl_surface, output->wld_scale); + } else if (window->buffer) { + if (!window->buffer->cb) { + Fl_Wayland_Graphics_Driver::buffer_commit(window); + } } + if (window->fl_win->as_gl_window()) + wl_surface_set_buffer_scale(window->wl_surface, output->wld_scale); } + static void surface_leave(void *data, struct wl_surface *wl_surface, struct wl_output *wl_output) { // Do nothing because surface_leave old display arrives **after** surface_enter new display @@ -1565,12 +1556,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_wld_buffer *offscreen = Fl_Wayland_Graphics_Driver::create_shm_buffer(new_image->image.width, new_image->image.height); new_image->buffer = offscreen->wl_buffer; - custom_cursor_data *new_buf_data = - (custom_cursor_data*)malloc(sizeof(custom_cursor_data)); - new_buf_data->buf_data = (struct Fl_Wayland_Graphics_Driver::wld_shm_pool_data *) - wl_buffer_get_user_data(new_image->buffer); - new_buf_data->offscreen = offscreen; - wl_buffer_set_user_data(new_image->buffer, new_buf_data); + wl_buffer_set_user_data(new_image->buffer, offscreen); new_cursor->image_count = 1; new_cursor->images = (struct wl_cursor_image**)malloc(sizeof(struct wl_cursor_image*)); new_cursor->images[0] = (struct wl_cursor_image*)new_image; |
