diff options
| author | ManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com> | 2023-05-15 12:40:24 +0200 |
|---|---|---|
| committer | ManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com> | 2023-05-15 12:40:24 +0200 |
| commit | e5ac5678dc4a4d22ad9ca1e088c656c4e5f9b1e9 (patch) | |
| tree | 5fde93420231fd00d905fbbf179a972d62a26b3a /src | |
| parent | 1555132df1be1632d904b75792aa76d962c5401f (diff) | |
Fix handling of tall menu windows with the KDE Wayland compositor
Unfortunately (sigh), the KDE Wayland compositor does not seem to support
correctly, that is, as described by the Wayland protocol, popup windows
that are taller than the display : there is no means to make it draw such popup
so that part of it is above the screen top, whereas the 3 other tested compositors
(Mutter, Weston, Sway) don't have this problem.
This commit implements a new approach to draw tall menu windows, and uses
it only with the KDE compositor : instead of asking the compositor to slide the
menu window up, the menu window remains at a fixed position and the graphics
inside the window is slided up.
This requires to add a member variable, int offset_y, to class menuwindow, that
gets used only for the Wayland platform and that contains the vertical offset by which
graphics to the menu window is moved, expressed in FLTK units. An accessor
to the address of this member variable is added to class Fl_Window_Driver.
Diffstat (limited to 'src')
| -rw-r--r-- | src/Fl_Menu.cxx | 8 | ||||
| -rw-r--r-- | src/Fl_Window_Driver.H | 1 | ||||
| -rw-r--r-- | src/drivers/Wayland/Fl_Wayland_Screen_Driver.cxx | 2 | ||||
| -rw-r--r-- | src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx | 19 |
4 files changed, 30 insertions, 0 deletions
diff --git a/src/Fl_Menu.cxx b/src/Fl_Menu.cxx index d67b116d0..f3400bd9a 100644 --- a/src/Fl_Menu.cxx +++ b/src/Fl_Menu.cxx @@ -163,6 +163,7 @@ public: menuwindow* as_menuwindow() FL_OVERRIDE { return this; } int menubartitle; menuwindow *origin; + int offset_y; }; Fl_Window *menuwindow::parent_ = NULL; @@ -224,6 +225,12 @@ int Fl_Window_Driver::menu_selected(Fl_Window *win) { return (mwin ? mwin->selected : -1); } +/** Accessor to the address of the offset_y member variable of class menuwindow */ +int *Fl_Window_Driver::menu_offset_y(Fl_Window *win) { + menuwindow *mwin = to_menuwindow(win); + return (mwin ? &(mwin->offset_y) : NULL); +} + /** Returns whether win is a non-menubar menutitle */ bool Fl_Window_Driver::is_floating_title(Fl_Window *win) { if (!win->menu_window()) return false; @@ -371,6 +378,7 @@ menuwindow::menuwindow(const Fl_Menu_Item* m, int X, int Y, int Wp, int Hp, int tx = X, ty = Y; menubartitle = menubar_title; origin = NULL; + offset_y = 0; Fl_Window_Driver::driver(this)->menu_window_area(scr_x, scr_y, scr_w, scr_h); if (!right_edge || right_edge > scr_x+scr_w) right_edge = scr_x+scr_w; diff --git a/src/Fl_Window_Driver.H b/src/Fl_Window_Driver.H index 0149d28b0..9d7588d9d 100644 --- a/src/Fl_Window_Driver.H +++ b/src/Fl_Window_Driver.H @@ -200,6 +200,7 @@ public: static int menu_itemheight(Fl_Window*); static int menu_bartitle(Fl_Window*); static int menu_selected(Fl_Window*); + static int *menu_offset_y(Fl_Window*); static bool is_floating_title(Fl_Window *); static void scroll_to_selected_item(Fl_Window *); static bool is_menutitle(Fl_Window *); diff --git a/src/drivers/Wayland/Fl_Wayland_Screen_Driver.cxx b/src/drivers/Wayland/Fl_Wayland_Screen_Driver.cxx index a95cce8fe..2a379d57a 100644 --- a/src/drivers/Wayland/Fl_Wayland_Screen_Driver.cxx +++ b/src/drivers/Wayland/Fl_Wayland_Screen_Driver.cxx @@ -219,6 +219,8 @@ static Fl_Window *event_coords_from_surface(struct wl_surface *surface, Fl::e_x = wl_fixed_to_int(surface_x) / f + delta_x; Fl::e_x_root = Fl::e_x + win->x(); Fl::e_y = wl_fixed_to_int(surface_y) / f + delta_y; + int *poffset = Fl_Window_Driver::menu_offset_y(win); + if (poffset) Fl::e_y -= *poffset; Fl::e_y_root = Fl::e_y + win->y(); return win; } diff --git a/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx b/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx index 7ea0b948f..b4a5f6ebc 100644 --- a/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx +++ b/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx @@ -356,6 +356,10 @@ void Fl_Wayland_Window_Driver::make_current() { &window->buffer->draw_buffer_needs_commit); } ((Fl_Wayland_Graphics_Driver*)fl_graphics_driver)->set_buffer(window->buffer, f * wld_s); + int *poffset = Fl_Window_Driver::menu_offset_y(pWindow); + if (poffset) { // for tall menu windows under KDE to offset drawing inside window + cairo_translate(window->buffer->cairo_, 0, *poffset); + } cairo_rectangle_int_t *extents = subRect(); if (extents) { // make damage-to-buffer not to leak outside parent Fl_Region clip_region = fl_graphics_driver->XRectangleRegion(extents->x, extents->y, @@ -1741,6 +1745,21 @@ void Fl_Wayland_Window_Driver::subRect(cairo_rectangle_int_t *r) { void Fl_Wayland_Window_Driver::reposition_menu_window(int x, int y) { if (y == pWindow->y()) return; + if (Fl_Wayland_Screen_Driver::compositor == Fl_Wayland_Screen_Driver::KDE) { + // The KDE compositor refuses to position a popup such that it extends above + // the top of the screen. Therefore, instead of sliding the popup window + // on the display, we slide the drawing inside the fixed popup via + // member variable offset_y of the menuwindow class, and we redraw the popup + // content. It's also useful to make such tall popup window transparent. + *Fl_Window_Driver::menu_offset_y(pWindow) += (y - pWindow->y()); + struct wld_window *xid = fl_wl_xid(pWindow); + wl_surface_set_opaque_region(xid->wl_surface, NULL); + memset(xid->buffer->draw_buffer, 0, xid->buffer->data_size); + //printf("offset_y=%d\n", *Fl_Window_Driver::menu_offset_y(pWindow)); + this->y(y); + pWindow->redraw(); + return; + } struct wld_window * xid_menu = fl_wl_xid(pWindow); //printf("reposition %dx%d[cur=%d] menu->state=%d\n", x, y, pWindow->y(), xid_menu->state); struct xdg_popup *old_popup = xid_menu->xdg_popup; |
