Improve handling of type Fl_Offscreen under Wayland

Type Fl_Offscreen is now to be cast to cairo_t*.
Also, make sure the dimensions of GL windows are
multiples of the screen scale factor.
This commit is contained in:
ManoloFLTK 2023-08-18 18:02:35 +02:00
parent 64f64835dd
commit 3384776f8e
11 changed files with 128 additions and 90 deletions

View File

@ -39,7 +39,7 @@ typedef opaque fl_uintptr_t;
Platform-specific value representing an offscreen drawing buffer.
\note This value can be safely cast to these types on each platform:
\li X11: Pixmap
\li Wayland: struct fl_wld_draw_buffer *
\li Wayland: cairo_t *
\li Windows: HBITMAP
\li macOS: CGContextRef
*/

View File

@ -528,11 +528,12 @@ give \c size, the common size of both byte arrays.
Section \ref wayland-buffer-factory below details how FLTK creates \c wl_buffer objects.
FLTK associates to each surface a <tt>struct fl_wld_buffer</tt> (see \ref fl_wld_buffer) containing
a pointer to the byte array of the Cairo image surface (member \c draw_buffer), information about the
FLTK associates to each surface a
<tt>struct Fl_Wayland_Graphics_Driver::wld_buffer</tt> (see \ref wld_buffer) containing
a pointer to the byte array of the Cairo image surface (member \c buffer), information about the
Wayland buffer (members \c wl_buffer and \c data), the common size of the Cairo surface's and
Wayland buffer's byte arrays (member \c data_size), and other information. A pointer to this
<tt>struct fl_wld_buffer</tt> is memorized as member \c buffer of the Fl_Window's \ref wld_window.
<tt>struct Fl_Wayland_Graphics_Driver::wld_buffer</tt> is memorized as member \c buffer of the Fl_Window's \ref wld_window.
All drawing operations to the Fl_Window then modify the content of the Cairo image surface.
Function \c Fl_Wayland_Window_Driver::flush() is in charge of sending FLTK
@ -550,7 +551,7 @@ mechanism to make sure the surface's \c wl_buffer is not changed until the surfa
mapped on the display. This 3-step mechanism works as follows:
- Fl_Wayland_Graphics_Driver::buffer_commit() first calls function \c wl_surface_frame() to
obtain a <tt>struct wl_callback</tt> object and stores it as member \c cb of the surface's
\ref fl_wld_buffer.
\ref wld_buffer.
- Then it calls \c wl_callback_add_listener() to associate this object to the FLTK-defined,
callback function \c surface_frame_done() that Wayland calls when it's ready for another
mapping operation.
@ -609,23 +610,23 @@ 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
from the pool. A record of type <tt>struct Fl_Wayland_Graphics_Driver::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.
Member \c shm_pool of the newly constructed \c fl_wld_buffer object is set to the address of
Member \c shm_pool of the newly constructed \c Fl_Wayland_Graphics_Driver::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
At that point, a <tt>struct Fl_Wayland_Graphics_Driver::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,
When a new <tt>struct Fl_Wayland_Graphics_Driver::wld_buffer</tt> record is to be created,
\code
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);
struct Fl_Wayland_Graphics_Driver::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
gives the offset within the current pool's mmap'ed memory available for a new \c wl_buffer.
@ -636,8 +637,8 @@ A window's \c wl_buffer is re-used each time the window gets redrawn, and is des
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
\c Fl_Wayland_Graphics_Driver::wld_buffer record from the linked list of buffers from the same \c wl_shm_pool.
Since new \c Fl_Wayland_Graphics_Driver::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.
@ -1110,7 +1111,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 fl_wld_buffer *buffer; // see \ref fl_wld_buffer
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
union {
@ -1132,29 +1133,39 @@ struct wld_window {
}
</pre>
\anchor fl_wld_buffer
<h3>struct fl_wld_buffer and struct fl_wld_draw_buffer</h3>
Defined in \c Fl_Wayland_Graphics_Driver.H.
One <tt>struct fl_wld_buffer</tt> record is created
\anchor wld_buffer
<h3>struct wld_buffer and struct draw_buffer</h3>
They are defined as types of class \c Fl_Wayland_Graphics_Driver in file
\c Fl_Wayland_Graphics_Driver.H.
One <tt>struct Fl_Wayland_Graphics_Driver::wld_buffer</tt> record is created
by \c Fl_Wayland_Graphics_Driver::create_shm_buffer() when
an Fl_Window is show()'n or resized,
when a custom cursor shape is created, or when text is dragged.
A <tt>struct fl_wld_draw_buffer</tt> record is created when an Fl_Image_Surface object
is created by the \c Fl_Wayland_Image_Surface_Driver c'tor.
One such record is also embedded inside each <tt>struct fl_wld_buffer</tt> record.
A <tt>struct Fl_Wayland_Graphics_Driver::draw_buffer</tt> record
is created when an Fl_Image_Surface object is created.
One such record is also embedded inside each
<tt>struct Fl_Wayland_Graphics_Driver::wld_buffer</tt> record.
<pre>
struct fl_wld_draw_buffer { // Under Wayland, Fl_Offscreen points to this structure
size_t data_size; // of wl_buffer and draw_buffer
struct Fl_Wayland_Graphics_Driver::draw_buffer {
size_t data_size; // of wl_buffer and buffer
int stride; // bytes per line
int width;
unsigned char *buffer; // address of the beginning of the Cairo image surface's byte array
cairo_t *cairo_; // used when drawing to the Cairo image surface
};
</pre>
FLTK gives offscreen buffers the platform-dependent type \c Fl_Offscreen which is
in fact member \c cairo_ of <tt>struct Fl_Wayland_Graphics_Driver::draw_buffer</tt>.
Thus, a variable with type \c Fl_Offscreen needs be casted to type \c cairo_t*.
Member function <tt>struct Fl_Wayland_Graphics_Driver::draw_buffer *
Fl_Wayland_Graphics_Driver::offscreen_buffer(Fl_Offscreen);</tt>
returns the \c draw_buffer record corresponding to an \c Fl_Offscreen value.
struct fl_wld_buffer {
struct fl_wld_draw_buffer draw_buffer;
<pre>
struct Fl_Wayland_Graphics_Driver::wld_buffer {
struct draw_buffer draw_buffer;
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 while Wayland buffer is being committed

View File

@ -46,7 +46,7 @@ Fl_Wayland_Copy_Surface_Driver::~Fl_Wayland_Copy_Surface_Driver() {
void Fl_Wayland_Copy_Surface_Driver::set_current() {
Fl_Surface_Device::set_current();
((Fl_Wayland_Graphics_Driver*)driver())->set_cairo(((struct fl_wld_draw_buffer *)img_surf->offscreen())->cairo_);
((Fl_Wayland_Graphics_Driver*)driver())->set_cairo((cairo_t*)img_surf->offscreen());
}

View File

@ -114,7 +114,8 @@ char *Fl_Wayland_Gl_Window_Driver::alpha_mask_for_string(const char *str, int n,
fl_draw(str, n, 0, fl_height() - fl_descent());
// get the R channel only of the bitmap
char *alpha_buf = new char[w*h], *r = alpha_buf;
struct fl_wld_draw_buffer *off = (struct fl_wld_draw_buffer *)surf->offscreen();
struct Fl_Wayland_Graphics_Driver::draw_buffer *off =
Fl_Wayland_Graphics_Driver::offscreen_buffer(surf->offscreen());
for (int i = 0; i < h; i++) {
uchar *q = off->buffer + i * off->stride;
for (int j = 0; j < w; j++) {
@ -274,7 +275,10 @@ void Fl_Wayland_Gl_Window_Driver::make_current_before() {
if (!egl_window) {
struct wld_window *win = fl_wl_xid(pWindow);
struct wl_surface *surface = win->wl_surface;
egl_window = wl_egl_window_create(surface, pWindow->pixel_w(), pWindow->pixel_h());
int W = pWindow->pixel_w();
int H = pWindow->pixel_h();
int scale = Fl_Wayland_Window_Driver::driver(pWindow)->wld_scale();
egl_window = wl_egl_window_create(surface, (W/scale)*scale, (H/scale)*scale);
if (egl_window == EGL_NO_SURFACE) {
Fl::fatal("Can't create egl window with wl_egl_window_create()\n");
} else {
@ -283,8 +287,7 @@ void Fl_Wayland_Gl_Window_Driver::make_current_before() {
Fl_Wayland_Gl_Choice *g = (Fl_Wayland_Gl_Choice*)this->g();
egl_surface = eglCreateWindowSurface(egl_display, g->egl_conf, egl_window, NULL);
//fprintf(stderr, "Created egl surface=%p at scale=%d\n", egl_surface, win->scale);
wl_surface_set_buffer_scale(surface,
Fl_Wayland_Window_Driver::driver(pWindow)->wld_scale());
wl_surface_set_buffer_scale(surface, scale);
// Tested apps: shape, glpuzzle, cube, fractals, gl_overlay, fullscreen, unittests,
// OpenGL3-glut-test, OpenGL3test.
// Tested wayland compositors: mutter, kde-plasma, weston, sway on FreeBSD.
@ -383,8 +386,8 @@ 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());
int s = Fl_Wayland_Window_Driver::driver(pWindow)->wld_scale();
W = (W * s) * f;
H = (H * s) * f;
W = int(W * f) * s; // W, H must be multiples of int s
H = int(H * f) * s;
int W2, H2;
wl_egl_window_get_attached_size(egl_window, &W2, &H2);
if (W2 != W || H2 != H) {

View File

@ -27,28 +27,24 @@
#include <wayland-client.h> // for wl_list
struct fl_wld_draw_buffer { // Under Wayland, Fl_Offscreen points to this structure
size_t data_size; // of wl_buffer and draw_buffer
int stride;
int width;
unsigned char *buffer;
cairo_t *cairo_;
};
struct fl_wld_buffer {
struct fl_wld_draw_buffer draw_buffer;
struct wl_buffer *wl_buffer;
void *data;
struct wl_callback *cb;
bool draw_buffer_needs_commit;
struct wl_shm_pool *shm_pool;
struct wl_list link; // links all buffers from the same wl_shm_pool
};
class Fl_Wayland_Graphics_Driver : public Fl_Cairo_Graphics_Driver {
public:
struct draw_buffer {
size_t data_size; // of wl_buffer and buffer
int stride;
int width;
unsigned char *buffer;
cairo_t *cairo_;
};
struct wld_buffer {
struct draw_buffer draw_buffer;
struct wl_buffer *wl_buffer;
void *data;
struct wl_callback *cb;
bool draw_buffer_needs_commit;
struct wl_shm_pool *shm_pool;
struct wl_list link; // links all buffers from the same wl_shm_pool
};
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
@ -56,10 +52,11 @@ public:
};
static const uint32_t wld_format;
void copy_offscreen(int x, int y, int w, int h, Fl_Offscreen osrc, int srcx, int srcy) FL_OVERRIDE;
static struct fl_wld_buffer *create_shm_buffer(int width, int height);
static struct wld_buffer *create_shm_buffer(int width, int height);
static void buffer_release(struct wld_window *window);
static void buffer_commit(struct wld_window *window, struct flCairoRegion *r = NULL);
static void cairo_init(struct fl_wld_draw_buffer *buffer, int width, int height, int stride, cairo_format_t format);
static void cairo_init(struct draw_buffer *buffer, int width, int height, int stride, cairo_format_t format);
static struct draw_buffer *offscreen_buffer(Fl_Offscreen);
};
#endif // FL_WAYLAND_GRAPHICS_DRIVER_H

View File

@ -31,9 +31,10 @@ extern "C" {
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_Wayland_Graphics_Driver::wld_buffer *
Fl_Wayland_Graphics_Driver::create_shm_buffer(int width, int height)
{
struct fl_wld_buffer *buffer;
struct wld_buffer *buffer;
int stride = cairo_format_stride_for_width(Fl_Cairo_Graphics_Driver::cairo_format, width);
int size = stride * height;
const int default_pool_size = 10000000; // larger pools are possible if needed
@ -42,8 +43,8 @@ struct fl_wld_buffer *Fl_Wayland_Graphics_Driver::create_shm_buffer(int width, i
(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);
// last wld_buffer created from current pool
struct wld_buffer *record = wl_container_of(pool_data->buffers.next, record, link);
chunk_offset = ((char*)record->data - pool_data->pool_memory) + record->draw_buffer.data_size;
}
if (!pool || chunk_offset + size > pool_size) { // if true, a new pool is needed
@ -69,7 +70,7 @@ struct fl_wld_buffer *Fl_Wayland_Graphics_Driver::create_shm_buffer(int width, i
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 = (struct wld_buffer*)calloc(1, sizeof(struct wld_buffer));
buffer->wl_buffer = wl_shm_pool_create_buffer(pool, chunk_offset, width, height, stride, Fl_Wayland_Graphics_Driver::wld_format);
// add this buffer to head of list of current pool's buffers
wl_list_insert(&pool_data->buffers, &buffer->link);
@ -106,7 +107,7 @@ static void surface_frame_done(void *data, struct wl_callback *cb, uint32_t time
// copy pixels in region r from the Cairo surface to the Wayland buffer
static void copy_region(struct wld_window *window, struct flCairoRegion *r) {
struct fl_wld_buffer *buffer = window->buffer;
struct Fl_Wayland_Graphics_Driver::wld_buffer *buffer = window->buffer;
float f = Fl::screen_scale(window->fl_win->screen_num()) *
Fl_Wayland_Window_Driver::driver(window->fl_win)->wld_scale();
for (int i = 0; i < r->count; i++) {
@ -149,7 +150,7 @@ void Fl_Wayland_Graphics_Driver::buffer_commit(struct wld_window *window,
}
void Fl_Wayland_Graphics_Driver::cairo_init(struct fl_wld_draw_buffer *buffer, int width, int height, int stride, cairo_format_t format) {
void Fl_Wayland_Graphics_Driver::cairo_init(struct Fl_Wayland_Graphics_Driver::draw_buffer *buffer, int width, int height, int stride, cairo_format_t format) {
buffer->data_size = stride * height;
buffer->stride = stride;
buffer->buffer = new uchar[buffer->data_size];
@ -182,7 +183,7 @@ void Fl_Wayland_Graphics_Driver::buffer_release(struct wld_window *window)
(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);
// remove fl_wld_buffer from list of pool's buffers
// remove 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
@ -206,14 +207,13 @@ const uint32_t Fl_Wayland_Graphics_Driver::wld_format = WL_SHM_FORMAT_ARGB8888;
void Fl_Wayland_Graphics_Driver::copy_offscreen(int x, int y, int w, int h, Fl_Offscreen src, int srcx, int srcy) {
// draw portion srcx,srcy,w,h of osrc to position x,y (top-left) of the graphics driver's surface
struct fl_wld_draw_buffer *osrc = (struct fl_wld_draw_buffer *)src;
cairo_matrix_t matrix;
cairo_get_matrix(cairo_, &matrix);
double s = matrix.xx;
cairo_save(cairo_);
cairo_rectangle(cairo_, x, y, w, h);
cairo_clip(cairo_);
cairo_surface_t *surf = cairo_get_target(osrc->cairo_);
cairo_surface_t *surf = cairo_get_target((cairo_t *)src);
cairo_pattern_t *pat = cairo_pattern_create_for_surface(surf);
cairo_set_source(cairo_, pat);
cairo_matrix_init_scale(&matrix, s, s);
@ -223,3 +223,9 @@ void Fl_Wayland_Graphics_Driver::copy_offscreen(int x, int y, int w, int h, Fl_O
cairo_pattern_destroy(pat);
cairo_restore(cairo_);
}
struct Fl_Wayland_Graphics_Driver::draw_buffer *Fl_Wayland_Graphics_Driver::offscreen_buffer(
Fl_Offscreen offscreen) {
return (struct draw_buffer*)cairo_get_user_data((cairo_t*)offscreen, NULL);
}

View File

@ -32,11 +32,14 @@ Fl_Wayland_Image_Surface_Driver::Fl_Wayland_Image_Surface_Driver(int w, int h, i
w = int(w * d);
h = int(h * d);
}
struct fl_wld_draw_buffer *off_ = (struct fl_wld_draw_buffer*)calloc(1, sizeof(struct fl_wld_draw_buffer));
offscreen = (Fl_Offscreen)off_;
struct Fl_Wayland_Graphics_Driver::draw_buffer *off_ =
(struct Fl_Wayland_Graphics_Driver::draw_buffer*)calloc(1,
sizeof(struct Fl_Wayland_Graphics_Driver::draw_buffer));
Fl_Wayland_Graphics_Driver::cairo_init(off_, w, h,
cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, w), CAIRO_FORMAT_RGB24);
}
offscreen = (Fl_Offscreen)off_->cairo_;
cairo_set_user_data(off_->cairo_, NULL, off_, NULL);
} else offscreen = off;
driver(new Fl_Wayland_Graphics_Driver());
if (d != 1 && high_res) driver()->scale(d);
}
@ -44,23 +47,25 @@ Fl_Wayland_Image_Surface_Driver::Fl_Wayland_Image_Surface_Driver(int w, int h, i
Fl_Wayland_Image_Surface_Driver::~Fl_Wayland_Image_Surface_Driver() {
if (offscreen && !external_offscreen) {
cairo_destroy(((struct fl_wld_draw_buffer *)offscreen)->cairo_);
delete[] ((struct fl_wld_draw_buffer *)offscreen)->buffer;
free((struct fl_wld_draw_buffer *)offscreen);
struct Fl_Wayland_Graphics_Driver::draw_buffer *buffer =
Fl_Wayland_Graphics_Driver::offscreen_buffer(offscreen);
cairo_destroy((cairo_t *)offscreen);
delete[] buffer->buffer;
free(buffer);
}
delete driver();
}
void Fl_Wayland_Image_Surface_Driver::set_current() {
Fl_Surface_Device::set_current();
((Fl_Wayland_Graphics_Driver*)fl_graphics_driver)->set_cairo(((struct fl_wld_draw_buffer*)offscreen)->cairo_);
((Fl_Wayland_Graphics_Driver*)fl_graphics_driver)->set_cairo((cairo_t*)offscreen);
pre_window = Fl_Wayland_Window_Driver::wld_window;
Fl_Wayland_Window_Driver::wld_window = NULL;
fl_window = 0;
}
void Fl_Wayland_Image_Surface_Driver::end_current() {
cairo_surface_t *surf = cairo_get_target(((struct fl_wld_draw_buffer *)offscreen)->cairo_);
cairo_surface_t *surf = cairo_get_target((cairo_t*)offscreen);
cairo_surface_flush(surf);
Fl_Wayland_Window_Driver::wld_window = pre_window;
fl_window = (Window)pre_window;
@ -77,20 +82,21 @@ void Fl_Wayland_Image_Surface_Driver::untranslate() {
Fl_RGB_Image* Fl_Wayland_Image_Surface_Driver::image() {
// Convert depth-4 image in draw_buffer to a depth-3 image while exchanging R and B colors
int height = ((struct fl_wld_draw_buffer *)offscreen)->data_size / ((struct fl_wld_draw_buffer *)offscreen)->stride;
uchar *rgb = new uchar[((struct fl_wld_draw_buffer *)offscreen)->width * height * 3];
struct Fl_Wayland_Graphics_Driver::draw_buffer *off_buf = Fl_Wayland_Graphics_Driver::offscreen_buffer(offscreen);
int height = off_buf->data_size / off_buf->stride;
uchar *rgb = new uchar[off_buf->width * height * 3];
uchar *p = rgb;
uchar *q;
for (int j = 0; j < height; j++) {
q = ((struct fl_wld_draw_buffer *)offscreen)->buffer + j*((struct fl_wld_draw_buffer *)offscreen)->stride;
for (int i = 0; i < ((struct fl_wld_draw_buffer *)offscreen)->width; i++) { // exchange R and B colors, transmit G
q = off_buf->buffer + j*off_buf->stride;
for (int i = 0; i < off_buf->width; i++) { // exchange R and B colors, transmit G
*p = *(q+2);
*(p+1) = *(q+1);
*(p+2) = *q;
p += 3; q += 4;
}
}
Fl_RGB_Image *image = new Fl_RGB_Image(rgb, ((struct fl_wld_draw_buffer *)offscreen)->width, height, 3);
Fl_RGB_Image *image = new Fl_RGB_Image(rgb, off_buf->width, height, 3);
image->alloc_array = 1;
return image;
}

View File

@ -1507,11 +1507,12 @@ Fl_RGB_Image *Fl_Wayland_Screen_Driver::read_win_rectangle(int X, int Y, int w,
bool ignore, bool *p_ignore) {
struct wld_window* xid = win ? fl_wl_xid(win) : NULL;
if (win && (!xid || !xid->buffer)) return NULL;
struct fl_wld_draw_buffer *buffer;
struct Fl_Wayland_Graphics_Driver::draw_buffer *buffer;
if (win) buffer = &xid->buffer->draw_buffer;
else {
Fl_Image_Surface_Driver *dr = (Fl_Image_Surface_Driver*)Fl_Surface_Device::surface();
buffer = (struct fl_wld_draw_buffer *)dr->image_surface()->offscreen();
buffer = Fl_Wayland_Graphics_Driver::offscreen_buffer(
dr->image_surface()->offscreen());
}
float s = win ?
Fl_Wayland_Window_Driver::driver(win)->wld_scale() * scale(win->screen_num()) :
@ -1545,7 +1546,7 @@ Fl_RGB_Image *Fl_Wayland_Screen_Driver::read_win_rectangle(int X, int Y, int w,
void Fl_Wayland_Screen_Driver::offscreen_size(Fl_Offscreen off_, int &width, int &height)
{
struct fl_wld_draw_buffer *off = (struct fl_wld_draw_buffer *)off_;
struct Fl_Wayland_Graphics_Driver::draw_buffer *off = Fl_Wayland_Graphics_Driver::offscreen_buffer(off_);
width = off->width;
height = off->data_size / off->stride;
}

View File

@ -25,6 +25,7 @@
#include "../../Fl_Window_Driver.H"
#include <FL/Fl_Plugin.H>
#include "Fl_Wayland_Screen_Driver.H"
#include "Fl_Wayland_Graphics_Driver.H"
/*
@ -137,7 +138,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 fl_wld_buffer *buffer;
struct Fl_Wayland_Graphics_Driver::wld_buffer *buffer;
struct xdg_surface *xdg_surface;
enum Fl_Wayland_Window_Driver::kind kind;
union { // for each value of kind

View File

@ -76,7 +76,9 @@ void Fl_Wayland_Window_Driver::delete_cursor_(struct wld_window *xid, bool delet
if (custom) {
struct wl_cursor *wl_cursor = custom->wl_cursor;
struct cursor_image *new_image = (struct cursor_image*)wl_cursor->images[0];
struct fl_wld_buffer *offscreen = (struct fl_wld_buffer *)wl_buffer_get_user_data(new_image->buffer);
struct Fl_Wayland_Graphics_Driver::wld_buffer *offscreen =
(struct Fl_Wayland_Graphics_Driver::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);
@ -575,7 +577,7 @@ int Fl_Wayland_Window_Driver::scroll(int src_x, int src_y, int src_w, int src_h,
void (*draw_area)(void*, int,int,int,int), void* data)
{
struct wld_window * xid = fl_wl_xid(pWindow);
struct fl_wld_buffer *buffer = xid->buffer;
struct Fl_Wayland_Graphics_Driver::wld_buffer *buffer = xid->buffer;
float s = wld_scale() * fl_graphics_driver->scale();
if (s != 1) {
src_x = src_x * s;
@ -1620,7 +1622,7 @@ int Fl_Wayland_Window_Driver::set_cursor_4args(const Fl_RGB_Image *rgb, int hotx
new_image->image.delay = 0;
new_image->offset = 0;
//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);
struct Fl_Wayland_Graphics_Driver::wld_buffer *offscreen = Fl_Wayland_Graphics_Driver::create_shm_buffer(new_image->image.width, new_image->image.height);
new_image->buffer = offscreen->wl_buffer;
wl_buffer_set_user_data(new_image->buffer, offscreen);
new_cursor->image_count = 1;
@ -1628,7 +1630,11 @@ int Fl_Wayland_Window_Driver::set_cursor_4args(const Fl_RGB_Image *rgb, int hotx
new_cursor->images[0] = (struct wl_cursor_image*)new_image;
new_cursor->name = strdup("custom cursor");
// draw the rgb image to the cursor's drawing buffer
Fl_Image_Surface *img_surf = new Fl_Image_Surface(new_image->image.width, new_image->image.height, 0, (Fl_Offscreen)&offscreen->draw_buffer);
cairo_set_user_data(offscreen->draw_buffer.cairo_,
NULL,
&offscreen->draw_buffer,
NULL);
Fl_Image_Surface *img_surf = new Fl_Image_Surface(new_image->image.width, new_image->image.height, 0, (Fl_Offscreen)offscreen->draw_buffer.cairo_);
Fl_Surface_Device::push_current(img_surf);
Fl_Wayland_Graphics_Driver *driver = (Fl_Wayland_Graphics_Driver*)img_surf->driver();
cairo_scale(driver->cr(), scale, scale);

View File

@ -101,7 +101,9 @@ static void data_source_handle_cancelled(void *data, struct wl_data_source *sour
wl_data_source_destroy(source);
doing_dnd = false;
if (dnd_icon) {
struct fl_wld_buffer * off = (struct fl_wld_buffer *)wl_surface_get_user_data(dnd_icon);
struct Fl_Wayland_Graphics_Driver::wld_buffer *off =
(struct Fl_Wayland_Graphics_Driver::wld_buffer *)
wl_surface_get_user_data(dnd_icon);
struct wld_window fake_window;
fake_window.buffer = off;
Fl_Wayland_Graphics_Driver::buffer_release(&fake_window);
@ -176,7 +178,7 @@ static const struct wl_data_source_listener data_source_listener = {
};
static struct fl_wld_buffer *offscreen_from_text(const char *text, int scale) {
static struct Fl_Wayland_Graphics_Driver::wld_buffer *offscreen_from_text(const char *text, int scale) {
const char *p, *q;
int width = 0, height, w2, ltext = strlen(text);
fl_font(FL_HELVETICA, 10 * scale);
@ -196,9 +198,14 @@ static struct fl_wld_buffer *offscreen_from_text(const char *text, int scale) {
if (width > 300*scale) width = 300*scale;
height = nl * fl_height() + 3;
width += 6;
struct fl_wld_buffer *off = Fl_Wayland_Graphics_Driver::create_shm_buffer(width, height);
width = ceil(width/float(scale)) * scale; // these must be multiples of scale
height = ceil(height/float(scale)) * scale;
struct Fl_Wayland_Graphics_Driver::wld_buffer *off = Fl_Wayland_Graphics_Driver::create_shm_buffer(width, height);
memset(off->draw_buffer.buffer, 0, off->draw_buffer.data_size);
Fl_Image_Surface *surf = new Fl_Image_Surface(width, height, 0, (Fl_Offscreen)&off->draw_buffer);
cairo_set_user_data(off->draw_buffer.cairo_,
NULL,
&off->draw_buffer, NULL);
Fl_Image_Surface *surf = new Fl_Image_Surface(width, height, 0, (Fl_Offscreen)off->draw_buffer.cairo_);
Fl_Surface_Device::push_current(surf);
p = text;
fl_font(FL_HELVETICA, 10 * scale);
@ -232,13 +239,13 @@ int Fl_Wayland_Screen_Driver::dnd(int use_selection) {
wl_data_source_add_listener(source, &data_source_listener, (void*)0);
wl_data_source_offer(source, wld_plain_text_clipboard);
wl_data_source_set_actions(source, WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY);
struct fl_wld_buffer * off = NULL;
struct Fl_Wayland_Graphics_Driver::wld_buffer *off = NULL;
int s = 1;
if (use_selection) {
// use the text as dragging icon
Fl_Widget *current = Fl::pushed() ? Fl::pushed() : Fl::first_window();
s = Fl_Wayland_Window_Driver::driver(current->top_window())->wld_scale();
off = (struct fl_wld_buffer *)offscreen_from_text(fl_selection_buffer[0], s);
off = (struct Fl_Wayland_Graphics_Driver::wld_buffer *)offscreen_from_text(fl_selection_buffer[0], s);
dnd_icon = wl_compositor_create_surface(scr_driver->wl_compositor);
} else dnd_icon = NULL;
doing_dnd = true;