diff options
| author | ManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com> | 2025-03-11 17:35:29 +0100 |
|---|---|---|
| committer | ManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com> | 2025-03-11 23:47:39 +0100 |
| commit | 9b5d40ad973395ceed431abd2e6165ec5ffd70bd (patch) | |
| tree | e1dbfe210fc6ab9176ae7954660fb13d80aa75ed /src/drivers/Wayland | |
| parent | 1054e81504dc2fe45086e534c2986921f1bf861d (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/drivers/Wayland')
| -rw-r--r-- | src/drivers/Wayland/Fl_Wayland_Screen_Driver.H | 6 | ||||
| -rw-r--r-- | src/drivers/Wayland/Fl_Wayland_Screen_Driver.cxx | 103 |
2 files changed, 100 insertions, 9 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; } } |
