Wayland: add support for multiple high or low DPI displays
This commit is contained in:
parent
af4789077f
commit
eeb9267e6e
@ -526,17 +526,6 @@ public:
|
||||
*/
|
||||
void make_current();
|
||||
|
||||
/**
|
||||
Changes the cursor for this window.
|
||||
|
||||
This always calls the system. If you are changing the cursor a lot
|
||||
you may want to keep track of how you set it in a static variable
|
||||
and call this only if the new cursor is different.
|
||||
|
||||
The type Fl_Cursor is an enumeration defined in <FL/Enumerations.H>.
|
||||
|
||||
\see cursor(const Fl_RGB_Image*, int, int), default_cursor()
|
||||
*/
|
||||
void cursor(Fl_Cursor);
|
||||
void cursor(const Fl_RGB_Image*, int, int);
|
||||
void default_cursor(Fl_Cursor);
|
||||
|
||||
@ -96,12 +96,9 @@ a minimized window has no effect.
|
||||
it's currently not possible for an app to be notified of changes to the content of
|
||||
the system clipboard, that is, Fl::add_clipboard_notify() has no effect.
|
||||
|
||||
* With GTK-style window titlebars, narrow windows are silently forced to be wide enough
|
||||
* Narrow windows with a titlebar are silently forced to be wide enough
|
||||
for the titlebar to display window buttons and a few letters of the title.
|
||||
|
||||
* The library should support multi-display configurations in principle, but has not been
|
||||
tested in that situation.
|
||||
|
||||
* Text input methods have been tested without any understanding of the writing systems,
|
||||
so feedback on this subject would be helpful.
|
||||
|
||||
|
||||
@ -451,19 +451,19 @@ displaying dragged text in a DnD operation.
|
||||
|
||||
\section wayland-display Displays and HighDPI support
|
||||
|
||||
Wayland uses the concept of seat of type <tt>struct wl_seat</tt> which encompasses displays,
|
||||
a keyboard, a mouse, and a trackpad. It might be possible for an app to deal with several seats,
|
||||
but that has not been tested with FLTK yet. Each seat may contain one or more displays, which
|
||||
Wayland calls outputs, of type <tt>struct wl_output</tt>.
|
||||
Wayland uses the concept of <em>seat</em> of type <tt>struct wl_seat</tt> which encompasses displays,
|
||||
a keyboard, a mouse, and a trackpad. Although Wayland may be in principle able to deal with several
|
||||
seats, FLTK's Wayland platform is conceived for one seat only. That seat may contain one or more
|
||||
displays, which Wayland calls <em>outputs</em>, of type <tt>struct wl_output</tt>.
|
||||
|
||||
As written above, function \c registry_handle_global() discovers available seats at start-up time.
|
||||
This function also associates a 'listener' to each display
|
||||
by calling function \c wl_output_add_listener(). This 'listener' is an array of callback function
|
||||
As written above, function \c registry_handle_global() discovers the available seat at start-up time.
|
||||
This function also associates a listener to each display connected to the system
|
||||
by calling function \c wl_output_add_listener(). This listener is an array of callback function
|
||||
pointers among which one (\c output_mode) runs when the display is resized and another
|
||||
(\c output_scale) when the Wayland scale factor (see below) is changed.
|
||||
FLTK defines type <tt>struct Fl_Wayland_Screen_Driver::output</tt> (see \ref output)
|
||||
to store display size and scaling information.
|
||||
One such record is created for each display. FLTK uses 2 distinct scaling parameters under Wayland:
|
||||
One such record is created for each display. FLTK uses 2 distinct scaling parameters for each display:
|
||||
- <tt>int wld_scale;</tt>. This member variable of
|
||||
<tt>struct Fl_Wayland_Screen_Driver::output</tt> typically equals 1 for standard, and 2 for
|
||||
HighDPI displays. Its value is set by the Wayland compositor for each display with the effect
|
||||
|
||||
@ -179,7 +179,6 @@ static void do_set_cursor(struct seat *seat, struct wl_cursor *wl_cursor = NULL)
|
||||
image->hotspot_x / scale,
|
||||
image->hotspot_y / scale);
|
||||
wl_surface_attach(seat->cursor_surface, buffer, 0, 0);
|
||||
wl_surface_set_buffer_scale(seat->cursor_surface, scale);
|
||||
wl_surface_damage_buffer(seat->cursor_surface, 0, 0,
|
||||
image->width, image->height);
|
||||
wl_surface_commit(seat->cursor_surface);
|
||||
@ -258,7 +257,8 @@ static void pointer_enter(void *data,
|
||||
{
|
||||
Fl_Window *win = event_coords_from_surface(surface, surface_x, surface_y);
|
||||
if (!win) return;
|
||||
struct wl_cursor *cursor = fl_wl_xid(win)->custom_cursor;// use custom cursor if present
|
||||
// use custom cursor if present
|
||||
struct wl_cursor *cursor = fl_wl_xid(win)->custom_cursor ? fl_wl_xid(win)->custom_cursor->wl_cursor : NULL;
|
||||
struct seat *seat = (struct seat*)data;
|
||||
do_set_cursor(seat, cursor);
|
||||
seat->serial = serial;
|
||||
@ -412,6 +412,7 @@ static void cursor_surface_enter(void *data,
|
||||
struct wl_surface *wl_surface,
|
||||
struct wl_output *wl_output)
|
||||
{
|
||||
// Runs when the seat's cursor_surface enters a display
|
||||
struct seat *seat = (struct seat*)data;
|
||||
struct pointer_output *pointer_output;
|
||||
|
||||
@ -428,9 +429,13 @@ static void cursor_surface_enter(void *data,
|
||||
if (win) {
|
||||
Fl_Wayland_Window_Driver *driver = Fl_Wayland_Window_Driver::driver(win);
|
||||
//fprintf(stderr, "cursor_surface_enter: cursor_default=%d standard_cursor=%d\n", driver->cursor_default(), driver->standard_cursor());
|
||||
struct wl_cursor *cursor = fl_wl_xid(win)->custom_cursor;
|
||||
if (cursor) do_set_cursor(seat, cursor);
|
||||
else if (driver->cursor_default()) driver->set_cursor(driver->cursor_default());
|
||||
struct wld_window *xid = fl_wl_xid(win);
|
||||
struct wld_window::custom_cursor *custom = xid->custom_cursor;
|
||||
if (custom) {
|
||||
// Change custom cursor's width & height according to display's wld_scale
|
||||
driver->set_cursor_4args(custom->rgb, custom->hotx, custom->hoty, false);
|
||||
do_set_cursor(seat, xid->custom_cursor->wl_cursor);
|
||||
} else if (driver->cursor_default()) driver->set_cursor(driver->cursor_default());
|
||||
else win->cursor(driver->standard_cursor());
|
||||
}
|
||||
}
|
||||
@ -448,6 +453,14 @@ static void cursor_surface_leave(void *data,
|
||||
free(pointer_output);
|
||||
}
|
||||
}
|
||||
try_update_cursor(seat);
|
||||
// maintain custom window cursor
|
||||
Fl_Window *win = Fl::first_window();
|
||||
if (win) {
|
||||
struct wld_window *xid = fl_wl_xid(win);
|
||||
if (xid->custom_cursor) do_set_cursor(seat, xid->custom_cursor->wl_cursor);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static struct wl_surface_listener cursor_surface_listener = {
|
||||
@ -962,6 +975,17 @@ static void output_scale(void *data, struct wl_output *wl_output, int32_t factor
|
||||
Fl_Wayland_Screen_Driver::output *output = (Fl_Wayland_Screen_Driver::output*)data;
|
||||
output->wld_scale = factor;
|
||||
//fprintf(stderr,"output_scale: wl_output=%p factor=%d\n",wl_output, factor);
|
||||
// rescale cursors of windows that map here and have a custom cursor
|
||||
Fl_Window *win = Fl::first_window();
|
||||
while (win) {
|
||||
struct wld_window *xid = fl_wl_xid(win);
|
||||
if (xid->custom_cursor && wl_output_get_user_data(wl_output) == xid->output) {
|
||||
Fl_Wayland_Window_Driver *driver = Fl_Wayland_Window_Driver::driver(win);
|
||||
driver->set_cursor_4args(xid->custom_cursor->rgb,
|
||||
xid->custom_cursor->hotx, xid->custom_cursor->hoty, false);
|
||||
};
|
||||
win = Fl::next_window(win);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -60,7 +60,7 @@ private:
|
||||
static bool in_flush; // useful for progressive window drawing
|
||||
static Fl_Wayland_Plugin *gl_plugin();
|
||||
Fl_Cursor standard_cursor_; // window's standard custom kind
|
||||
void delete_cursor_(struct wld_window *);
|
||||
void delete_cursor_(struct wld_window *, bool keep_rgb = false);
|
||||
struct gl_start_support *gl_start_support_; // for support of gl_start/gl_finish
|
||||
public:
|
||||
inline Fl_Cursor standard_cursor() { return standard_cursor_; };
|
||||
@ -116,6 +116,7 @@ public:
|
||||
// --- window cursor stuff
|
||||
int set_cursor(Fl_Cursor) FL_OVERRIDE;
|
||||
int set_cursor(const Fl_RGB_Image*, int, int) FL_OVERRIDE;
|
||||
int set_cursor_4args(const Fl_RGB_Image*, int, int, bool);
|
||||
|
||||
void shape(const Fl_Image* img) FL_OVERRIDE;
|
||||
void capture_titlebar_and_borders(Fl_RGB_Image*& top, Fl_RGB_Image*& left, Fl_RGB_Image*& bottom, Fl_RGB_Image*& right) FL_OVERRIDE;
|
||||
@ -136,14 +137,18 @@ struct wld_window {
|
||||
struct wl_surface *wl_surface;
|
||||
struct fl_wld_buffer *buffer;
|
||||
struct xdg_surface *xdg_surface;
|
||||
union {
|
||||
enum Fl_Wayland_Window_Driver::kind kind;
|
||||
union { // for each value of kind
|
||||
struct libdecor_frame *frame;
|
||||
struct wl_subsurface *subsurface;
|
||||
struct xdg_popup *xdg_popup;
|
||||
struct xdg_toplevel *xdg_toplevel;
|
||||
};
|
||||
struct wl_cursor *custom_cursor; // non-null when using custom cursor
|
||||
enum Fl_Wayland_Window_Driver::kind kind;
|
||||
struct custom_cursor {
|
||||
struct wl_cursor *wl_cursor;
|
||||
const Fl_RGB_Image *rgb;
|
||||
int hotx, hoty;
|
||||
} *custom_cursor; // non-null when using custom cursor
|
||||
int configured_width;
|
||||
int configured_height;
|
||||
int floating_width;
|
||||
|
||||
@ -78,9 +78,10 @@ Fl_Wayland_Window_Driver::Fl_Wayland_Window_Driver(Fl_Window *win) : Fl_Window_D
|
||||
subRect_ = NULL;
|
||||
}
|
||||
|
||||
void Fl_Wayland_Window_Driver::delete_cursor_(struct wld_window *xid) {
|
||||
struct wl_cursor *wl_cursor = xid->custom_cursor;
|
||||
if (wl_cursor) {
|
||||
void Fl_Wayland_Window_Driver::delete_cursor_(struct wld_window *xid, bool keep_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];
|
||||
struct fl_wld_buffer *offscreen = (struct fl_wld_buffer *)wl_buffer_get_user_data(new_image->buffer);
|
||||
struct wld_window fake_xid;
|
||||
@ -92,6 +93,8 @@ void Fl_Wayland_Window_Driver::delete_cursor_(struct wld_window *xid) {
|
||||
free(wl_cursor);
|
||||
Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver();
|
||||
if (scr_driver->default_cursor() == wl_cursor) scr_driver->default_cursor(scr_driver->xc_arrow);
|
||||
if (!keep_rgb) delete custom->rgb;
|
||||
delete custom;
|
||||
xid->custom_cursor = NULL;
|
||||
}
|
||||
}
|
||||
@ -637,6 +640,7 @@ static void surface_enter(void *data, struct wl_surface *wl_surface, struct wl_o
|
||||
if (output == NULL)
|
||||
return;
|
||||
|
||||
//printf("surface_enter win=%p wl_output=%p wld_scale=%d\n", window->fl_win, wl_output, output->wld_scale);
|
||||
window->output = output;
|
||||
Fl_Wayland_Window_Driver *win_driver = Fl_Wayland_Window_Driver::driver(window->fl_win);
|
||||
if (!window->fl_win->parent()) { // for top-level, set its screen number
|
||||
@ -652,15 +656,23 @@ 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 {
|
||||
win_driver->is_a_rescale(true);
|
||||
window->fl_win->size(window->fl_win->w(), window->fl_win->h());
|
||||
win_driver->is_a_rescale(false);
|
||||
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)
|
||||
{
|
||||
struct wld_window *window = (struct wld_window*)data;
|
||||
if (! window->wl_surface) return;
|
||||
if (window->output->wl_output == wl_output) {
|
||||
window->output = NULL;
|
||||
}
|
||||
// Do nothing because surface_leave old display arrives **after** surface_enter new display
|
||||
//struct wld_window *window = (struct wld_window*)data;
|
||||
//printf("surface_leave win=%p wl_output=%p\n", window->fl_win, wl_output);
|
||||
}
|
||||
|
||||
static struct wl_surface_listener surface_listener = {
|
||||
@ -1453,6 +1465,21 @@ void Fl_Wayland_Window_Driver::label(const char *name, const char *iname) {
|
||||
|
||||
|
||||
int Fl_Wayland_Window_Driver::set_cursor(const Fl_RGB_Image *rgb, int hotx, int hoty) {
|
||||
return set_cursor_4args(rgb, hotx, hoty, true);
|
||||
}
|
||||
|
||||
|
||||
int Fl_Wayland_Window_Driver::set_cursor_4args(const Fl_RGB_Image *rgb, int hotx, int hoty,
|
||||
bool keep_copy) {
|
||||
if (keep_copy) {
|
||||
int ld = rgb->ld() ? rgb->ld() : rgb->data_w() * rgb->d();
|
||||
uchar *data = new uchar[ld * rgb->data_h()];
|
||||
memcpy(data, rgb->array, ld * rgb->data_h());
|
||||
Fl_RGB_Image *rgb2 = new Fl_RGB_Image(data, rgb->data_w(), rgb->data_h(), rgb->d(), rgb->ld());
|
||||
rgb2->alloc_array = 1;
|
||||
rgb2->scale(rgb->w(), rgb->h());
|
||||
rgb = rgb2;
|
||||
}
|
||||
// build a new wl_cursor and its image
|
||||
struct wld_window *xid = (struct wld_window *)Fl_Window_Driver::xid(pWindow);
|
||||
struct wl_cursor *new_cursor = (struct wl_cursor*)malloc(sizeof(struct wl_cursor));
|
||||
@ -1482,12 +1509,15 @@ int Fl_Wayland_Window_Driver::set_cursor(const Fl_RGB_Image *rgb, int hotx, int
|
||||
Fl_Surface_Device::pop_current();
|
||||
delete img_surf;
|
||||
memcpy(offscreen->data, offscreen->draw_buffer, offscreen->data_size);
|
||||
// delete the previous custom cursor, if there was one
|
||||
delete_cursor_(xid);
|
||||
// delete the previous custom cursor, if there was one, but keep its Fl_RGB_Image
|
||||
delete_cursor_(xid, true);
|
||||
//have this new cursor used
|
||||
xid->custom_cursor = new_cursor;
|
||||
xid->custom_cursor = new struct wld_window::custom_cursor;
|
||||
xid->custom_cursor->wl_cursor = new_cursor;
|
||||
xid->custom_cursor->rgb = rgb;
|
||||
xid->custom_cursor->hotx = hotx;
|
||||
xid->custom_cursor->hoty = hoty;
|
||||
Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver();
|
||||
scr_driver->default_cursor(xid->custom_cursor);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@ -107,6 +107,18 @@ static void fallback_cursor(Fl_Window *w, Fl_Cursor c) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Changes the cursor for this window.
|
||||
|
||||
The window must be show()'n for this function to have any effect.
|
||||
This always calls the system. If you are changing the cursor a lot
|
||||
you may want to keep track of how you set it in a static variable
|
||||
and call this only if the new cursor is different.
|
||||
|
||||
The type Fl_Cursor is an enumeration defined in <FL/Enumerations.H>.
|
||||
|
||||
\see cursor(const Fl_RGB_Image*, int, int), default_cursor()
|
||||
*/
|
||||
void Fl_Window::cursor(Fl_Cursor c) {
|
||||
int ret;
|
||||
|
||||
@ -137,13 +149,17 @@ void Fl_Window::cursor(Fl_Cursor c) {
|
||||
}
|
||||
|
||||
/**
|
||||
Changes the cursor for this window. This always calls the system. If
|
||||
Changes the cursor for this window using the provided image as cursor's shape.
|
||||
The window must be show()'n for this function to have any effect.
|
||||
This always calls the system. If
|
||||
you are changing the cursor a lot you may want to keep track of how
|
||||
you set it in a static variable and call this only if the new cursor
|
||||
is different.
|
||||
|
||||
The default cursor will be used if the provided image cannot be used
|
||||
as a cursor.
|
||||
\param image Sets the cursor size and shape
|
||||
\param hotx,hoty Sets the cursor's active location relatively to top-left of \c image when clicking
|
||||
|
||||
\see cursor(Fl_Cursor), default_cursor()
|
||||
*/
|
||||
|
||||
Loading…
Reference in New Issue
Block a user