summaryrefslogtreecommitdiff
path: root/src/drivers
diff options
context:
space:
mode:
authorManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com>2023-06-19 17:48:37 +0200
committerManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com>2023-06-19 17:48:37 +0200
commitc43cf2f19243057fe8b02410bb11669a720e2ca8 (patch)
tree2e23d30eabb3168e0c01f5c1cff86bd7416c089c /src/drivers
parent742af8a31a8627bdfc1ed4d14cdc73c396c015f6 (diff)
Wayland: improve support of multi-display setups
Diffstat (limited to 'src/drivers')
-rw-r--r--src/drivers/Wayland/Fl_Wayland_Copy_Surface_Driver.cxx9
-rw-r--r--src/drivers/Wayland/Fl_Wayland_Screen_Driver.cxx10
-rw-r--r--src/drivers/Wayland/Fl_Wayland_Window_Driver.H6
-rw-r--r--src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx107
4 files changed, 91 insertions, 41 deletions
diff --git a/src/drivers/Wayland/Fl_Wayland_Copy_Surface_Driver.cxx b/src/drivers/Wayland/Fl_Wayland_Copy_Surface_Driver.cxx
index c3d8a977c..b1c34b2ec 100644
--- a/src/drivers/Wayland/Fl_Wayland_Copy_Surface_Driver.cxx
+++ b/src/drivers/Wayland/Fl_Wayland_Copy_Surface_Driver.cxx
@@ -22,9 +22,12 @@
Fl_Wayland_Copy_Surface_Driver::Fl_Wayland_Copy_Surface_Driver(int w, int h) : Fl_Copy_Surface_Driver(w, h) {
- int os_scale =
- (Fl_Wayland_Window_Driver::wld_window && Fl_Wayland_Window_Driver::wld_window->output ?
- Fl_Wayland_Window_Driver::wld_window->output->wld_scale : 1);
+ struct Fl_Wayland_Window_Driver::surface_output *s_output = NULL;
+ if (Fl_Wayland_Window_Driver::wld_window &&
+ !wl_list_empty(&Fl_Wayland_Window_Driver::wld_window->outputs)) {
+ s_output = wl_container_of(Fl_Wayland_Window_Driver::wld_window->outputs.next, s_output, link);
+ }
+ int os_scale = (s_output ? s_output->output->wld_scale : 1);
img_surf = new Fl_Image_Surface(w * os_scale, h * os_scale);
driver(img_surf->driver());
driver()->scale(os_scale);
diff --git a/src/drivers/Wayland/Fl_Wayland_Screen_Driver.cxx b/src/drivers/Wayland/Fl_Wayland_Screen_Driver.cxx
index 653fc646d..cac300567 100644
--- a/src/drivers/Wayland/Fl_Wayland_Screen_Driver.cxx
+++ b/src/drivers/Wayland/Fl_Wayland_Screen_Driver.cxx
@@ -996,7 +996,10 @@ static void output_scale(void *data, struct wl_output *wl_output, int32_t factor
Fl_Window *win = Fl::first_window();
while (win) {
struct wld_window *xid = fl_wl_xid(win);
- if (xid->custom_cursor && output == xid->output) {
+ struct Fl_Wayland_Window_Driver::surface_output *s_output;
+ // get 1st screen where window appears
+ s_output = wl_container_of(xid->outputs.next, s_output, link);
+ if (xid->custom_cursor && output == s_output->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);
@@ -1131,10 +1134,13 @@ static void registry_handle_global_remove(void *data, struct wl_registry *regist
Fl_X *xp = Fl_X::first;
while (xp) { // all mapped windows
struct wld_window *win = (struct wld_window*)xp->xid;
- if (win->output == output) {
+ struct Fl_Wayland_Window_Driver::surface_output *s_output;
+ wl_list_for_each(s_output, &win->outputs, link) {
+ if (output == s_output->output) {
delete win->fl_win;
goto again;
}
+ }
xp = xp->next;
}
wl_list_remove(&output->link);
diff --git a/src/drivers/Wayland/Fl_Wayland_Window_Driver.H b/src/drivers/Wayland/Fl_Wayland_Window_Driver.H
index ebcdfea5f..985d7bfe2 100644
--- a/src/drivers/Wayland/Fl_Wayland_Window_Driver.H
+++ b/src/drivers/Wayland/Fl_Wayland_Window_Driver.H
@@ -68,6 +68,10 @@ public:
int screen;
bool busy;
};
+ struct surface_output { // for linked list of displays where a surface maps
+ struct Fl_Wayland_Screen_Driver::output *output;
+ struct wl_list link;
+ };
static type_for_resize_window_between_screens data_for_resize_window_between_screens_;
void decorated_win_size(int &w, int &h);
void shape_bitmap_(Fl_Image* b);
@@ -131,7 +135,7 @@ public:
struct wld_window {
Fl_Window *fl_win;
- struct Fl_Wayland_Screen_Driver::output *output; // the display where win is mapped
+ 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 xdg_surface *xdg_surface;
diff --git a/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx b/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx
index eec088e6c..97b8f5252 100644
--- a/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx
+++ b/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx
@@ -117,10 +117,6 @@ void Fl_Wayland_Window_Driver::decorated_win_size(int &w, int &h)
Fl_Window *win = pWindow;
w = win->w();
h = win->h();
- // needed until libdecor_plugin_fallback_frame_get_border_size() is corrected upstream
- if (((Fl_Wayland_Screen_Driver*)Fl::screen_driver())->compositor ==
- Fl_Wayland_Screen_Driver::OWL) return;
-
if (!win->shown() || win->parent() || !win->border() || !win->visible()) return;
int X, titlebar_height;
libdecor_frame_translate_coordinate(fl_wl_xid(win)->frame, 0, 0, &X, &titlebar_height);
@@ -475,7 +471,12 @@ void Fl_Wayland_Window_Driver::hide() {
wld_win->wl_surface = NULL;
}
if (wld_win->custom_cursor) delete_cursor_(wld_win);
- wld_win->output = NULL;
+ while (!wl_list_empty(&wld_win->outputs)) { // remove from screens where it belongs
+ struct surface_output *s_output;
+ s_output = wl_container_of(wld_win->outputs.next, s_output, link);
+ wl_list_remove(&s_output->link);
+ free(s_output);
+ }
if (Fl_Wayland_Window_Driver::wld_window == wld_win) Fl_Wayland_Window_Driver::wld_window = NULL;
//fprintf(stderr, "After hide: sub=%p frame=%p xdg=%p top=%p pop=%p surf=%p\n", wld_win->subsurface, wld_win->frame, wld_win->xdg_surface, wld_win->xdg_toplevel, wld_win->xdg_popup, wld_win->wl_surface);
free(wld_win);
@@ -638,37 +639,25 @@ static void delayed_redraw(Fl_Window *win) {
}
-static void surface_enter(void *data, struct wl_surface *wl_surface, struct wl_output *wl_output)
-{
- struct wld_window *window = (struct wld_window*)data;
-
- if (!Fl_Wayland_Screen_Driver::own_output(wl_output))
- return;
-
- Fl_Wayland_Screen_Driver::output *output = (Fl_Wayland_Screen_Driver::output*)wl_output_get_user_data(wl_output);
- if (output == NULL)
- return;
-
-//printf("surface_enter win=%p wl_output=%p wld_scale=%d\n", window->fl_win, wl_output, output->wld_scale);
+void change_scale(Fl_Wayland_Screen_Driver::output *output, struct wld_window *window,
+ float pre_scale) {
Fl_Wayland_Window_Driver *win_driver = Fl_Wayland_Window_Driver::driver(window->fl_win);
- float pre_scale = Fl::screen_scale(win_driver->screen_num()) * win_driver->wld_scale();
- window->output = output;
- if (!window->fl_win->parent()) { // for top-level, set its screen number
+ if (!window->fl_win->parent()) {
+ // for top-level, set its screen number when the 1st screen for this surface changes
Fl_Wayland_Screen_Driver::output *running_output;
Fl_Wayland_Screen_Driver *scr_dr = (Fl_Wayland_Screen_Driver*)Fl::screen_driver();
int i = 0;
wl_list_for_each(running_output, &scr_dr->outputs, link) { // each screen of the system
if (running_output == output) { // we've found our screen of the system
win_driver->screen_num(i);
-//fprintf(stderr,"window %p is on screen #%d\n", window->fl_win, i);
break;
}
i++;
}
}
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) {
+//printf("pre_scale=%.1f post_scale=%.1f\n", pre_scale, post_scale);
+ if (post_scale != pre_scale) {
if (window->kind == Fl_Wayland_Window_Driver::POPUP) {
Fl_Wayland_Graphics_Driver::buffer_release(window);
window->fl_win->redraw();
@@ -682,23 +671,67 @@ static void surface_enter(void *data, struct wl_surface *wl_surface, struct wl_o
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);
}
-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
- //struct wld_window *window = (struct wld_window*)data;
- //printf("surface_leave win=%p wl_output=%p\n", window->fl_win, wl_output);
+static void surface_enter(void *data, struct wl_surface *wl_surface,
+ struct wl_output *wl_output) {
+ struct wld_window *window = (struct wld_window*)data;
+
+ if (!Fl_Wayland_Screen_Driver::own_output(wl_output))
+ return;
+
+ Fl_Wayland_Screen_Driver::output *output = (Fl_Wayland_Screen_Driver::output*)wl_output_get_user_data(wl_output);
+ if (output == NULL)
+ return;
+
+ Fl_Wayland_Window_Driver *win_driver = Fl_Wayland_Window_Driver::driver(window->fl_win);
+ float pre_scale = Fl::screen_scale(win_driver->screen_num()) * win_driver->wld_scale();
+ bool list_was_empty = wl_list_empty(&window->outputs);
+ struct Fl_Wayland_Window_Driver::surface_output *surface_output =
+ (struct Fl_Wayland_Window_Driver::surface_output*)malloc(
+ sizeof(struct Fl_Wayland_Window_Driver::surface_output));
+ surface_output->output = output;
+ // add to end of the linked list of displays of this surface
+ struct wl_list *e = &window->outputs;
+ while (e->next != &window->outputs) e = e->next; // move e to end of linked list
+ wl_list_insert(e, &surface_output->link);
+//printf("window %p enters screen id=%d length=%d\n", window->fl_win, output->id, wl_list_length(&window->outputs));
+ if (list_was_empty) {
+ change_scale(output, window, pre_scale);
+ }
}
+
+static void surface_leave(void *data, struct wl_surface *wl_surface,
+ struct wl_output *wl_output) {
+ if (!Fl_Wayland_Screen_Driver::own_output(wl_output))
+ return;
+ struct wld_window *window = (struct wld_window*)data;
+ Fl_Wayland_Screen_Driver::output *output = (Fl_Wayland_Screen_Driver::output*)wl_output_get_user_data(wl_output);
+ Fl_Wayland_Window_Driver *win_driver = Fl_Wayland_Window_Driver::driver(window->fl_win);
+ float pre_scale = Fl::screen_scale(win_driver->screen_num()) * win_driver->wld_scale();
+ struct Fl_Wayland_Window_Driver::surface_output *s_output;
+ int count = 0;
+ wl_list_for_each(s_output, &window->outputs, link) {
+ count++;
+ if (s_output->output == output) {
+ wl_list_remove(&s_output->link);
+ free(s_output);
+//printf("window %p leaves screen id=%d length=%d\n", window->fl_win, output->id, wl_list_length(&window->outputs));
+ break;
+ }
+ }
+ if (count == 1 && !wl_list_empty(&window->outputs)) {
+ s_output = wl_container_of(window->outputs.next, s_output, link);
+ change_scale(s_output->output, window, pre_scale);
+ }
+}
+
+
static struct wl_surface_listener surface_listener = {
surface_enter,
surface_leave,
@@ -1189,6 +1222,7 @@ void Fl_Wayland_Window_Driver::makeWindow()
new_window = (struct wld_window *)calloc(1, sizeof *new_window);
new_window->fl_win = pWindow;
+ wl_list_init(&new_window->outputs);
Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver();
new_window->wl_surface = wl_compositor_create_surface(scr_driver->wl_compositor);
@@ -1612,6 +1646,7 @@ void Fl_Wayland_Window_Driver::resize(int X, int Y, int W, int H) {
if (fl_win && fl_win->kind == DECORATED && !xdg_toplevel()) {
pWindow->wait_for_expose();
}
+ if (!pWindow->parent()) X = Y = 0; // toplevel windows must have origin at 0,0
int is_a_move = (X != x() || Y != y());
bool true_rescale = Fl_Window::is_a_rescale();
if (fl_win && fl_win->buffer) {
@@ -1865,16 +1900,18 @@ void Fl_Wayland_Window_Driver::menu_window_area(int &X, int &Y, int &W, int &H,
int Fl_Wayland_Window_Driver::wld_scale() {
struct wld_window *xid = (struct wld_window *)Fl_X::flx(pWindow)->xid;
- if (!xid->output) {
- Fl_Wayland_Screen_Driver::output *output;
+ if (wl_list_empty(&xid->outputs)) {
int scale = 1;
Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver();
+ Fl_Wayland_Screen_Driver::output *output;
wl_list_for_each(output, &(scr_driver->outputs), link) {
scale = fl_max(scale, output->wld_scale);
}
return scale;
}
- return xid->output->wld_scale;
+ struct surface_output *s_output;
+ s_output = wl_container_of(xid->outputs.next, s_output, link);
+ return s_output->output->wld_scale;
}