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.
This commit is contained in:
parent
1555132df1
commit
e5ac5678dc
@ -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;
|
||||
|
@ -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 *);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user