diff options
| author | ManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com> | 2025-03-14 12:29:17 +0100 |
|---|---|---|
| committer | ManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com> | 2025-03-14 13:04:31 +0100 |
| commit | 24aec69f27aedeead49ed629b7d434b8846826d3 (patch) | |
| tree | 96dc21c0ecbcc77a6b50fe8983975527d2ccd2e6 /src/drivers | |
| parent | c18c39071a4dc0ace4fc5e23c61f3aa7ddd8c679 (diff) | |
Wayland: simplify handling of tall menu windows
Diffstat (limited to 'src/drivers')
| -rw-r--r-- | src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx | 109 |
1 files changed, 26 insertions, 83 deletions
diff --git a/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx b/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx index c9a0cbbf8..75d3f05b7 100644 --- a/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx +++ b/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx @@ -1347,13 +1347,20 @@ bool Fl_Wayland_Window_Driver::process_menu_or_tooltip(struct wld_window *new_wi xdg_positioner_set_anchor_rect(positioner, popup_x, 0, 1, 1); popup_y++; } - int V, screen_H; - Fl::screen_work_area(V, V, V, screen_H, origin_win->screen_num()); - // Under KWIN, we need to have in screen_H the size of the current screen's work-area. - // We get this exactly only when there's a single screen. Otherwise, we get the screen height. - bool tall_kde = (pWindow->h() > screen_H) && - (Fl_Wayland_Screen_Driver::compositor == Fl_Wayland_Screen_Driver::KWIN); - xdg_positioner_set_size(positioner, pWindow->w() * f , (tall_kde ? screen_H : pWindow->h()) * f ); + int positioner_H = pWindow->h(); + if (Fl_Wayland_Screen_Driver::compositor == Fl_Wayland_Screen_Driver::KWIN) { + // Under KWIN, limiting the height of the positioner to the work area height + // results in tall popup windows starting at the top of the screen, what we want. + // Unfortunately, we know the work area height exactly only for single-screen systems, + // otherwise FLTK returns work area height == screen height. In that case we estimate + // work area height ≈ screen height - 40. + int V, work_area_H, screen_H; + Fl::screen_work_area(V, V, V, work_area_H, origin_win->screen_num()); + Fl::screen_xywh(V, V, V, screen_H, origin_win->screen_num()); + if (work_area_H == screen_H) work_area_H -= 40; + if (positioner_H > work_area_H) positioner_H = work_area_H; + } + xdg_positioner_set_size(positioner, pWindow->w() * f , positioner_H * f ); xdg_positioner_set_anchor(positioner, XDG_POSITIONER_ANCHOR_BOTTOM_LEFT); xdg_positioner_set_gravity(positioner, XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT); // prevent menuwindow from expanding beyond display limits @@ -2012,83 +2019,19 @@ 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::KWIN) { - // The KWin compositor refuses to position a popup such that it extends above - // the top of the screen. That's no longer true with version 6 of KWIN. - // 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); - if (xid->buffer) memset(xid->buffer->draw_buffer.buffer, 0, - xid->buffer->draw_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; - struct xdg_surface *old_xdg = xid_menu->xdg_surface; - struct wl_surface *old_surface = xid_menu->wl_surface; - // menu_origin will be the parent of the processed menu window - Fl_Window *menu_origin = Fl_Window_Driver::menu_title(pWindow); - if (!menu_origin) menu_origin = Fl_Window_Driver::menu_leftorigin(pWindow); - if (!menu_origin) menu_origin = Fl_Window_Driver::menu_parent(); - if (Fl_Window_Driver::menu_title(pWindow) && !Fl_Window_Driver::menu_bartitle(pWindow) && - !Fl_Window_Driver::menu_leftorigin(pWindow)) { - // occurs with tall popup menu - menu_origin = Fl_Window_Driver::menu_parent(); - } - // create a new popup at position (x,y) and display it above the current one - Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); - xid_menu->wl_surface = wl_compositor_create_surface(scr_driver->wl_compositor); - wl_surface_add_listener(xid_menu->wl_surface, &surface_listener, xid_menu); - xid_menu->xdg_surface = xdg_wm_base_get_xdg_surface(scr_driver->xdg_wm_base, - xid_menu->wl_surface); - xdg_surface_add_listener(xid_menu->xdg_surface, &xdg_surface_listener, xid_menu); - struct xdg_positioner *positioner = xdg_wm_base_create_positioner(scr_driver->xdg_wm_base); - struct wld_window * parent_xid = fl_wl_xid(menu_origin); - float f = Fl::screen_scale(Fl_Window_Driver::menu_parent()->screen_num()); - int popup_x = x * f, popup_y = y * f + xid_menu->state; - if (menu_origin->menu_window() && driver(menu_origin)->popup_window()) { - popup_x -= menu_origin->x() * f; - popup_y -= menu_origin->y() * f; - } - if (popup_x >= menu_origin->w() * f) popup_x = menu_origin->w() * f - 1; - if (parent_xid->kind == DECORATED) { - libdecor_frame_translate_coordinate(parent_xid->frame, popup_x, popup_y, - &popup_x, &popup_y); - } - xdg_positioner_set_anchor_rect(positioner, popup_x, 0, 1, 1); - 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); - xdg_positioner_set_constraint_adjustment(positioner, - XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X); - xdg_positioner_set_offset(positioner, 0, popup_y); - xid_menu->xdg_popup = xdg_surface_get_popup(xid_menu->xdg_surface, parent_xid->xdg_surface, - positioner); - xdg_positioner_destroy(positioner); - struct win_positioner *win_pos = new struct win_positioner; - win_pos->window = xid_menu; - win_pos->x = popup_x; - win_pos->y = popup_y; - win_pos->child_popup = NULL; - xdg_popup_add_listener(xid_menu->xdg_popup, &popup_listener, win_pos); - wl_surface_commit(xid_menu->wl_surface); - wl_display_roundtrip(Fl_Wayland_Screen_Driver::wl_display); // necessary with sway - // delete the previous popup - struct win_positioner *old_win_pos = - (struct win_positioner*)xdg_popup_get_user_data(old_popup); - xdg_popup_destroy(old_popup); - delete old_win_pos; - xdg_surface_destroy(old_xdg); - destroy_surface_caution_pointer_focus(old_surface, scr_driver->seat); + // The top of the tall popup window was positioned at the top of the screen + // Instead of sliding up the popup window on the display, we slide up 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); + if (xid->buffer) memset(xid->buffer->draw_buffer.buffer, 0, + xid->buffer->draw_buffer.data_size); + //printf("offset_y=%d\n", *Fl_Window_Driver::menu_offset_y(pWindow)); this->y(y); + pWindow->redraw(); } |
