diff options
| author | ManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com> | 2022-12-27 13:15:31 +0100 |
|---|---|---|
| committer | ManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com> | 2022-12-27 13:15:31 +0100 |
| commit | e73b2da5e441f8d9f56ee7c1a9e9cbda269653bf (patch) | |
| tree | 9636e267d8895b100d1e229b47eaa85db64c2010 /src/drivers | |
| parent | 694df9d7e656c4638430c76c83aa4c81b03ae1bb (diff) | |
Wayland: Dropdown menu moves when navigated (#613) - cont'd
Menu windows containing sub-menus are now processed differently.
Diffstat (limited to 'src/drivers')
| -rw-r--r-- | src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx | 53 |
1 files changed, 46 insertions, 7 deletions
diff --git a/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx b/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx index f5399af0c..fd912b9a0 100644 --- a/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx +++ b/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx @@ -30,6 +30,7 @@ #include <FL/fl_ask.H> #include <FL/Fl.H> #include <FL/Fl_Image_Surface.H> +#include <FL/Fl_Menu_Item.H> #include <string.h> #include <math.h> // for ceil() #include <sys/types.h> // for pid_t @@ -950,6 +951,44 @@ static const char *get_prog_name() { } +/* Implementation note about menu windows under Wayland. + Wayland offers a way to position popup windows such as menu windows using constraints + but hides the position of the window inside the display. Each popup is located relatively + to a parent window which can be a popup itself and MUST overlap or at least touch this parent. + FLTK computes the adequate position of a menu window in the display and then maps it + at that position. + These 2 logics are quite different. + The approach implemented here is two-fold. + 1) If a menu window is not taller than the display and contains no submenu, use Wayland + logic to position it. The benefit is that window menus become authorized to lay outside + the parent window but Wayland will not make them run beyond display limits. + We avoid submenu-containing popups because these could lead to + locate the future submenu outside its parent window, which Wayland forbids. + We avoid very tall menu windows because navigating with FLTK inside them would require to know + what part of them is visible which Wayland hides. + 2) Otherwise, have FLTK compute the menu position under the constraint that its active item + must be inside the menu-containing window. This constraint ensures Wayland will accept this + position because the required overlap is satisfied. + Function use_wayland_menu_positioning() below determines wether 1) or 2) is used for any + window menu. The result of this function is stored in the state member of the menu window's + struct wld_window for fast re-use. + */ + +//returns true if win is a menuwindow without submenu and is not taller than display +static bool use_wayland_menu_positioning(Fl_Window *win, Fl_Window *parent_win) { + if (!win->menu_window()) return true; + int XX, YY, WW, HH; + Fl::screen_xywh(XX, YY, WW, HH, parent_win->screen_num()); + if (win->h() > HH) return false; + const Fl_Menu_Item *m = Fl_Window_Driver::driver(win)->current_menu(); + while (m->label()) { + if (m->flags & (FL_SUBMENU | FL_SUBMENU_POINTER)) return false; + m = m->next(); + } + return true; +} + + Fl_X *Fl_Wayland_Window_Driver::makeWindow() { struct wld_window *new_window; @@ -1005,10 +1044,9 @@ Fl_X *Fl_Wayland_Window_Driver::makeWindow() xdg_positioner_set_size(positioner, pWindow->w() * f , pWindow->h() * f ); xdg_positioner_set_anchor(positioner, XDG_POSITIONER_ANCHOR_TOP_LEFT); xdg_positioner_set_gravity(positioner, XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT); - int XX, YY, WW, HH; - Fl::screen_xywh(XX, YY, WW, HH, parent_win->screen_num()); - if (pWindow->h() <= HH) { - // prevent menuwindow from expanding beyond display bottom + new_window->state = use_wayland_menu_positioning(pWindow, parent_win); + if (new_window->state) { + // prevent menuwindow from expanding beyond display limits xdg_positioner_set_constraint_adjustment(positioner, XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y); } @@ -1557,9 +1595,10 @@ void Fl_Wayland_Window_Driver::reposition_menu_window(int x, int y) { void Fl_Wayland_Window_Driver::menu_window_area(int &X, int &Y, int &W, int &H, int nscreen) { Fl_Window *parent = Fl_Window_Driver::menu_parent(); if (parent) { - int XX,YY,WW,HH; - Fl::screen_xywh(XX, YY, WW, HH, parent->screen_num()); - if (pWindow->h() > HH) { // the menu window is higher than the display + struct wld_window *xid = fl_wl_xid(pWindow); + bool condition = xid ? xid->state : use_wayland_menu_positioning(pWindow, parent); + if (!condition) { + // keep active menu part inside parent window X = parent->x(); Y = parent->y(); W = parent->w(); |
