summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com>2025-03-11 17:35:29 +0100
committerManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com>2025-03-11 23:47:39 +0100
commit9b5d40ad973395ceed431abd2e6165ec5ffd70bd (patch)
treee1dbfe210fc6ab9176ae7954660fb13d80aa75ed /src
parent1054e81504dc2fe45086e534c2986921f1bf861d (diff)
Fix "Wayland: Huge menu hiding unexpectedly when moving a mouse (#1115)
This commit also computes work-area size for single-display settings.
Diffstat (limited to 'src')
-rw-r--r--src/drivers/Wayland/Fl_Wayland_Screen_Driver.H6
-rw-r--r--src/drivers/Wayland/Fl_Wayland_Screen_Driver.cxx103
-rw-r--r--src/screen_xywh.cxx5
3 files changed, 102 insertions, 12 deletions
diff --git a/src/drivers/Wayland/Fl_Wayland_Screen_Driver.H b/src/drivers/Wayland/Fl_Wayland_Screen_Driver.H
index 9a4f9a895..16eb750a4 100644
--- a/src/drivers/Wayland/Fl_Wayland_Screen_Driver.H
+++ b/src/drivers/Wayland/Fl_Wayland_Screen_Driver.H
@@ -67,8 +67,10 @@ public:
struct output { // one record for each screen
uint32_t id;
int x, y; // logical position of screen
- int width; // in pixels
- int height; // in pixels
+ int pixel_width; // in pixels
+ int pixel_height; // in pixels
+ int width; // in pixels, account for fractional scaling
+ int height; // in pixels, account for fractional scaling
float dpi;
struct wl_output *wl_output;
int wld_scale; // Wayland scale factor
diff --git a/src/drivers/Wayland/Fl_Wayland_Screen_Driver.cxx b/src/drivers/Wayland/Fl_Wayland_Screen_Driver.cxx
index 50329d17b..84e3d59e7 100644
--- a/src/drivers/Wayland/Fl_Wayland_Screen_Driver.cxx
+++ b/src/drivers/Wayland/Fl_Wayland_Screen_Driver.cxx
@@ -1106,8 +1106,8 @@ static void output_mode(void *data, struct wl_output *wl_output, uint32_t flags,
int32_t width, int32_t height, int32_t refresh)
{
Fl_Wayland_Screen_Driver::output *output = (Fl_Wayland_Screen_Driver::output*)data;
- output->width = int(width);
- output->height = int(height);
+ output->pixel_width = int(width);
+ output->pixel_height = int(height);
//fprintf(stderr, "output_mode: [%p]=%dx%d\n",output->wl_output,width,height);
}
@@ -1531,18 +1531,107 @@ void Fl_Wayland_Screen_Driver::close_display() {
}
+struct pair_s { int W, H; };
+static void xdg_toplevel_configure(void *data, struct xdg_toplevel *xdg_toplevel,
+ int32_t width, int32_t height, struct wl_array *states)
+{
+ struct pair_s *pair = (struct pair_s*)data;
+ pair->W = width;
+ pair->H = height;
+}
+
+static void xdg_toplevel_close(void *data, struct xdg_toplevel *toplevel) {}
+
+static const struct xdg_toplevel_listener xdg_toplevel_listener = {
+ .configure = xdg_toplevel_configure,
+ .close = xdg_toplevel_close,
+};
+
+
+static void compute_full_and_maximized_areas(Fl_Wayland_Screen_Driver::output *output,
+ int& Wfullscreen, int& Hfullscreen,
+ int& Wworkarea, int& Hworkarea,
+ bool need_workarea) {
+ Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver();
+ struct wl_surface *wl_surface = wl_compositor_create_surface(scr_driver->wl_compositor);
+ wl_surface_set_opaque_region(wl_surface, NULL);
+ struct xdg_surface *xdg_surface = xdg_wm_base_get_xdg_surface(scr_driver->xdg_wm_base, wl_surface);
+ struct xdg_toplevel *xdg_toplevel = xdg_surface_get_toplevel(xdg_surface);
+ struct pair_s pair = {0, 0};
+ xdg_toplevel_add_listener(xdg_toplevel, &xdg_toplevel_listener, &pair);
+ xdg_toplevel_set_fullscreen(xdg_toplevel, output->wl_output);
+ wl_surface_commit(wl_surface);
+ while (!pair.H) wl_display_dispatch(Fl_Wayland_Screen_Driver::wl_display);
+ Wfullscreen = pair.W;
+ Hfullscreen = pair.H;
+ if (need_workarea) {
+ xdg_toplevel_unset_fullscreen(xdg_toplevel);
+ xdg_toplevel_set_maximized(xdg_toplevel);
+ pair.H = 0;
+ wl_surface_commit(wl_surface);
+ while (!pair.H) wl_display_dispatch(Fl_Wayland_Screen_Driver::wl_display);
+ }
+ Wworkarea = pair.W;
+ Hworkarea = pair.H;
+ xdg_toplevel_destroy(xdg_toplevel);
+ xdg_surface_destroy(xdg_surface);
+ wl_surface_destroy(wl_surface);
+ //int H = output->pixel_height / output->wld_scale;
+ //float fractional_scale = Hfullscreen / float(H);
+ //printf("fullscreen=%dx%d workarea=%dx%d apparentH=%d fractional_scale=%g wld_s=%d\n",
+ // Wfullscreen,Hfullscreen,Wworkarea,Hworkarea,H,fractional_scale,output->wld_scale);
+}
+
static int workarea_xywh[4] = { -1, -1, -1, -1 };
+/* Implementation note about computing work area and about handling fractional scaling.
+
+ FLTK computes 2 pairs of (WxH) values for each display:
+ 1) (pixel_width x pixel_height) gives the size in pixel of a display. It's unchanged by
+ any scaling applied by the compositor; it's assigned by function output_mode().
+ 2) (width x height) gives the size in pixels of a buffer that would fully cover the display.
+ When the active scaling is non-fractional, these equations hold:
+ pixel_width = width = wld_scale * configured-width-of-fullscreen-window
+ pixel_height = height = wld_scale * configured-height-of-fullscreen-window
+
+ When fractional scaling is active, buffers received from client are scaled down
+ by the compositor and mapped to screen. These equations hold:
+ pixel_width < width = wld_scale * configured-width-of-fullscreen-window
+ pixel_height < height = wld_scale * configured-height-of-fullscreen-window
+
+ One way for a client to discover that fractional scaling is active on a given display
+ is to ask for a fullscreen window on that display, get its configured size and compare
+ it to the display pixel size. That's what function compute_full_and_maximized_areas() does.
+
+ One way for a client to discover the work area size is to get the configured size
+ of a maximized window on a given display. But it's not possible to control on what display
+ the compositor puts the maximized window. Therefore, FLTK computes an exact work area size
+ only when the system contains a single display. That's also done by function
+ compute_full_and_maximized_areas().
+
+ FLTK didn't find how to recognize the primary display within the list of displays
+ received from the compositor. That's another reason why FLTK doesn't attempt
+ to compute work area sizes when there are multiple displays.
+ */
+
void Fl_Wayland_Screen_Driver::init_workarea()
{
Fl_Wayland_Screen_Driver::output *output;
+ int count = 0;
+ wl_list_for_each(output, &outputs, link) ++count;
+ bool need_workarea = (count == 1);
+ bool first = true;
wl_list_for_each(output, &outputs, link) {
- workarea_xywh[0] = output->x; // pixels
- workarea_xywh[1] = output->y; // pixels
- workarea_xywh[2] = output->width; // pixels
- workarea_xywh[3] = output->height; // pixels
- break;
+ if (first) workarea_xywh[0] = output->x; // pixels
+ if (first) workarea_xywh[1] = output->y; // pixels
+ int Wfullscreen, Hfullscreen, Wworkarea, Hworkarea;
+ compute_full_and_maximized_areas(output, Wfullscreen, Hfullscreen, Wworkarea, Hworkarea, need_workarea);
+ output->width = Wfullscreen * output->wld_scale; // pixels
+ if (first) workarea_xywh[2] = Wworkarea * output->wld_scale; // pixels
+ output->height = Hfullscreen * output->wld_scale; // pixels
+ if (first) workarea_xywh[3] = Hworkarea * output->wld_scale; // pixels
+ first = false;
}
}
diff --git a/src/screen_xywh.cxx b/src/screen_xywh.cxx
index 2fedf86fa..ab72c1c2a 100644
--- a/src/screen_xywh.cxx
+++ b/src/screen_xywh.cxx
@@ -95,9 +95,8 @@ void Fl::screen_work_area(int &X, int &Y, int &W, int &H, int mx, int my)
\param[out] X,Y,W,H the work area bounding box
\param[in] n the screen number (0 to Fl::screen_count() - 1)
\see void screen_xywh(int &x, int &y, int &w, int &h, int mx, int my)
- \note Under X11, the screen work area is given values that differ from that screen's bounding box
- only if the system contains a single screen. Under Wayland, a screen work area is always
- equal to that screen's bounding box.
+ \note Under X11 and Wayland, the screen work area is given values that differ
+ from that screen's bounding box only if the system contains a single screen.
\note Like all quantities accessible via public APIs of FLTK, values of \p X,Y,W,H
are given in FLTK units, that is, in drawing units divided by the scaling factor of screen \p n.
*/