summaryrefslogtreecommitdiff
path: root/src/drivers/Wayland
diff options
context:
space:
mode:
authorManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com>2022-12-27 13:15:31 +0100
committerManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com>2022-12-27 13:15:31 +0100
commite73b2da5e441f8d9f56ee7c1a9e9cbda269653bf (patch)
tree9636e267d8895b100d1e229b47eaa85db64c2010 /src/drivers/Wayland
parent694df9d7e656c4638430c76c83aa4c81b03ae1bb (diff)
Wayland: Dropdown menu moves when navigated (#613) - cont'd
Menu windows containing sub-menus are now processed differently.
Diffstat (limited to 'src/drivers/Wayland')
-rw-r--r--src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx53
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();