summaryrefslogtreecommitdiff
path: root/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx
diff options
context:
space:
mode:
authormaxim nikonov <maxim.nikonov@hqo.co>2026-02-05 15:21:34 +0500
committermaxim nikonov <maxim.nikonov@hqo.co>2026-02-05 15:21:34 +0500
commitdb214d1145e46d527a46d1fc2519548d2c4d23f1 (patch)
treecf0fd9922e4d54f6beb63888f9b28c8e2a787bdf /src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx
parent75fc94d6c71fe686f6dde5b41ad91cba2f6bdd6f (diff)
wip: fork
Diffstat (limited to 'src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx')
-rw-r--r--src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx2191
1 files changed, 0 insertions, 2191 deletions
diff --git a/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx b/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx
deleted file mode 100644
index 0495fb7bc..000000000
--- a/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx
+++ /dev/null
@@ -1,2191 +0,0 @@
-//
-// Implementation of the Wayland window driver.
-//
-// Copyright 1998-2026 by Bill Spitzak and others.
-//
-// This library is free software. Distribution and use rights are outlined in
-// the file "COPYING" which should have been included with this file. If this
-// file is missing or damaged, see the license at:
-//
-// https://www.fltk.org/COPYING.php
-//
-// Please see the following page on how to report bugs and issues:
-//
-// https://www.fltk.org/bugs.php
-//
-
-#include <FL/platform.H>
-#include "Fl_Wayland_Window_Driver.H"
-#include "Fl_Wayland_Screen_Driver.H"
-#include "Fl_Wayland_Graphics_Driver.H"
-#include <FL/filename.H>
-#include <wayland-cursor.h>
-#include "../../../libdecor/build/fl_libdecor.h"
-#include "xdg-shell-client-protocol.h"
-#include "gtk-shell-client-protocol.h"
-#if HAVE_XDG_DIALOG
-# include "xdg-dialog-client-protocol.h"
-#endif
-#include <pango/pangocairo.h>
-#include <FL/Fl_Overlay_Window.H>
-#include <FL/Fl_Tooltip.H>
-#include <FL/fl_draw.H>
-#include <FL/fl_ask.H>
-#include <FL/Fl.H>
-#include <FL/Fl_Image_Surface.H>
-#include <FL/Fl_Menu_Button.H>
-#include <string.h>
-#include <math.h> // for ceil()
-#include <sys/types.h> // for pid_t
-#include <unistd.h> // for getpid()
-
-struct cursor_image { // as in wayland-cursor.c of the Wayland project source code
- struct wl_cursor_image image;
- struct wl_cursor_theme *theme;
- struct wl_buffer *buffer;
- int offset; /* data offset of this image in the shm pool */
-};
-
-extern "C" {
-# include "../../../libdecor/src/libdecor-plugin.h"
- uchar *fl_libdecor_titlebar_buffer(struct libdecor_frame *frame, int *w, int *h, int *stride);
-}
-
-#define fl_max(a,b) ((a) > (b) ? (a) : (b))
-#define fl_min(a,b) ((a) < (b) ? (a) : (b))
-
-#if !defined(FLTK_USE_X11)
-Window fl_window = 0;
-#endif
-
-
-struct wld_window *Fl_Wayland_Window_Driver::wld_window = NULL;
-bool Fl_Wayland_Window_Driver::new_popup = false; // to support tall menu buttons
-// A menutitle to be mapped later as the child of a menuwindow
-Fl_Window *Fl_Wayland_Window_Driver::previous_floatingtitle = NULL;
-
-
-Fl_Wayland_Window_Driver::Fl_Wayland_Window_Driver(Fl_Window *win) : Fl_Window_Driver(win)
-{
- shape_data_ = NULL;
- standard_cursor_ = FL_CURSOR_DEFAULT;
- in_handle_configure = false;
- screen_num_ = -1;
- gl_start_support_ = NULL;
- subRect_ = NULL;
- is_popup_window_ = false;
- can_expand_outside_parent_ = false;
-}
-
-
-void Fl_Wayland_Window_Driver::delete_cursor(
- struct Fl_Wayland_Window_Driver::custom_cursor *custom, bool delete_rgb) {
- struct wl_cursor *wl_cursor = custom->wl_cursor;
- struct cursor_image *new_image = (struct cursor_image*)wl_cursor->images[0];
- struct Fl_Wayland_Graphics_Driver::wld_buffer *offscreen =
- (struct Fl_Wayland_Graphics_Driver::wld_buffer *)
- wl_buffer_get_user_data(new_image->buffer);
- struct wld_window fake_xid;
- memset(&fake_xid, 0, sizeof(fake_xid));
- fake_xid.buffer = offscreen;
- Fl_Wayland_Graphics_Driver::buffer_release(&fake_xid);
- free(new_image);
- free(wl_cursor->images);
- free(wl_cursor->name);
- free(wl_cursor);
- Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver();
- if (scr_driver->default_cursor() == wl_cursor) {
- scr_driver->default_cursor(scr_driver->xc_cursor[Fl_Wayland_Screen_Driver::arrow]);
- }
- if (delete_rgb) delete custom->rgb;
- delete custom;
-}
-
-
-Fl_Wayland_Window_Driver::~Fl_Wayland_Window_Driver()
-{
- if (shape_data_) {
- cairo_surface_t *surface;
- cairo_pattern_get_surface(shape_data_->mask_pattern_, &surface);
- uchar *data = cairo_image_surface_get_data(surface);
- cairo_pattern_destroy(shape_data_->mask_pattern_);
- delete[] data;
- delete shape_data_;
- }
- if (subRect_) delete subRect_;
- if (gl_start_support_) { // occurs only if gl_start/gl_finish was used
- gl_plugin()->destroy(gl_start_support_);
- }
-}
-
-
-void Fl_Wayland_Window_Driver::decorated_win_size(int &w, int &h)
-{
- Fl_Window *win = pWindow;
- w = win->w();
- h = win->h();
- if (!win->shown() || win->parent() || !win->border() || !win->visible()) return;
- int X, titlebar_height;
- libdecor_frame_translate_coordinate(fl_wl_xid(win)->frame, 0, 0, &X, &titlebar_height);
-//printf("titlebar_height=%d\n",titlebar_height);
- h = win->h() + ceil(titlebar_height / Fl::screen_scale(win->screen_num()));
-}
-
-
-int Fl_Wayland_Window_Driver::decorated_h()
-{
- int w, h;
- decorated_win_size(w, h);
- return h;
-}
-
-
-int Fl_Wayland_Window_Driver::decorated_w()
-{
- int w, h;
- decorated_win_size(w, h);
- return w;
-}
-
-
-struct xdg_toplevel *Fl_Wayland_Window_Driver::xdg_toplevel() {
- struct wld_window * w = fl_wl_xid(pWindow);
- struct xdg_toplevel *top = NULL;
- if (w->kind == DECORATED) top = libdecor_frame_get_xdg_toplevel(w->frame);
- else if (w->kind == UNFRAMED) top = w->xdg_toplevel;
- return top;
-}
-
-
-void Fl_Wayland_Window_Driver::take_focus()
-{
- struct wld_window *w = fl_wl_xid(pWindow);
- if (w) {
- Fl_Window *old_first = Fl::first_window();
- struct wld_window *first_xid = (old_first ? fl_wl_xid(old_first->top_window()) : NULL);
- if (first_xid && first_xid != w && xdg_toplevel()) {
- // this will move the target window to the front
- Fl_Wayland_Window_Driver *top_dr =
- Fl_Wayland_Window_Driver::driver(old_first->top_window());
- xdg_toplevel_set_parent(xdg_toplevel(), top_dr->xdg_toplevel());
- // this will remove the parent-child relationship
- xdg_toplevel_set_parent(xdg_toplevel(), NULL);
- wl_display_roundtrip(Fl_Wayland_Screen_Driver::wl_display);
- }
- // this sets the first window
- fl_wl_find(w);
- }
-}
-
-
-void Fl_Wayland_Window_Driver::flush_overlay()
-{
- if (!shown()) return;
- Fl_Overlay_Window *oWindow = pWindow->as_overlay_window();
- int erase_overlay = (pWindow->damage()&FL_DAMAGE_OVERLAY) | (overlay() == oWindow);
- pWindow->clear_damage((uchar)(pWindow->damage()&~FL_DAMAGE_OVERLAY));
- pWindow->make_current();
- if (!other_xid) {
- other_xid = new Fl_Image_Surface(oWindow->w(), oWindow->h(), 1);
- oWindow->clear_damage(FL_DAMAGE_ALL);
- }
- if (oWindow->damage() & ~FL_DAMAGE_EXPOSE) {
- Fl_X *myi = Fl_X::flx(pWindow);
- fl_clip_region(myi->region); myi->region = 0;
- Fl_Surface_Device::push_current(other_xid);
- draw();
- Fl_Surface_Device::pop_current();
- }
- if (erase_overlay) fl_clip_region(0);
- if (other_xid) {
- struct Fl_Wayland_Graphics_Driver::draw_buffer *buffer =
- Fl_Wayland_Graphics_Driver::offscreen_buffer(other_xid->offscreen());
- struct wld_window *xid = fl_wl_xid(pWindow);
- struct Fl_Wayland_Graphics_Driver::wld_buffer *wbuffer = xid->buffer;
- if (wbuffer->draw_buffer.data_size != buffer->data_size) {
- fl_copy_offscreen(0, 0, oWindow->w(), oWindow->h(), other_xid->offscreen(), 0, 0);
- } else {
- memcpy(wbuffer->draw_buffer.buffer, buffer->buffer, wbuffer->draw_buffer.data_size);
- }
- }
- if (overlay() == oWindow) oWindow->draw_overlay();
-}
-
-
-const Fl_Image* Fl_Wayland_Window_Driver::shape() {
- return shape_data_ ? shape_data_->shape_ : NULL;
-}
-
-
-void Fl_Wayland_Window_Driver::shape_bitmap_(Fl_Image* b) {
- shape_data_->mask_pattern_ = Fl_Cairo_Graphics_Driver::bitmap_to_pattern(
- (Fl_Bitmap*)b, true, NULL);
- shape_data_->shape_ = b;
- shape_data_->lw_ = b->data_w();
- shape_data_->lh_ = b->data_h();
-}
-
-
-void Fl_Wayland_Window_Driver::shape_alpha_(Fl_Image* img, int offset) {
- int i, j, d = img->d(), w = img->data_w(), h = img->data_h();
- int bytesperrow = cairo_format_stride_for_width(CAIRO_FORMAT_A1, w);
- unsigned u;
- uchar byte, onebit;
- // build a CAIRO_FORMAT_A1 surface covering the non-fully transparent/black part of the image
- uchar* bits = new uchar[h*bytesperrow]; // to store the surface data
- const uchar* alpha = (const uchar*)*img->data() + offset; // points to alpha value of pixels
- for (i = 0; i < h; i++) {
- uchar *p = (uchar*)bits + i * bytesperrow;
- byte = 0;
- onebit = 1;
- for (j = 0; j < w; j++) {
- if (d == 3) {
- u = *alpha;
- u += *(alpha+1);
- u += *(alpha+2);
- }
- else u = *alpha;
- if (u > 0) { // if the pixel is not fully transparent/black
- byte |= onebit; // turn on the corresponding bit of the bitmap
- }
- onebit = onebit << 1; // move the single set bit one position to the left
- if (onebit == 0 || j == w-1) {
- onebit = 1;
- *p++ = ~byte; // store in bitmap one pack of bits, complemented
- byte = 0;
- }
- alpha += d; // point to alpha value of next img pixel
- }
- }
- cairo_surface_t *mask_surf = cairo_image_surface_create_for_data(bits, CAIRO_FORMAT_A1,
- w, h, bytesperrow);
- shape_data_->mask_pattern_ = cairo_pattern_create_for_surface(mask_surf);
- cairo_surface_destroy(mask_surf);
- shape_data_->shape_ = img;
- shape_data_->lw_ = w;
- shape_data_->lh_ = h;
-}
-
-
-void Fl_Wayland_Window_Driver::shape(const Fl_Image* img) {
- if (shape_data_) {
- if (shape_data_->mask_pattern_) {
- cairo_surface_t *surface;
- cairo_pattern_get_surface(shape_data_->mask_pattern_, &surface);
- uchar *data = cairo_image_surface_get_data(surface);
- cairo_pattern_destroy(shape_data_->mask_pattern_);
- delete[] data;
- }
- }
- else {
- shape_data_ = new shape_data_type;
- }
- memset(shape_data_, 0, sizeof(shape_data_type));
- pWindow->border(false);
- int d = img->d();
- if (d && img->count() >= 2) {
- shape_pixmap_((Fl_Image*)img);
- shape_data_->shape_ = (Fl_Image*)img;
- }
- else if (d == 0) shape_bitmap_((Fl_Image*)img);
- else if (d == 2 || d == 4) shape_alpha_((Fl_Image*)img, d - 1);
- else if ((d == 1 || d == 3) && img->count() == 1) shape_alpha_((Fl_Image*)img, 0);
-}
-
-
-void Fl_Wayland_Window_Driver::draw_end()
-{
- if (shape_data_ && shape_data_->mask_pattern_) {
- Fl_Wayland_Graphics_Driver *gr_dr = (Fl_Wayland_Graphics_Driver*)fl_graphics_driver;
- cairo_t *cr = gr_dr->cr();
- cairo_matrix_t matrix;
- cairo_matrix_init_scale(&matrix, double(shape_data_->lw_) / (pWindow->w() + 1),
- double(shape_data_->lh_) / (pWindow->h() + 1) );
- cairo_matrix_translate(&matrix, 1, 1);
- cairo_pattern_set_matrix(shape_data_->mask_pattern_, &matrix);
- cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
- cairo_mask(cr, shape_data_->mask_pattern_);
- cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
- }
-}
-
-
-/* Returns images of the captures of the window title-bar, and the left, bottom and right window borders
- (or NULL if a particular border is absent).
- Returned images can be deleted after use. Their depth and size may be platform-dependent.
- The top and bottom images extend from left of the left border to right of the right border.
- */
-void Fl_Wayland_Window_Driver::capture_titlebar_and_borders(Fl_RGB_Image*& top,
- Fl_RGB_Image*& left, Fl_RGB_Image*& bottom, Fl_RGB_Image*& right)
-{
- top = left = bottom = right = NULL;
- if (pWindow->decorated_h() == h()) return;
- int htop = pWindow->decorated_h() - pWindow->h();
- struct wld_window *wwin = fl_wl_xid(pWindow);
- int width, height, stride;
- uchar *cairo_data = fl_libdecor_titlebar_buffer(wwin->frame, &width, &height, &stride);
- if (!cairo_data) return;
- uchar *data = new uchar[width * height * 4];
- uchar *p = data;
- for (int j = 0; j < height; j++) {
- uchar *q = cairo_data + j * stride;
- for (int i = 0; i < width; i++) {
- *p++ = *(q+2); // R
- *p++ = *(q+1); // G
- *p++ = *q; // B
- *p++ = *(q+3); // A
- q += 4;
- }
- }
- top = new Fl_RGB_Image(data, width, height, 4);
- top->alloc_array = 1;
- top->scale(pWindow->w(), htop);
-}
-
-
-// make drawing go into this window (called by subclass flush() impl.)
-void Fl_Wayland_Window_Driver::make_current() {
- if (!shown()) {
- static const char err_message[] = "Fl_Window::make_current(), but window is not shown().";
- fl_alert(err_message);
- Fl::fatal(err_message);
- }
-
- struct wld_window *window = fl_wl_xid(pWindow);
- if (window->buffer) {
- ((Fl_Cairo_Graphics_Driver*)fl_graphics_driver)->needs_commit_tag(
- &window->buffer->draw_buffer_needs_commit);
- }
-
- // to support progressive drawing
- if ( (!Fl_Wayland_Window_Driver::in_flush_) && window->buffer && (!window->frame_cb) &&
- (!wait_for_expose_value) ) {
- Fl_Wayland_Graphics_Driver::buffer_commit(window);
- }
-
- Fl_Wayland_Window_Driver::wld_window = window;
- fl_window = (Window)window;
- float f = Fl::screen_scale(pWindow->screen_num());
- int wld_s = wld_scale();
- if (!window->buffer) {
- window->buffer = Fl_Wayland_Graphics_Driver::create_wld_buffer(
- int(pWindow->w() * f) * wld_s, int(pWindow->h() * f) * wld_s, false);
- ((Fl_Cairo_Graphics_Driver*)fl_graphics_driver)->needs_commit_tag(
- &window->buffer->draw_buffer_needs_commit);
- }
- ((Fl_Wayland_Graphics_Driver*)fl_graphics_driver)->set_cairo(
- window->buffer->draw_buffer.cairo_, f * wld_s);
- ((Fl_Cairo_Graphics_Driver*)fl_graphics_driver)->wld_scale = wld_s;
- int *poffset = Fl_Window_Driver::menu_offset_y(pWindow);
- if (poffset) { // for tall menu windows under KWIN to offset drawing inside window
- cairo_translate(window->buffer->draw_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,
- extents->width, extents->height);
-//printf("make_current: %dx%d %dx%d\n",extents->x, extents->y, extents->width, extents->height);
- Fl_X::flx(pWindow)->region = clip_region;
- }
- else fl_graphics_driver->clip_region(0);
-
-#ifdef FLTK_HAVE_CAIROEXT
- // update the cairo_t context
- if (Fl::cairo_autolink_context()) Fl::cairo_make_current(pWindow);
-#endif
-}
-
-
-void Fl_Wayland_Window_Driver::flush() {
- if (!pWindow->damage()) return;
- if (pWindow->as_gl_window()) {
- int W = pWindow->w();
- int H = pWindow->h();
- float scale = fl_graphics_driver->scale();
- Fl_Wayland_Window_Driver::in_flush_ = true;
- Fl_Window_Driver::flush();
- Fl_Wayland_Window_Driver::in_flush_ = false;
- gl_plugin()->do_swap(pWindow); // useful only for GL win with overlay
- if (scale != fl_graphics_driver->scale() || W != pWindow->w() || H != pWindow->h()) {
- gl_plugin()->invalidate(pWindow);
- }
- return;
- }
- struct wld_window *window = fl_wl_xid(pWindow);
- if (!window || !window->configured_width) return;
-
- Fl_X *ip = Fl_X::flx(pWindow);
- cairo_region_t* r = (cairo_region_t*)ip->region;
- if (!window->buffer || pWindow->as_overlay_window()) r = NULL;
-
- Fl_Wayland_Window_Driver::in_flush_ = true;
- Fl_Window_Driver::flush();
- Fl_Wayland_Window_Driver::in_flush_ = false;
- if (!window->frame_cb) Fl_Wayland_Graphics_Driver::buffer_commit(window, r);
-}
-
-
-void Fl_Wayland_Window_Driver::show() {
- if (!shown()) {
- fl_open_display();
- makeWindow();
- } else {
- // Wayland itself gives no way to programmatically unminimize a minimized window
- Fl::handle(FL_SHOW, pWindow);
- }
-}
-
-
-static void popup_done(void *data, struct xdg_popup *xdg_popup);
-
-
-static void destroy_surface_caution_pointer_focus(struct wl_surface *surface,
- struct Fl_Wayland_Screen_Driver::seat *seat) {
- if (seat->pointer_focus == surface) seat->pointer_focus = NULL;
- if (seat->keyboard_surface == surface) seat->keyboard_surface = NULL;
- wl_surface_destroy(surface);
-}
-
-
-void Fl_Wayland_Window_Driver::hide() {
- if (pWindow == Fl_Screen_Driver::transient_scale_parent) {
- // Delete also the running transient scale window
- // because the transient is a popup and MUST be deleted
- // before its parent.
- Fl::remove_timeout(Fl_Screen_Driver::del_transient_window);
- Fl_Screen_Driver::del_transient_window(NULL);
- }
- Fl_X* ip = Fl_X::flx(pWindow);
- if (hide_common()) return;
- if (ip->region) {
- Fl_Graphics_Driver::default_driver().XDestroyRegion(ip->region);
- ip->region = 0;
- }
- screen_num_ = -1;
- struct wld_window *wld_win = (struct wld_window*)ip->xid;
- if (wld_win) { // this test makes sure ip->xid has not been destroyed already
- Fl_Wayland_Graphics_Driver::buffer_release(wld_win);
- if (wld_win->kind == SUBWINDOW && wld_win->subsurface) {
- wl_subsurface_destroy(wld_win->subsurface);
- wld_win->subsurface = NULL;
- }
-#if HAVE_XDG_DIALOG
- if (wld_win->xdg_dialog) {
- xdg_dialog_v1_destroy(wld_win->xdg_dialog);
- wld_win->xdg_dialog = NULL;
- }
-#endif
- if (wld_win->kind == DECORATED) {
- libdecor_frame_unref(wld_win->frame);
- wld_win->frame = NULL;
- wld_win->xdg_surface = NULL;
- } else {
- if (wld_win->kind == POPUP && wld_win->xdg_popup) {
- popup_done(xdg_popup_get_user_data(wld_win->xdg_popup), wld_win->xdg_popup);
- wld_win->xdg_popup = NULL;
- }
- if (wld_win->kind == UNFRAMED && wld_win->xdg_toplevel) {
- xdg_toplevel_destroy(wld_win->xdg_toplevel);
- wld_win->xdg_toplevel = NULL;
- }
- if (wld_win->xdg_surface) {
- xdg_surface_destroy(wld_win->xdg_surface);
- wld_win->xdg_surface = NULL;
- }
- }
- if (wld_win->custom_cursor) delete_cursor(wld_win->custom_cursor);
- if (wld_win->wl_surface) {
- Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver();
- destroy_surface_caution_pointer_focus(wld_win->wl_surface, scr_driver->seat);
- wld_win->wl_surface = NULL;
- }
- while (!wl_list_empty(&wld_win->outputs)) { // remove from screens where it belongs
- struct surface_output *s_output;
- s_output = wl_container_of(wld_win->outputs.next, s_output, link);
- wl_list_remove(&s_output->link);
- free(s_output);
- }
- if (Fl_Wayland_Window_Driver::wld_window == wld_win) {
- Fl_Wayland_Window_Driver::wld_window = NULL;
- }
- if (wld_win->frame_cb) wl_callback_destroy(wld_win->frame_cb); // useful for GL subwins
- free(wld_win);
- }
- delete ip;
-}
-
-
-void Fl_Wayland_Window_Driver::map() {
- Fl_X* ip = Fl_X::flx(pWindow);
- struct wld_window *wl_win = (struct wld_window*)ip->xid;
- if (wl_win->kind == SUBWINDOW && !wl_win->subsurface) {
- struct wld_window *parent = fl_wl_xid(pWindow->window());
- if (parent) {
- Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver();
- wl_win->subsurface = wl_subcompositor_get_subsurface(scr_driver->wl_subcompositor,
- wl_win->wl_surface, parent->wl_surface);
- float f = Fl::screen_scale(pWindow->top_window()->screen_num());
- wl_subsurface_set_position(wl_win->subsurface, pWindow->x() * f, pWindow->y() * f);
- wl_subsurface_set_desync(wl_win->subsurface); // important
- wl_subsurface_place_above(wl_win->subsurface, parent->wl_surface);
- wl_win->configured_width = pWindow->w();
- wl_win->configured_height = pWindow->h();
- wait_for_expose_value = 0;
- pWindow->redraw();
- }
- }
-}
-
-
-void Fl_Wayland_Window_Driver::unmap() {
- Fl_X* ip = Fl_X::flx(pWindow);
- struct wld_window *wl_win = (struct wld_window*)ip->xid;
- if (wl_win->kind == SUBWINDOW && wl_win->wl_surface) {
- wl_surface_attach(wl_win->wl_surface, NULL, 0, 0);
- Fl_Wayland_Graphics_Driver::buffer_release(wl_win);
- wl_subsurface_destroy(wl_win->subsurface);
- wl_win->subsurface = NULL;
- }
-}
-
-
-void Fl_Wayland_Window_Driver::size_range() {
- if (shown()) {
- Fl_X* ip = Fl_X::flx(pWindow);
- struct wld_window *wl_win = (struct wld_window*)ip->xid;
- float f = Fl::screen_scale(pWindow->screen_num());
- int minw, minh, maxw, maxh;
- pWindow->get_size_range(&minw, &minh, &maxw, &maxh, NULL, NULL, NULL);
- if (wl_win->kind == DECORATED && wl_win->frame) {
- int X,Y,W,H;
- Fl::screen_work_area(X,Y,W,H, Fl::screen_num(x(),y(),w(),h()));
- if (maxw && maxw < W && maxh && maxh < H) {
- libdecor_frame_unset_capabilities(wl_win->frame, LIBDECOR_ACTION_FULLSCREEN);
- } else {
- libdecor_frame_set_capabilities(wl_win->frame, LIBDECOR_ACTION_FULLSCREEN);
- }
- if (maxw && maxh && (minw >= maxw || minh >= maxh)) {
- libdecor_frame_unset_capabilities(wl_win->frame, LIBDECOR_ACTION_RESIZE);
- } else {
- libdecor_frame_set_capabilities(wl_win->frame, LIBDECOR_ACTION_RESIZE);
- }
- libdecor_frame_set_min_content_size(wl_win->frame, minw*f, minh*f);
- libdecor_frame_set_max_content_size(wl_win->frame, maxw*f, maxh*f);
- if (xdg_toplevel()) {
- struct libdecor_state *state = libdecor_state_new(int(w() * f), int(h() * f));
- libdecor_frame_commit(wl_win->frame, state, NULL);
- libdecor_state_free(state);
- }
- } else if (wl_win->kind == UNFRAMED && wl_win->xdg_toplevel) {
- xdg_toplevel_set_min_size(wl_win->xdg_toplevel, minw*f, minh*f);
- if (maxw && maxh)
- xdg_toplevel_set_max_size(wl_win->xdg_toplevel, maxw*f, maxh*f);
- }
- }
-}
-
-
-void Fl_Wayland_Window_Driver::iconize() {
- Fl_X* ip = Fl_X::flx(pWindow);
- struct wld_window *wl_win = (struct wld_window*)ip->xid;
- if (wl_win->kind == DECORATED) {
- libdecor_frame_set_minimized(wl_win->frame);
- if (xdg_toplevel_get_version(xdg_toplevel()) < 6) {
- Fl::handle(FL_HIDE, pWindow);
- }
- }
- else if (wl_win->kind == UNFRAMED && wl_win->xdg_toplevel) xdg_toplevel_set_minimized(wl_win->xdg_toplevel);
-}
-
-
-void Fl_Wayland_Window_Driver::decoration_sizes(int *top, int *left, int *right, int *bottom)
-{
- struct wld_window *xid = (struct wld_window*)fl_xid(pWindow);
- if (xid && xid->kind == DECORATED) {
- libdecor_frame_translate_coordinate(xid->frame, 0, 0, left, top);
- *right = *left;
- *bottom = 0;
- } else {
- Fl_Window_Driver::decoration_sizes(top, left, right, bottom);
- }
-}
-
-
-int Fl_Wayland_Window_Driver::scroll(int src_x, int src_y, int src_w, int src_h,
- int dest_x, int dest_y,
- void (*draw_area)(void*, int,int,int,int), void* data)
-{
- struct wld_window * xid = fl_wl_xid(pWindow);
- struct Fl_Wayland_Graphics_Driver::wld_buffer *buffer = xid->buffer;
- float s = wld_scale() * fl_graphics_driver->scale();
- if (s != 1) {
- src_x = src_x * s;
- src_y = src_y * s;
- src_w = src_w * s;
- src_h = src_h * s;
- dest_x = dest_x * s;
- dest_y = dest_y * s;
- }
- if (src_x == dest_x) { // vertical scroll
- int i, to, step;
- if (src_y > dest_y) {
- i = 0; to = src_h; step = 1;
- } else {
- i = src_h - 1; to = -1; step = -1;
- }
- while (i != to) {
- memcpy(
- buffer->draw_buffer.buffer + (dest_y + i) * buffer->draw_buffer.stride + 4 * dest_x,
- buffer->draw_buffer.buffer + (src_y + i) * buffer->draw_buffer.stride + 4 * src_x,
- 4 * src_w);
- i += step;
- }
- } else { // horizontal scroll
- int i, to, step;
- if (src_x > dest_x) {
- i = 0; to = src_h; step = 1;
- } else {
- i = src_h - 1; to = -1; step = -1;
- }
- while (i != to) {
- memmove(
- buffer->draw_buffer.buffer + (src_y + i) * buffer->draw_buffer.stride + 4 * dest_x,
- buffer->draw_buffer.buffer + (src_y + i) * buffer->draw_buffer.stride + 4 * src_x,
- 4 * src_w);
- i += step;
- }
- }
- return 0;
-}
-
-
-static void handle_error(struct libdecor *libdecor_context, enum libdecor_error error, const char *message)
-{
- Fl::fatal("Caught error (%d): %s\n", error, message);
-}
-
-
-static struct libdecor_interface libdecor_iface = {
- .error = handle_error,
-};
-
-
-
-static void delayed_rescale(Fl_Window *win) {
- Fl_Window_Driver::driver(win)->is_a_rescale(true);
- win->size(win->w(), win->h());
- Fl_Window_Driver::driver(win)->is_a_rescale(false);
-}
-
-
-void change_scale(Fl_Wayland_Screen_Driver::output *output, struct wld_window *window,
- float pre_scale) {
- Fl_Wayland_Window_Driver *win_driver = Fl_Wayland_Window_Driver::driver(window->fl_win);
- if (!window->fl_win->parent()) {
- // for top-level, set its screen number when the 1st screen for this surface changes
- Fl_Wayland_Screen_Driver::output *running_output;
- Fl_Wayland_Screen_Driver *scr_dr = (Fl_Wayland_Screen_Driver*)Fl::screen_driver();
- int i = 0;
- wl_list_for_each(running_output, &scr_dr->outputs, link) { // each screen of the system
- if (running_output == output) { // we've found our screen of the system
- win_driver->screen_num(i);
- break;
- }
- i++;
- }
- }
- float post_scale = Fl::screen_scale(win_driver->screen_num()) * output->wld_scale;
-//printf("pre_scale=%.1f post_scale=%.1f\n", pre_scale, post_scale);
- if (post_scale != pre_scale) {
- if (window->kind == Fl_Wayland_Window_Driver::POPUP) {
- Fl_Wayland_Graphics_Driver::buffer_release(window);
- window->fl_win->redraw();
- } else {
- // delaying the rescaling is necessary to set first the window's size_range according to the new screen
- Fl::add_timeout(0, (Fl_Timeout_Handler)delayed_rescale, window->fl_win);
- }
- }
-}
-
-
-static void surface_enter(void *data, struct wl_surface *wl_surface,
- struct wl_output *wl_output) {
- struct wld_window *window = (struct wld_window*)data;
-
- if (!Fl_Wayland_Screen_Driver::own_output(wl_output))
- return;
-
- Fl_Wayland_Screen_Driver::output *output =
- (Fl_Wayland_Screen_Driver::output*)wl_output_get_user_data(wl_output);
- if (output == NULL)
- return;
-
- bool list_was_empty = wl_list_empty(&window->outputs);
- struct Fl_Wayland_Window_Driver::surface_output *surface_output =
- (struct Fl_Wayland_Window_Driver::surface_output*)malloc(
- sizeof(struct Fl_Wayland_Window_Driver::surface_output));
- surface_output->output = output;
- // add to end of the linked list of displays of this surface
- struct wl_list *e = &window->outputs;
- while (e->next != &window->outputs) e = e->next; // move e to end of linked list
- wl_list_insert(e, &surface_output->link);
-//printf("window %p enters screen id=%d length=%d\n", window->fl_win, output->id, wl_list_length(&window->outputs));
- if (list_was_empty && !window->fl_win->parent()) {
- change_scale(output, window, 0);
- }
-}
-
-
-static void surface_leave(void *data, struct wl_surface *wl_surface,
- struct wl_output *wl_output) {
- if (!Fl_Wayland_Screen_Driver::own_output(wl_output))
- return;
- struct wld_window *window = (struct wld_window*)data;
- Fl_Wayland_Screen_Driver::output *output =
- (Fl_Wayland_Screen_Driver::output*)wl_output_get_user_data(wl_output);
- Fl_Wayland_Window_Driver *win_driver = Fl_Wayland_Window_Driver::driver(window->fl_win);
- float pre_scale = Fl::screen_scale(win_driver->screen_num()) * win_driver->wld_scale();
- struct Fl_Wayland_Window_Driver::surface_output *s_output;
- int count = 0;
- wl_list_for_each(s_output, &window->outputs, link) {
- count++;
- if (s_output->output == output) {
- wl_list_remove(&s_output->link);
- free(s_output);
-//printf("window %p leaves screen id=%d length=%d\n", window->fl_win, output->id, wl_list_length(&window->outputs));
- break;
- }
- }
- if (count == 1 && !wl_list_empty(&window->outputs) && !window->fl_win->parent()) {
- s_output = wl_container_of(window->outputs.next, s_output, link);
- change_scale(s_output->output, window, pre_scale);
- }
-}
-
-
-static struct wl_surface_listener surface_listener = {
- surface_enter,
- surface_leave,
-};
-
-
-Fl_Window *Fl_Wayland_Window_Driver::surface_to_window(struct wl_surface *surface) {
- if (surface) {
- if (wl_proxy_get_listener((struct wl_proxy *)surface) == &surface_listener) {
- return ((struct wld_window *)wl_surface_get_user_data(surface))->fl_win;
- }
- }
- return NULL;
-}
-
-
-static struct Fl_Wayland_Screen_Driver::output *screen_num_to_output(int num_screen) {
- Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver();
- int i = 0;
- Fl_Wayland_Screen_Driver::output *output;
- wl_list_for_each(output, &(scr_driver->outputs), link) { // all screens of the system
- if (i++ == num_screen) return output;
- }
- return NULL;
-}
-
-
-#define LIBDECOR_MR131 1 // this means libdecor does not include MR!131 yet
-
-#ifdef LIBDECOR_MR131
-/* === Beginning of hack that would become un-needed if libdecor accepted MR!131 === */
-
-// true while the GUI is interactively resizing a decorated window
-static bool in_decorated_window_resizing = false;
-
-
-// libdecor's configure cb function for xdg_toplevel objects
-static void (*decor_xdg_toplevel_configure)(void*, struct xdg_toplevel *, int32_t,
- int32_t, struct wl_array *);
-
-
-static void fltk_xdg_toplevel_configure(void *user_data, struct xdg_toplevel *xdg_toplevel,
- int32_t width, int32_t height,
- struct wl_array *states) {
- uint32_t *p;
- in_decorated_window_resizing = false;
- // Replace wl_array_for_each(p, states) rejected by C++
- for (p = (uint32_t *)(states)->data;
- (const char *) p < ((const char *) (states)->data + (states)->size);
- (p)++) {
- if (*p == XDG_TOPLEVEL_STATE_RESIZING) {
- in_decorated_window_resizing = true;
- break;
- }
- }
- decor_xdg_toplevel_configure(user_data, xdg_toplevel, width, height, states);
-}
-
-
-struct wl_object { // copied from wayland-private.h
- const struct wl_interface *interface;
- const void *implementation;
- uint32_t id;
-};
-
-
-// replace libdecor's toplevel configure cb by FLTK's
-static void use_FLTK_toplevel_configure_cb(struct libdecor_frame *frame) {
- struct wl_object *object = (struct wl_object *)libdecor_frame_get_xdg_toplevel(frame);
- static struct xdg_toplevel_listener *fltk_listener = NULL;
- if (!fltk_listener) {
- struct xdg_toplevel_listener *decor_listener = (struct xdg_toplevel_listener*)
- object->implementation;
- fltk_listener = (struct xdg_toplevel_listener*)
- malloc(sizeof(struct xdg_toplevel_listener));
- // initialize FLTK's listener with libdecor's values
- *fltk_listener = *decor_listener;
- // memorize libdecor's toplevel configure cb
- decor_xdg_toplevel_configure = decor_listener->configure;
- // replace libdecor's toplevel configure cb by FLTK's
- fltk_listener->configure = fltk_xdg_toplevel_configure;
- }
- // replace the toplevel listener by a copy whose configure member is FLTK's
- object->implementation = fltk_listener;
-}
-
-/* === End of hack that would become un-needed if libdecor accepted MR!131 === */
-#endif // LIBDECOR_MR131
-
-
-// does win entirely cover its parent ?
-static void does_window_cover_parent(Fl_Window *win) {
- Fl_Window *parent = win->window();
- fl_wl_xid(parent)->covered = (win->x() <= 0 && win->y() <= 0 &&
- win->w() >= parent->w() && win->h() >= parent->h());
-}
-
-
-// recursively explore all shown subwindows in a window and call f for each
-static void scan_subwindows(Fl_Group *g, void (*f)(Fl_Window *)) {
- for (int i = 0; i < g->children(); i++) {
- Fl_Widget *o = g->child(i);
- if (o->as_window()) {
- if (!o->as_window()->shown()) continue;
- f(o->as_window());
- }
- if (o->as_group()) scan_subwindows(o->as_group(), f);
- }
-}
-
-// Generate FL_APP_ACTIVATE and FL_APP_DEACTIVATE events
-static bool app_has_active_window = false;
-
-// If a window is deactivated, check after a short delay if any other window has
-// become active. If not, send an FL_APP_DEACTIVATE event.
-static void deferred_check_app_deactivate(void*) {
- if (!app_has_active_window) return;
- app_has_active_window = false;
- // Check all FLTK windows to see if any are still active
- for (Fl_Window *w = Fl::first_window(); w; w = Fl::next_window(w)) {
- if (w->visible_r()) {
- struct wld_window* xid = fl_wl_xid(w);
- if (xid && (xid->state & LIBDECOR_WINDOW_STATE_ACTIVE)) {
- app_has_active_window = true;
- break;
- }
- }
- }
- if (!app_has_active_window) Fl::handle(FL_APP_DEACTIVATE, nullptr);
-}
-
-static void handle_configure(struct libdecor_frame *frame,
- struct libdecor_configuration *configuration, void *user_data)
-{
- struct wld_window *window = (struct wld_window*)user_data;
- if (!window->wl_surface) return;
- int width, height;
- enum libdecor_window_state window_state;
- struct libdecor_state *state;
- Fl_Wayland_Window_Driver *driver = Fl_Wayland_Window_Driver::driver(window->fl_win);
- // true exactly for the 1st run of handle_configure() for this window
- bool is_1st_run = (window->xdg_surface == 0);
- // true exactly for the 2nd run of handle_configure() for this window
- bool is_2nd_run = (window->xdg_surface != 0 && driver->wait_for_expose_value);
- float f = Fl::screen_scale(window->fl_win->screen_num());
-
- if (!window->xdg_surface) window->xdg_surface = libdecor_frame_get_xdg_surface(frame);
-
-#ifdef LIBDECOR_MR131
- if (is_1st_run) use_FLTK_toplevel_configure_cb(frame);
-#endif
- struct wl_output *wl_output = NULL;
- if (window->fl_win->fullscreen_active()) {
- if (!(window->state & LIBDECOR_WINDOW_STATE_FULLSCREEN)) {
- if (Fl_Window_Driver::driver(window->fl_win)->force_position()) {
- struct Fl_Wayland_Screen_Driver::output *output =
- screen_num_to_output(window->fl_win->screen_num());
- if (output) wl_output = output->wl_output;
- }
- libdecor_frame_set_fullscreen(window->frame, wl_output);
- }
- } else if (driver->show_iconic()) {
- libdecor_frame_set_minimized(window->frame);
- driver->show_iconic(0);
- }
- if (!libdecor_configuration_get_window_state(configuration, &window_state))
- window_state = LIBDECOR_WINDOW_STATE_NONE;
- if ((window->state & LIBDECOR_WINDOW_STATE_FULLSCREEN) &&
- !(window_state & LIBDECOR_WINDOW_STATE_FULLSCREEN) && !window->fl_win->border()) {
- // necessary so Mutter correctly positions borderless window back from fullscreen
- window->fl_win->redraw();
- }
- window->state = window_state;
-
- // Weston, KWin, and some old versions of Mutter, on purpose, don't set the
- // window width x height when xdg_toplevel_configure runs twice
- // during resizable window creation
- // (see https://gitlab.freedesktop.org/wayland/wayland-protocols/-/issues/6).
- // Consequently, libdecor_configuration_get_content_size() may return false twice.
- // Weston and KWin, at least, don't change the window size asked by the client application
- // which is available here in floating_{width,height}.
- if (!libdecor_configuration_get_content_size(configuration, frame, &width, &height)) {
- if (is_2nd_run) {
- width = window->floating_width;
- height = window->floating_height;
- if (!driver->is_resizable()) {
- libdecor_frame_set_min_content_size(frame, width, height);
- libdecor_frame_set_max_content_size(frame, width, height);
- }
- } else { width = height = 0; }
- }
- if (is_2nd_run && Fl_Wayland_Screen_Driver::compositor == Fl_Wayland_Screen_Driver::MUTTER) {
- scan_subwindows(window->fl_win, does_window_cover_parent); // issue #878
- }
-
- if (window->fl_win->fullscreen_active() &&
- Fl_Window_Driver::driver(window->fl_win)->force_position()) {
- int X, Y, W, H;
- Fl::screen_xywh(X, Y, W, H, window->fl_win->screen_num());
- width = W * f; height = H * f;
- }
-
- if (width == 0) {
- width = window->floating_width;
- height = window->floating_height;
- //fprintf(stderr,"handle_configure: using floating %dx%d\n",width,height);
- }
-
-#ifndef LIBDECOR_MR131
- bool in_decorated_window_resizing = (window->state & LIBDECOR_WINDOW_STATE_RESIZING);
-#endif
- bool condition = in_decorated_window_resizing;
- if (condition) { // see issue #878
- condition = (window->covered ? (window->buffer && window->buffer->in_use) : (window->frame_cb != NULL));
- }
- if (condition) {
- // Skip resizing & redrawing. The last resize request won't be skipped because
- // LIBDECOR_WINDOW_STATE_RESIZING will be off or cb will be NULL then.
- return;
- }
-
- driver->in_handle_configure = true;
- window->fl_win->resize(0, 0, ceil(width / f), ceil(height / f));
- driver->in_handle_configure = false;
- if (wl_output) window->fl_win->redraw();
- window->configured_width = ceil(width / f);
- window->configured_height = ceil(height / f);
- if (is_2nd_run) driver->wait_for_expose_value = 0;
-//fprintf(stderr, "handle_configure fl_win=%p size:%dx%d state=%x wait_for_expose_value=%d is_2nd_run=%d\n", window->fl_win, width,height,window_state,driver->wait_for_expose_value, is_2nd_run);
-
- // When no window is active, and one window gets activated, generate an FL_APP_ACTIVATE event
- if (window_state & LIBDECOR_WINDOW_STATE_ACTIVE) {
- if (!app_has_active_window) {
- app_has_active_window = true;
- Fl::handle(FL_APP_ACTIVATE, nullptr);
- }
-
- if (Fl_Wayland_Screen_Driver::compositor == Fl_Wayland_Screen_Driver::WESTON) {
- // After click on titlebar, weston calls wl_keyboard_enter() for a
- // titlebar-related surface that FLTK can't identify, so we send FL_FOCUS here.
- Fl::handle(FL_FOCUS, window->fl_win);
- }
- if (!window->fl_win->border()) libdecor_frame_set_visibility(window->frame, false);
- else if (!libdecor_frame_is_visible(window->frame)) {
- libdecor_frame_set_visibility(window->frame, true);
- } else if (!window->fl_win->visible()) {
- Fl::handle(FL_SHOW, window->fl_win); // useful when un-minimizing
- }
- } else if (window_state & LIBDECOR_WINDOW_STATE_SUSPENDED) { // window is minimized
- Fl::handle(FL_HIDE, window->fl_win);
- }
-
- // When a window gets deactivated and there are no other active windows,
- // generate an FL_APP_DEACTIVATE event
- if ( ((window_state & LIBDECOR_WINDOW_STATE_ACTIVE) == 0) && app_has_active_window) {
- Fl::add_timeout(0.1, deferred_check_app_deactivate, nullptr);
- }
-
- if (window->fl_win->border())
- driver->is_maximized(window_state & LIBDECOR_WINDOW_STATE_MAXIMIZED);
- if (window_state & LIBDECOR_WINDOW_STATE_MAXIMIZED) state = libdecor_state_new(width,
- height);
- else state = libdecor_state_new(int(ceil(width/f)*f), int(ceil(height/f)*f));
- libdecor_frame_commit(frame, state, configuration);
- if (libdecor_frame_is_floating(frame)) { // store floating dimensions
- window->floating_width = int(ceil(width/f)*f);
- window->floating_height = int(ceil(height/f)*f);
- //fprintf(stderr,"set floating_width+height %dx%d\n",width,height);
- }
- libdecor_state_free(state);
-
- driver->flush();
- if (Fl_Wayland_Screen_Driver::compositor != Fl_Wayland_Screen_Driver::WESTON || !is_1st_run) {
- window->fl_win->clear_damage();
- }
-}
-
-
-void Fl_Wayland_Window_Driver::wait_for_expose()
-{
- Fl_Window_Driver::wait_for_expose();
- struct wld_window * xid = fl_wl_xid(pWindow);
- if (!xid) return;
- if (pWindow->fullscreen_active()) {
- if (xid->kind == DECORATED) {
- while (!(xid->state & LIBDECOR_WINDOW_STATE_FULLSCREEN) ||
- !(xid->state & LIBDECOR_WINDOW_STATE_ACTIVE)) {
- wl_display_dispatch(Fl_Wayland_Screen_Driver::wl_display);
- }
- } else if (xid->kind == UNFRAMED) {
- wl_display_roundtrip(Fl_Wayland_Screen_Driver::wl_display);
- }
- } else if (xid->kind == DECORATED) {
- // necessary for the windowfocus demo program with recent Wayland versions
- if (!(xid->state & LIBDECOR_WINDOW_STATE_ACTIVE)) {
- wl_display_dispatch(Fl_Wayland_Screen_Driver::wl_display);
- }
- }
-}
-
-
-static void delayed_close(Fl_Window *win) {
- Fl::remove_check((Fl_Timeout_Handler)delayed_close, win);
- Fl::handle(FL_CLOSE, win);
-}
-
-
-static void handle_close(struct libdecor_frame *frame, void *user_data)
-{ // runs when the close button of a window titlebar is pushed
- // or after "Quit" of the application menu
- // or after the Kill command of Sway
- Fl_Window* win = ((struct wld_window*)user_data)->fl_win;
- int X, Y;
- libdecor_frame_translate_coordinate(frame, 0, 0, &X, &Y);
- if (Y == 0) Fl::handle(FL_CLOSE, win);
- else {
- // the close window attempt is delayed because libdecor
- // uses the frame after return from this function
- Fl::add_check((Fl_Timeout_Handler)delayed_close, win);
- }
-}
-
-
-static void handle_commit(struct libdecor_frame *frame, void *user_data)
-{
- struct wld_window* wl_win = (struct wld_window*)user_data;
- if (wl_win->wl_surface) wl_surface_commit(wl_win->wl_surface);
-}
-
-
-static void handle_dismiss_popup(struct libdecor_frame *frame, const char *seat_name, void *user_data)
-{
-}
-
-
-static struct libdecor_frame_interface libdecor_frame_iface = {
- handle_configure,
- handle_close,
- handle_commit,
- handle_dismiss_popup,
-};
-
-
-static void xdg_surface_configure(void *data, struct xdg_surface *xdg_surface, uint32_t serial)
-{
- // runs for borderless windows and popup (menu,tooltip) windows
- struct wld_window *window = (struct wld_window*)data;
- xdg_surface_ack_configure(xdg_surface, serial);
-//fprintf(stderr, "xdg_surface_configure: surface=%p\n", window->wl_surface);
-
- if (window->fl_win->w() != window->configured_width ||
- window->fl_win->h() != window->configured_height) {
- if (window->buffer) {
- Fl_Wayland_Graphics_Driver::buffer_release(window);
- }
- }
- window->configured_width = window->fl_win->w();
- window->configured_height = window->fl_win->h();
- Fl_Window_Driver::driver(window->fl_win)->flush();
- window->fl_win->clear_damage();
-}
-
-
-static const struct xdg_surface_listener xdg_surface_listener = {
- .configure = xdg_surface_configure,
-};
-
-
-static bool parse_states_fullscreen(struct wl_array *states)
-{
- uint32_t *p;
- // Replace wl_array_for_each(p, states) rejected by C++
- for (p = (uint32_t *)(states)->data;
- (const char *) p < ((const char *) (states)->data + (states)->size);
- (p)++) {
- if (*p == XDG_TOPLEVEL_STATE_FULLSCREEN) return true;
- }
- return false;
-}
-
-
-static void xdg_toplevel_configure(void *data, struct xdg_toplevel *xdg_toplevel,
- int32_t width, int32_t height, struct wl_array *states)
-{
- // runs for borderless top-level windows
- // under Weston: width & height are 0 during both calls, except if fullscreen
- struct wld_window *window = (struct wld_window*)data;
-//fprintf(stderr, "xdg_toplevel_configure: surface=%p size: %dx%d\n", window->wl_surface, width, height);
- if (window->fl_win->fullscreen_active() && !parse_states_fullscreen(states)) {
- struct wl_output *wl_output = NULL;
- if (Fl_Window_Driver::driver(window->fl_win)->force_position()) {
- struct Fl_Wayland_Screen_Driver::output *output =
- screen_num_to_output(window->fl_win->screen_num());
- if (output) wl_output = output->wl_output;
- }
- xdg_toplevel_set_fullscreen(xdg_toplevel, wl_output);
- if (wl_output) {
- int X, Y;
- Fl::screen_xywh(X, Y, width, height, window->fl_win->screen_num());
- }
- }
- if (window->configured_width) {
- Fl_Window_Driver::driver(window->fl_win)->wait_for_expose_value = 0;
- }
- float f = Fl::screen_scale(window->fl_win->screen_num());
- if (width == 0 || height == 0) {
- width = window->fl_win->w() * f;
- height = window->fl_win->h() * f;
- }
- window->fl_win->size(ceil(width / f), ceil(height / f));
- if (window->buffer && (ceil(width / f) != window->configured_width ||
- ceil(height / f) != window->configured_height)) {
- Fl_Wayland_Graphics_Driver::buffer_release(window);
- }
- window->configured_width = ceil(width / f);
- window->configured_height = ceil(height / f);
-}
-
-
-static void xdg_toplevel_close(void *data, struct xdg_toplevel *toplevel)
-{
-}
-
-
-static const struct xdg_toplevel_listener xdg_toplevel_listener = {
- .configure = xdg_toplevel_configure,
- .close = xdg_toplevel_close,
-};
-
-
-struct win_positioner {
- struct wld_window *window;
- int x, y;
- Fl_Window *child_popup;
-};
-
-
-static void popup_configure(void *data, struct xdg_popup *xdg_popup, int32_t x, int32_t y,
- int32_t width, int32_t height) {
- struct win_positioner *win_pos = (struct win_positioner *)data;
- struct wld_window *window = win_pos->window;
-//printf("popup_configure %p asked:%dx%d got:%dx%d\n",window->fl_win, win_pos->x,win_pos->y, x,y);
- Fl_Window_Driver::driver(window->fl_win)->wait_for_expose_value = 0;
- int HH;
- Fl_Window_Driver::menu_parent(&HH);
- if (window->fl_win->h() > HH && y != win_pos->y) { // A menu taller than the display
- // Under KWin, height is set to the display height or less: we ignore that.
- window->state = (y - win_pos->y);
- // make selected item visible, if there's one
- Fl_Window_Driver::scroll_to_selected_item(window->fl_win);
- }
- if (Fl_Window_Driver::current_menu_button && !Fl_Window_Driver::menu_leftorigin(window->fl_win)) {
- int X, Y;
- Fl_Window_Driver::current_menu_button->top_window_offset(X, Y);
- if (y < Y) {
- Fl_Window *win = window->fl_win;
- win->Fl_Widget::resize(win->x(), Y - win->h(), win->w(), win->h());
- }
- }
-}
-
-
-static struct xdg_popup *mem_grabbing_popup = NULL;
-
-
-static void popup_done(void *data, struct xdg_popup *xdg_popup) {
- struct win_positioner *win_pos = (struct win_positioner *)data;
- struct wld_window *window = win_pos->window;
-//fprintf(stderr, "popup_done: popup=%p data=%p xid=%p fl_win=%p\n", xdg_popup, data, window, window->fl_win);
- if (win_pos->child_popup) win_pos->child_popup->hide();
- xdg_popup_destroy(xdg_popup);
- delete win_pos;
- // The sway compositor calls popup_done directly and hides the menu
- // when the app looses focus.
- // Thus, we hide the window so FLTK and Wayland are in matching states.
- window->xdg_popup = NULL;
- window->fl_win->hide();
- if (mem_grabbing_popup == xdg_popup) {
- mem_grabbing_popup = NULL;
- }
-}
-
-
-static const struct xdg_popup_listener popup_listener = {
- .configure = popup_configure,
- .popup_done = popup_done,
-};
-
-
-bool Fl_Wayland_Window_Driver::in_flush_ = false;
-
-
-static const char *get_prog_name() {
- pid_t pid = getpid();
- char fname[100];
- snprintf(fname, 100, "/proc/%u/cmdline", pid);
- FILE *in = fopen(fname, "r");
- if (in) {
- static char line[200];
- const char *p = fgets(line, sizeof(line), in);
- fclose(in);
- p = strrchr(line, '/'); if (!p) p = line; else p++;
- return p;
- }
- return "unknown";
-}
-
-
-/* Implementation note about menu windows under Wayland.
- Wayland offers a way to position popup windows such as menu windows using constraints.
- Each popup is located relatively to a parent window which can be a popup itself and
- MUST overlap or at least touch this parent.
- Constraints determine how a popup is positioned relatively to a defined area (called
- the anchor rectangle) of its parent popup/window and what happens when this position
- would place the popup all or partly outside the display.
- In contrast, FLTK computes the adequate positions of menu windows in the display using
- knowledge about the display size and the location of the window in the display, and then
- maps them at these positions.
- These 2 logics are quite different because Wayland hides the position of windows inside the
- display, whereas FLTK uses the location of windows inside the display to position popups.
- Let's call "source window" the non-popup window above which all popups are mapped.
- The approach implemented here is two-fold.
- 1) If a menu window is not taller than the display, use Wayland constraints to position it.
- Wayland imposes that the first constructed popup must overlap or touch the source window.
- Other popups can be placed below, above, at right, or at left of a previous popup which
- allows them to expand outside the source window, while constraints can ensure they won't
- extend outside the display.
- 2) A menu window taller than the display is initially mapped with the constraint to
- begin at the top border of the display. This allows FLTK to know the distance between
- the source window and the display top. FLTK can later reposition the same tall popup,
- without the constraint not to go beyond the display top, at the exact position so that
- the desired series of menu items appear in the visible part of the tall popup.
-
- In case 1) above, the values that represent the display bounds are given very
- large values. That's done by member function Fl_Wayland_Window_Driver::menu_window_area().
- Consequently, FLTK computes an initial layout of future popups relatively to
- the source window as if it was mapped on an infinitely large display. Then, the location
- of the first popup to be mapped is modified if necessary so it overlaps or touches the
- source window. Finally, other popups are located using Wayland logic below, above or to the
- right of previous popups. Wayland constraints mechanism also allows a popup tentatively
- placed below a previous one to be flipped above it if that prevents the popup from expanding
- beyond display limits. This is used to unfold menu bar menus below or above the menu bar.
- After each popup is created and scheduled for being mapped on display by function
- process_menu_or_tooltip(), makeWindow() calls Fl_Window::wait_for_expose() so its constrained
- position is known before computing the position of the next popup. This ensures each
- popup is correctly placed relatively to its parent.
-
- Groups of popups containing a menutitle, the associated menuwindow, and optionally
- a submenu window and that don't belong to an Fl_Menu_Bar are mapped in a different order:
- the menuwindow is mapped first, and the menutitle is mapped second above it as a child popup.
- Fl_Window_Driver::is_floating_title() detects when such a menutitle is created,
- static member variable previous_floatingtitle is assigned the value of this menutitle, and
- the menutitle is mapped only after the menuwindow has been mapped, as a child of it.
- This positions better the popup group in the display relatively to where the popup
- was created.
-
- In case 2) above, a tall popup is mapped with XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y
- which puts its top at the display top border. The Wayland system then calls the
- popup_configure() callback function with the x,y coordinates of the top left corner
- where the popup is mapped relatively to an anchor point in the source window.
- The difference between the asked window position and the effective position is stored
- in the state member variable of the tall popup's struct wld_window. This information
- allows FLTK to compute the distance between the source window top and the display top border.
- Function Fl_Wayland_Window_Driver::menu_window_area() sets the top of the display to
- a value such that function Fl_Wayland_Window_Driver::reposition_menu_window(), called by
- menuwindow::autoscroll(int n), ensures that menu item #n is visible. Static boolean member
- variable Fl_Wayland_Window_Driver::new_popup is useful to position tall menuwindows created
- by an Fl_Menu_Button or Fl_Choice. It is set to true when any menu popup is created.
- It is used each time menu_window_area() runs for a particular Fl_Menu_Button or Fl_Choice,
- and is reset to false after its first use. This allows menu_window_area() to give the top of
- the display an adequate value the first time and to keep this value next times it runs.
- Fl_Window_Driver::scroll_to_selected_item() scrolls the tall popup so its selected
- item, when there's one, is visible immediately after the tall popup is mapped on display.
- */
-
-
-bool Fl_Wayland_Window_Driver::process_menu_or_tooltip(struct wld_window *new_window) {
- // a menu window or tooltip
- new_window->kind = Fl_Wayland_Window_Driver::POPUP;
- Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver();
- if (Fl_Window_Driver::is_floating_title(pWindow)) {
- previous_floatingtitle = pWindow;
- return true;
- }
- new_window->xdg_surface = xdg_wm_base_get_xdg_surface(scr_driver->xdg_wm_base,
- new_window->wl_surface);
- xdg_surface_add_listener(new_window->xdg_surface, &xdg_surface_listener, new_window);
- Fl_Wayland_Window_Driver::new_popup = true;
- Fl_Window *menu_origin = NULL;
- if (pWindow->menu_window()) {
- menu_origin = Fl_Window_Driver::menu_leftorigin(pWindow);
- if (!menu_origin && !previous_floatingtitle) menu_origin =
- Fl_Window_Driver::menu_title(pWindow);
- }
- Fl_Widget *target = (pWindow->tooltip_window() ? Fl_Tooltip::current() : NULL);
- if (pWindow->user_data() == &Fl_Screen_Driver::transient_scale_display &&
- Fl_Screen_Driver::transient_scale_parent) {
- target = Fl_Screen_Driver::transient_scale_parent;
- }
- if (!target) target = Fl_Window_Driver::menu_parent();
- if (!target) target = Fl::belowmouse();
- if (!target) target = Fl::first_window();
- Fl_Window *parent_win = target->top_window();
- while (parent_win && parent_win->menu_window() && driver(parent_win)->popup_window()) {
- parent_win = Fl::next_window(parent_win);
- }
- Fl_Window *origin_win = (menu_origin ? menu_origin : parent_win);
- struct wld_window * parent_xid = fl_wl_xid(origin_win);
- struct xdg_surface *parent_xdg = parent_xid->xdg_surface;
- float f = Fl::screen_scale(parent_win->screen_num());
- //fprintf(stderr, "menu parent_win=%p pos:%dx%d size:%dx%d\n", parent_win, pWindow->x(), pWindow->y(), pWindow->w(), pWindow->h());
-//printf("window=%p menutitle=%p bartitle=%d leftorigin=%p y=%d\n", pWindow, Fl_Window_Driver::menu_title(pWindow), Fl_Window_Driver::menu_bartitle(pWindow), Fl_Window_Driver::menu_leftorigin(pWindow), pWindow->y());
- struct xdg_positioner *positioner = xdg_wm_base_create_positioner(scr_driver->xdg_wm_base);
- //xdg_positioner_get_version(positioner) <== gives 1 under Debian and Sway
- int popup_x, popup_y;
- if (Fl_Window_Driver::current_menu_button && !Fl_Window_Driver::menu_leftorigin(pWindow)) {
- int X, Y;
- Fl_Window_Driver::current_menu_button->top_window_offset(X, Y);
- xdg_positioner_set_anchor_rect(positioner, X * f, Y * f,
- Fl_Window_Driver::current_menu_button->w() * f,
- Fl_Window_Driver::current_menu_button->h() * f);
- popup_x = X * f;
- popup_y = 0;
- if (parent_xid->kind == Fl_Wayland_Window_Driver::DECORATED && !origin_win->fullscreen_active())
- libdecor_frame_translate_coordinate(parent_xid->frame, popup_x, popup_y,
- &popup_x, &popup_y);
- } else if (Fl_Window_Driver::menu_title(pWindow) && Fl_Window_Driver::menu_bartitle(pWindow)) {
- xdg_positioner_set_anchor_rect(positioner, 0, 0,
- Fl_Window_Driver::menu_title(pWindow)->w() * f,
- Fl_Window_Driver::menu_title(pWindow)->h() * f);
- popup_x = 0;
- popup_y = Fl_Window_Driver::menu_title(pWindow)->h() * f;
- } else {
- popup_x = pWindow->x() * f; popup_y = pWindow->y() * f;
- if (popup_x + pWindow->w() * f < 0) popup_x = - pWindow->w() * f;
- if (menu_origin) {
- popup_x -= menu_origin->x() * f;
- popup_y -= menu_origin->y() * f;
- }
- if (popup_x >= origin_win->w() * f) popup_x = origin_win->w() * f - 1;
- if (!Fl_Window_Driver::menu_title(pWindow) && !Fl_Window_Driver::menu_bartitle(pWindow) &&
- !Fl_Window_Driver::menu_leftorigin(pWindow)) {
- // prevent first popup from going above the permissible source window
- popup_y = fl_max(popup_y, - pWindow->h() * f);
- }
- if (parent_xid->kind == Fl_Wayland_Window_Driver::DECORATED && !origin_win->fullscreen_active())
- 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);
- popup_y++;
- }
- 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 - 44.
- 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 -= 44;
- 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
- int constraint = 0;
- int top_menubar = pWindow->y() -
- (Fl_Window_Driver::menu_bartitle(pWindow) && Fl_Window_Driver::menu_title(pWindow) ?
- Fl_Window_Driver::menu_title(pWindow)->h() : 0);
- if ( !(parent_win->fullscreen_active() &&
- Fl_Wayland_Screen_Driver::compositor == Fl_Wayland_Screen_Driver::MUTTER &&
- ((!Fl_Window_Driver::menu_title(pWindow) && !Fl_Window_Driver::menu_leftorigin(pWindow)) ||
- Fl_Window_Driver::menu_bartitle(pWindow)) && top_menubar < 10 &&
- !Fl_Window_Driver::current_menu_button)
- ) {
- // Condition above is only to bypass Mutter bug for fullscreen windows (see #1061)
- constraint |= (XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X | XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y);
- if ((Fl_Window_Driver::current_menu_button || Fl_Window_Driver::menu_bartitle(pWindow)) &&
- !Fl_Window_Driver::menu_leftorigin(pWindow)) {
- constraint |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y;
- }
- xdg_positioner_set_constraint_adjustment(positioner, constraint);
- }
- if (!(Fl_Window_Driver::menu_title(pWindow) && Fl_Window_Driver::menu_bartitle(pWindow))) {
- xdg_positioner_set_offset(positioner, 0, popup_y);
- }
- new_window->xdg_popup = xdg_surface_get_popup(new_window->xdg_surface,
- parent_xdg, positioner);
- struct win_positioner *win_pos = new struct win_positioner;
- win_pos->window = new_window;
- win_pos->x = popup_x;
- win_pos->y = popup_y;
- win_pos->child_popup = NULL;
-//printf("create xdg_popup=%p data=%p xid=%p fl_win=%p\n",new_window->xdg_popup,win_pos,new_window,new_window->fl_win);
- xdg_positioner_destroy(positioner);
- xdg_popup_add_listener(new_window->xdg_popup, &popup_listener, win_pos);
- if (!mem_grabbing_popup) {
- mem_grabbing_popup = new_window->xdg_popup;
- //xdg_popup_grab(new_window->xdg_popup, scr_driver->get_wl_seat(), scr_driver->get_serial());
- //libdecor_frame_popup_grab(parent_xid->frame, scr_driver->get_seat_name());
- }
- wl_surface_commit(new_window->wl_surface);
- // put it on same screen as parent_win
- this->screen_num(parent_win->screen_num());
- return false;
-}
-
-
-void Fl_Wayland_Window_Driver::makeWindow()
-{
- Fl_Group::current(0); // get rid of very common user bug: forgot end()
- struct wld_window *new_window;
- bool is_floatingtitle = false;
- wait_for_expose_value = 1;
-
- if (pWindow->parent() && !pWindow->window()) return;
- if (pWindow->parent() && !pWindow->window()->shown()) return;
-
- if (!pWindow->parent() && !popup_window()) {
- x(0); y(0); // toplevel, non-popup windows must have origin at 0,0
- }
- new_window = (struct wld_window *)calloc(1, sizeof *new_window);
- new_window->fl_win = pWindow;
- wl_list_init(&new_window->outputs);
- Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver();
-
- new_window->wl_surface = wl_compositor_create_surface(scr_driver->wl_compositor);
-//printf("makeWindow:%p %s %s\n", pWindow, pWindow->parent()?"SUB":"", pWindow->as_gl_window()?"GL":"");
- wl_surface_add_listener(new_window->wl_surface, &surface_listener, new_window);
-
- if (!shape()) { // rectangular FLTK windows are opaque
- struct wl_region *opaque = wl_compositor_create_region(scr_driver->wl_compositor);
- wl_region_add(opaque, 0, 0, 1000000, 1000000);
- wl_surface_set_opaque_region(new_window->wl_surface, opaque);
- wl_region_destroy(opaque);
- }
-
- if (pWindow->user_data() == &Fl_Screen_Driver::transient_scale_display &&
- Fl::first_window()) {
- // put transient scale win at center of top window by making it a tooltip of top
- Fl_Screen_Driver::transient_scale_parent = Fl::first_window();
- pWindow->set_tooltip_window();
- set_popup_window();
- pWindow->position(
- (Fl_Screen_Driver::transient_scale_parent->w() - pWindow->w())/2 ,
- (Fl_Screen_Driver::transient_scale_parent->h() - pWindow->h())/2);
- }
-
- if (popup_window()) { // a menu window or tooltip
- is_floatingtitle = process_menu_or_tooltip(new_window);
-
- } else if (pWindow->border() && !pWindow->parent() ) { // a decorated window
- new_window->kind = DECORATED;
- if (!scr_driver->libdecor_context)
- scr_driver->libdecor_context = libdecor_new(Fl_Wayland_Screen_Driver::wl_display,
- &libdecor_iface);
- new_window->frame = libdecor_decorate(scr_driver->libdecor_context, new_window->wl_surface,
- &libdecor_frame_iface, new_window);
- // appears in the Gnome desktop menu bar
- libdecor_frame_set_app_id(new_window->frame, get_prog_name());
- libdecor_frame_set_title(new_window->frame, pWindow->label()?pWindow->label():"");
- if (!is_resizable()) {
- libdecor_frame_unset_capabilities(new_window->frame, LIBDECOR_ACTION_RESIZE);
- libdecor_frame_unset_capabilities(new_window->frame, LIBDECOR_ACTION_FULLSCREEN);
- }
- libdecor_frame_map(new_window->frame);
- float f = Fl::screen_scale(pWindow->screen_num());
- new_window->floating_width = pWindow->w() * f;
- new_window->floating_height = pWindow->h() * f;
-
- } else if (pWindow->parent()) { // for subwindows (GL or non-GL)
- new_window->kind = SUBWINDOW;
- struct wld_window *parent = fl_wl_xid(pWindow->window());
- new_window->subsurface = wl_subcompositor_get_subsurface(scr_driver->wl_subcompositor,
- new_window->wl_surface,
- parent->wl_surface);
-//fprintf(stderr, "makeWindow: subsurface=%p\n", new_window->subsurface);
- float f = Fl::screen_scale(pWindow->top_window()->screen_num());
- wl_subsurface_set_position(new_window->subsurface, pWindow->x() * f, pWindow->y() * f);
- wl_subsurface_set_desync(new_window->subsurface); // important
- // Next 5 statements ensure the subsurface will be mapped because:
- // "The effect of adding a sub-surface becomes visible on the next time
- // the state of the parent surface is applied."
- new_window->configured_width = pWindow->w();
- new_window->configured_height = pWindow->h();
- if (!pWindow->as_gl_window()) {
- parent->fl_win->wait_for_expose();
- wl_surface_commit(parent->wl_surface);
- }
- wait_for_expose_value = 0;
- pWindow->border(0);
- checkSubwindowFrame(); // make sure subwindow doesn't leak outside parent
-
- } else { // a window without decoration
- new_window->kind = UNFRAMED;
- new_window->xdg_surface = xdg_wm_base_get_xdg_surface(scr_driver->xdg_wm_base,
- new_window->wl_surface);
-//fprintf(stderr, "makeWindow: xdg_wm_base_get_xdg_surface=%p\n", new_window->xdg_surface);
- xdg_surface_add_listener(new_window->xdg_surface, &xdg_surface_listener, new_window);
- new_window->xdg_toplevel = xdg_surface_get_toplevel(new_window->xdg_surface);
- xdg_toplevel_add_listener(new_window->xdg_toplevel, &xdg_toplevel_listener, new_window);
- if (pWindow->label()) xdg_toplevel_set_title(new_window->xdg_toplevel, pWindow->label());
- wl_surface_commit(new_window->wl_surface);
- pWindow->border(0);
- }
-
- Fl_Window *old_first = Fl::first_window();
- struct wld_window * first_xid = (old_first ? fl_wl_xid(old_first) : NULL);
- Fl_X *xp = new Fl_X;
- xp->xid = (fl_uintptr_t)new_window;
- other_xid = 0;
- xp->w = pWindow;
- flx(xp);
- xp->region = 0;
- if (!pWindow->parent()) {
- xp->next = Fl_X::first;
- Fl_X::first = xp;
- } else if (Fl_X::first) {
- xp->next = Fl_X::first->next;
- Fl_X::first->next = xp;
- } else {
- xp->next = NULL;
- Fl_X::first = xp;
- }
-
- if (pWindow->modal() || pWindow->non_modal()) {
- if (pWindow->modal()) Fl::modal_ = pWindow;
- if (new_window->kind == DECORATED && first_xid && first_xid->kind == DECORATED) {
- if (first_xid->frame) libdecor_frame_set_parent(new_window->frame, first_xid->frame);
- } else if (new_window->kind == UNFRAMED && new_window->xdg_toplevel && first_xid) {
- Fl_Wayland_Window_Driver *top_dr = Fl_Wayland_Window_Driver::driver(first_xid->fl_win);
- if (top_dr->xdg_toplevel()) xdg_toplevel_set_parent(new_window->xdg_toplevel,
- top_dr->xdg_toplevel());
- }
- if (new_window->kind == DECORATED || new_window->kind == UNFRAMED) {
-#if HAVE_XDG_DIALOG
- if (scr_driver->xdg_wm_dialog) {
- new_window->xdg_dialog = xdg_wm_dialog_v1_get_xdg_dialog(scr_driver->xdg_wm_dialog, xdg_toplevel());
- if (pWindow->modal()) xdg_dialog_v1_set_modal(new_window->xdg_dialog);
- } else
-#endif
- if (scr_driver->seat->gtk_shell && pWindow->modal()) {
- // Useful to position modal windows above their parent with "gnome-shell --version" ≤ 45.2,
- // useless but harmless with "gnome-shell --version" ≥ 46.0.
- struct gtk_surface1 *gtk_surface = gtk_shell1_get_gtk_surface(scr_driver->seat->gtk_shell,
- new_window->wl_surface);
- gtk_surface1_set_modal(gtk_surface);
- if (gtk_surface1_get_version(gtk_surface) >= GTK_SURFACE1_RELEASE_SINCE_VERSION)
- gtk_surface1_release(gtk_surface); // very necessary
- else
- gtk_surface1_destroy(gtk_surface);
- }
- }
- }
-
- size_range();
- pWindow->set_visible();
- int old_event = Fl::e_number;
- pWindow->redraw();
- pWindow->handle(Fl::e_number = FL_SHOW); // get child windows to appear
- Fl::e_number = old_event;
- if (pWindow->menu_window() && popup_window() && !is_floatingtitle) {
- // make sure each menu window is mapped with its constraints before mapping next popup
- pWindow->wait_for_expose();
- if (previous_floatingtitle) { // a menuwindow with a menutitle
- //puts("previous_floatingtitle");
- int HH;
- Fl_Window_Driver::menu_parent(&HH);
- if (pWindow->h() > HH) {
- // a tall menuwindow with a menutitle: don't create the menutitle at all
- // and undo what has been created/allocated before
- struct wld_window *xid = fl_wl_xid(previous_floatingtitle);
- destroy_surface_caution_pointer_focus(xid->wl_surface, scr_driver->seat);
- free(xid);
- Fl_Window_Driver::driver(previous_floatingtitle)->hide_common();
- previous_floatingtitle = NULL;
- return;
- }
- // map the menutitle popup now as child of pWindow
- struct wld_window *xid = fl_wl_xid(previous_floatingtitle);
- xid->xdg_surface = xdg_wm_base_get_xdg_surface(scr_driver->xdg_wm_base, xid->wl_surface);
- xdg_surface_add_listener(xid->xdg_surface, &xdg_surface_listener, xid);
- struct xdg_positioner *positioner =
- xdg_wm_base_create_positioner(scr_driver->xdg_wm_base);
- xdg_positioner_set_anchor_rect(positioner, 0, 0, 1, 1);
- int snum = Fl_Window_Driver::menu_parent()->screen_num();
- float f = Fl::screen_scale(snum);
- // put it on same screen as parent menu
- Fl_Window_Driver::driver(previous_floatingtitle)->screen_num(snum);
- xdg_positioner_set_size(positioner, previous_floatingtitle->w() * f ,
- previous_floatingtitle->h() * f );
- xdg_positioner_set_anchor(positioner, XDG_POSITIONER_ANCHOR_TOP_LEFT);
- xdg_positioner_set_gravity(positioner, XDG_POSITIONER_GRAVITY_TOP_RIGHT);
- xid->xdg_popup = xdg_surface_get_popup(xid->xdg_surface, new_window->xdg_surface,
- positioner);
- xdg_positioner_destroy(positioner);
- struct win_positioner *win_pos = new struct win_positioner;
- win_pos->window = xid;
- win_pos->x = 0;
- win_pos->y = 0;
- win_pos->child_popup = NULL;
- xdg_popup_add_listener(xid->xdg_popup, &popup_listener, win_pos);
- wl_surface_commit(xid->wl_surface);
- struct win_positioner *parent_win_pos =
- (struct win_positioner*)xdg_popup_get_user_data(new_window->xdg_popup);
- parent_win_pos->child_popup = previous_floatingtitle;
- previous_floatingtitle = NULL;
- }
- }
- if (pWindow->fullscreen_active()) Fl::handle(FL_FULLSCREEN, pWindow);
-}
-
-
-int Fl_Wayland_Window_Driver::set_cursor(Fl_Cursor c) {
- Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver();
- struct wld_window *xid = (struct wld_window *)Fl_Window_Driver::xid(pWindow);
-#if HAVE_CURSOR_SHAPE
- if (scr_driver->wp_cursor_shape_device) {
- if (xid->custom_cursor) {
- delete_cursor(xid->custom_cursor);
- xid->custom_cursor = NULL;
- }
- if (c == FL_CURSOR_NONE) return 0;
- standard_cursor_ = c;
- Fl_Wayland_Screen_Driver::do_set_cursor(scr_driver->seat, NULL, c);
- return 1;
- }
-#endif // HAVE_CURSOR_SHAPE
- if (!scr_driver->seat->cursor_theme) return 1;
- // Cursor names are the files of directory /usr/share/icons/XXXX/cursors/
- // where XXXX is the name of the current 'cursor theme'.
- static struct cursor_file_struct {
- Fl_Cursor c;
- const char *fname;
- Fl_Wayland_Screen_Driver::cursor_shapes wld_c;
- } cursor_file_array[] = {
- {FL_CURSOR_ARROW, "left_ptr", Fl_Wayland_Screen_Driver::arrow },
- {FL_CURSOR_CROSS, "cross", Fl_Wayland_Screen_Driver::cross },
- {FL_CURSOR_WAIT, "watch", Fl_Wayland_Screen_Driver::wait },
- {FL_CURSOR_INSERT, "xterm", Fl_Wayland_Screen_Driver::insert },
- {FL_CURSOR_HAND, "hand1", Fl_Wayland_Screen_Driver::hand },
- {FL_CURSOR_HELP, "help", Fl_Wayland_Screen_Driver::help },
- {FL_CURSOR_MOVE, "move", Fl_Wayland_Screen_Driver::move },
- {FL_CURSOR_N, "top_side", Fl_Wayland_Screen_Driver::north },
- {FL_CURSOR_E, "right_side", Fl_Wayland_Screen_Driver::east },
- {FL_CURSOR_W, "left_side", Fl_Wayland_Screen_Driver::west },
- {FL_CURSOR_S, "bottom_side", Fl_Wayland_Screen_Driver::south },
- {FL_CURSOR_NS, "sb_v_double_arrow", Fl_Wayland_Screen_Driver::north_south },
- {FL_CURSOR_WE, "sb_h_double_arrow", Fl_Wayland_Screen_Driver::west_east },
- {FL_CURSOR_SW, "bottom_left_corner", Fl_Wayland_Screen_Driver::south_west },
- {FL_CURSOR_SE, "bottom_right_corner", Fl_Wayland_Screen_Driver::south_east },
- {FL_CURSOR_NE, "top_right_corner", Fl_Wayland_Screen_Driver::north_east },
- {FL_CURSOR_NW, "top_left_corner", Fl_Wayland_Screen_Driver::north_west },
- {FL_CURSOR_NESW, "fd_double_arrow", Fl_Wayland_Screen_Driver::nesw },
- {FL_CURSOR_NWSE, "bd_double_arrow", Fl_Wayland_Screen_Driver::nwse }
- };
-
- int found = -1;
- for (unsigned i = 0; i < sizeof(cursor_file_array) / sizeof(struct cursor_file_struct); i++) {
- if (cursor_file_array[i].c == c) {
- found = cursor_file_array[i].wld_c;
- if (!scr_driver->xc_cursor[found]) scr_driver->xc_cursor[found] =
- scr_driver->cache_cursor(cursor_file_array[i].fname);
- if (scr_driver->xc_cursor[found]) {
- scr_driver->default_cursor(scr_driver->xc_cursor[found]);
- }
- break;
- }
- }
- if (found < 0 || !scr_driver->xc_cursor[found]) return 0;
-
- if (xid->custom_cursor) {
- delete_cursor(xid->custom_cursor);
- xid->custom_cursor = NULL;
- }
- standard_cursor_ = c;
- scr_driver->set_cursor();
- return 1;
-}
-
-
-void Fl_Wayland_Window_Driver::use_border() {
- if (!shown() || pWindow->parent()) return;
- pWindow->wait_for_expose(); // useful for border(0) just after show()
- struct libdecor_frame *frame = fl_wl_xid(pWindow)->frame;
- if (frame && Fl_Wayland_Screen_Driver::compositor != Fl_Wayland_Screen_Driver::KWIN) {
- if (fl_wl_xid(pWindow)->kind == DECORATED) {
- libdecor_frame_set_visibility(frame, pWindow->border());
- } else {
- pWindow->hide();
- pWindow->show();
- }
- pWindow->redraw();
- } else {
- Fl_Window_Driver::use_border();
- }
-}
-
-
-/* Change an existing window to fullscreen */
-void Fl_Wayland_Window_Driver::fullscreen_on() {
- int top, bottom, left, right;
-
- top = fullscreen_screen_top();
- bottom = fullscreen_screen_bottom();
- left = fullscreen_screen_left();
- right = fullscreen_screen_right();
-
- if ((top < 0) || (bottom < 0) || (left < 0) || (right < 0)) {
- top = screen_num();
- bottom = top;
- left = top;
- right = top;
- }
- pWindow->wait_for_expose(); // make sure ->xdg_toplevel is initialized
- if (xdg_toplevel()) {
- xdg_toplevel_set_fullscreen(xdg_toplevel(), NULL);
- pWindow->_set_fullscreen();
- Fl::handle(FL_FULLSCREEN, pWindow);
- }
-}
-
-
-void Fl_Wayland_Window_Driver::fullscreen_off(int X, int Y, int W, int H) {
- pWindow->hide();
- pWindow->_clear_fullscreen();
- // avoid being called with W=H=0 in suboptimal scenario of #1299
- if (!W) W = w();
- if (!H) H = h();
- pWindow->resize(X, Y, W, H);
- pWindow->show();
- Fl::handle(FL_FULLSCREEN, pWindow);
-}
-
-
-void Fl_Wayland_Window_Driver::label(const char *name, const char *iname) {
- if (shown() && !parent() && fl_wl_xid(pWindow)->kind == DECORATED) {
- if (!name) name = "";
- if (!iname) iname = fl_filename_name(name);
- libdecor_frame_set_title(fl_wl_xid(pWindow)->frame, name);
- }
-}
-
-
-int Fl_Wayland_Window_Driver::set_cursor(const Fl_RGB_Image *rgb, int hotx, int hoty) {
- int retval = set_cursor_4args(rgb, hotx, hoty, true);
- if (retval) {
- Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver();
- struct wld_window *xid = (struct wld_window *)Fl_Window_Driver::xid(pWindow);
- Fl_Wayland_Screen_Driver::do_set_cursor(scr_driver->seat, xid->custom_cursor->wl_cursor);
- }
- return retval;
-}
-
-
-int Fl_Wayland_Window_Driver::set_cursor_4args(const Fl_RGB_Image *rgb, int hotx, int hoty,
- bool keep_copy) {
- if (keep_copy) {
- if (rgb->as_svg_image()) {
- int scale = wld_scale();
- Fl_RGB_Image *svg = (Fl_RGB_Image*)rgb->copy(rgb->w() * scale, rgb->h() * scale);
- svg->normalize();
- svg->scale(rgb->w(), rgb->h(), 0, 1);
- rgb = svg;
- } else {
- int ld = rgb->ld() ? rgb->ld() : rgb->data_w() * rgb->d();
- uchar *data = new uchar[ld * rgb->data_h()];
- memcpy(data, rgb->array, ld * rgb->data_h());
- Fl_RGB_Image *rgb2 = new Fl_RGB_Image(data, rgb->data_w(), rgb->data_h(), rgb->d(), rgb->ld());
- rgb2->alloc_array = 1;
- rgb2->scale(rgb->w(), rgb->h(), 0, 1);
- rgb = rgb2;
- }
- }
-// build a new wl_cursor and its image
- struct wld_window *xid = (struct wld_window *)Fl_Window_Driver::xid(pWindow);
- struct wl_cursor *new_cursor = (struct wl_cursor*)malloc(sizeof(struct wl_cursor));
- struct cursor_image *new_image = (struct cursor_image*)calloc(1,
- sizeof(struct cursor_image));
- int scale = wld_scale();
- new_image->image.width = rgb->w() * scale;
- new_image->image.height = rgb->h() * scale;
- new_image->image.hotspot_x = hotx * scale;
- new_image->image.hotspot_y = hoty * scale;
- new_image->image.delay = 0;
- new_image->offset = 0;
- //create a Wayland buffer and have it used as an image of the new cursor
- struct Fl_Wayland_Graphics_Driver::wld_buffer *offscreen;
- Fl_Image_Surface *img_surf = Fl_Wayland_Graphics_Driver::custom_offscreen(
- new_image->image.width, new_image->image.height, &offscreen);
- new_image->buffer = offscreen->wl_buffer;
- wl_buffer_set_user_data(new_image->buffer, offscreen);
- new_cursor->image_count = 1;
- new_cursor->images = (struct wl_cursor_image**)malloc(sizeof(struct wl_cursor_image*));
- new_cursor->images[0] = (struct wl_cursor_image*)new_image;
- new_cursor->name = strdup("custom cursor");
- // draw the rgb image to the cursor's drawing buffer
- Fl_Surface_Device::push_current(img_surf);
- Fl_Wayland_Graphics_Driver *driver = (Fl_Wayland_Graphics_Driver*)img_surf->driver();
- cairo_scale(driver->cr(), scale, scale);
- ((Fl_RGB_Image*)rgb)->draw(0, 0);
- Fl_Surface_Device::pop_current();
- delete img_surf;
- memcpy(offscreen->data, offscreen->draw_buffer.buffer, offscreen->draw_buffer.data_size);
- // delete the previous custom cursor, if there was one,
- // and keep its Fl_RGB_Image if appropriate
- if (xid->custom_cursor) delete_cursor(xid->custom_cursor, keep_copy);
- //have this new cursor used
- xid->custom_cursor = new custom_cursor;
- xid->custom_cursor->wl_cursor = new_cursor;
- xid->custom_cursor->rgb = rgb;
- xid->custom_cursor->hotx = hotx;
- xid->custom_cursor->hoty = hoty;
- return 1;
-}
-
-
-void Fl_Wayland_Window_Driver::resize(int X, int Y, int W, int H) {
- static int depth = 0;
- struct wld_window *fl_win = fl_wl_xid(pWindow);
- if (fl_win && fl_win->kind == DECORATED && !xdg_toplevel()) {
- pWindow->wait_for_expose();
- }
- int is_a_move = (X != x() || Y != y());
- bool true_rescale = Fl_Window::is_a_rescale();
- float f = fl_win ? Fl::screen_scale(pWindow->screen_num()) : 1;
- if (fl_win && fl_win->buffer) {
- int scale = wld_scale();
- int stride = cairo_format_stride_for_width(
- Fl_Cairo_Graphics_Driver::cairo_format, int(W * f) * scale );
- size_t bsize = stride * int(H * f) * scale;
- true_rescale = (bsize != fl_win->buffer->draw_buffer.data_size);
- }
- int is_a_resize = (W != w() || H != h() || true_rescale);
- if (is_a_move) force_position(1);
- else if (!is_a_resize && !is_a_move) return;
- depth++;
- if (shown() && !(parent() || popup_window())) {
- X = Y = 0;
- }
- Fl_Window *parent = this->parent() ? pWindow->window() : NULL;
- struct wld_window *parent_xid = parent ? fl_wl_xid(parent) : NULL;
-//printf("resize[%p] %dx%d is_a_resize=%d is_a_move=%d depth=%d parent_xid->frame_cb=%p\n", pWindow,W,H,is_a_resize,is_a_move,depth, (parent_xid?parent_xid->frame_cb:0) );
- if (depth == 1 && fl_win && parent_xid && parent_xid->frame_cb && can_expand_outside_parent_) {
- // When moving or resizing a subwindow independently from its parent while the parent window
- // is being redrawn, the processing depends on whether the moved/resize window
- // is a draggable-subwindow. For a draggable subwindow having can_expand_outside_parent_ != 0,
- // skip the X,Y,W,H tuple to process only tuples received when parent window is ready.
- // This smoothes the movement of the draggable subwindow.
- // Process regular subwindows normally.
- depth--;
- return;
- }
- if (is_a_resize) {
- if (pWindow->parent()) {
- if (W < 1) W = 1;
- if (H < 1) H = 1;
- }
- pWindow->Fl_Group::resize(X,Y,W,H);
- //fprintf(stderr, "resize: win=%p to %dx%d\n", pWindow, W, H);
- if (shown()) {pWindow->redraw();}
- } else {
- x(X); y(Y);
- //fprintf(stderr, "move win=%p to %dx%d\n", pWindow, X, Y);
- }
- if (!fl_win) {
- depth--;
- return;
- }
-
- if (is_a_resize) {
- if (pWindow->as_overlay_window() && other_xid) {
- destroy_double_buffer();
- }
- if (fl_win->kind == DECORATED) { // a decorated window
- if (fl_win->buffer) {
- Fl_Wayland_Graphics_Driver::buffer_release(fl_win);
- }
- fl_win->configured_width = W;
- fl_win->configured_height = H;
- if (!in_handle_configure && xdg_toplevel()) {
- if (Fl_Window::is_a_rescale()) size_range();
- struct libdecor_state *state = libdecor_state_new(int(W * f), int(H * f));
- // necessary only if resize is initiated by prog
- libdecor_frame_commit(fl_win->frame, state, NULL);
- libdecor_state_free(state);
- if (libdecor_frame_is_floating(fl_win->frame)) {
- fl_win->floating_width = int(W*f);
- fl_win->floating_height = int(H*f);
- }
- }
- } else if (fl_win->kind == SUBWINDOW && fl_win->subsurface) { // a subwindow
- wl_subsurface_set_position(fl_win->subsurface, X * f, Y * f);
- if (!pWindow->as_gl_window()) Fl_Wayland_Graphics_Driver::buffer_release(fl_win);
- fl_win->configured_width = W;
- fl_win->configured_height = H;
- } else if (fl_win->xdg_surface) { // a window without border
- if (!pWindow->as_gl_window()) Fl_Wayland_Graphics_Driver::buffer_release(fl_win);
- fl_win->configured_width = W;
- fl_win->configured_height = H;
- W *= f; H *= f;
- xdg_surface_set_window_geometry(fl_win->xdg_surface, 0, 0, W, H);
- //printf("xdg_surface_set_window_geometry: %dx%d\n",W, H);
- }
- } else if (!in_handle_configure && xdg_toplevel() && Fl::e_state == FL_BUTTON1) {
- // Wayland doesn't provide a way for the app to set the window position on screen.
- // This is functional when the move is mouse-driven.
- Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver();
- xdg_toplevel_move(xdg_toplevel(), scr_driver->seat->wl_seat, scr_driver->seat->serial);
- Fl::pushed(NULL);
- Fl::e_state = 0;
- }
-
- if (parent_xid) {
- if (depth > 1) {
- if (fl_win->subsurface) {
- wl_subsurface_set_position(fl_win->subsurface, X * f, Y * f);
- wl_surface_commit(parent_xid->wl_surface);
- }
- } else if (parent_xid->buffer && is_a_move) {
- if (fl_win->subsurface) wl_subsurface_set_position(fl_win->subsurface, X * f, Y * f);
- if (!parent_xid->buffer->wl_buffer || parent_xid->buffer->draw_buffer_needs_commit) {
- if (!parent_xid->frame_cb) Fl_Wayland_Graphics_Driver::buffer_commit(parent_xid);
- else wl_surface_commit(parent_xid->wl_surface);
- } else {
- if (!parent_xid->frame_cb) {
- // Use the frame callback mechanism applied to the object's parent window
- parent_xid->frame_cb = wl_surface_frame(parent_xid->wl_surface);
- wl_callback_add_listener(parent_xid->frame_cb,
- Fl_Wayland_Graphics_Driver::p_surface_frame_listener, parent_xid);
- }
- wl_surface_commit(parent_xid->wl_surface);
- }
- }
- checkSubwindowFrame(); // make sure subwindow doesn't leak outside parent
- }
- depth--;
-}
-
-
-static void crect_intersect(cairo_rectangle_int_t *to, cairo_rectangle_int_t *with) {
- int x = fl_max(to->x, with->x);
- to->width = fl_min(to->x + to->width, with->x + with->width) - x;
- if (to->width < 0) to->width = 0;
- int y = fl_max(to->y, with->y);
- to->height = fl_min(to->y + to->height, with->y + with->height) - y;
- if (to->height < 0) to->height = 0;
- to->x = x;
- to->y = y;
-}
-
-
-static bool crect_equal(cairo_rectangle_int_t *to, cairo_rectangle_int_t *with) {
- return (to->x == with->x && to->y == with->y && to->width == with->width &&
- to->height == with->height);
-}
-
-
-void Fl_Wayland_Window_Driver::checkSubwindowFrame() {
- if (!pWindow->parent() || can_expand_outside_parent_) return;
- // make sure this subwindow doesn't leak out of its parent window
- Fl_Window *from = pWindow, *parent;
- cairo_rectangle_int_t full = {0, 0, pWindow->w(), pWindow->h()}; // full subwindow area
- cairo_rectangle_int_t srect = full; // will become new subwindow clip
- int fromx = 0, fromy = 0;
- while ((parent = from->window()) != NULL) { // loop over all parent windows
- fromx -= from->x(); // parent origin in subwindow's coordinates
- fromy -= from->y();
- cairo_rectangle_int_t prect = {fromx, fromy, parent->w(), parent->h()};
- crect_intersect(&srect, &prect); // area of subwindow inside its parent
- from = parent;
- }
- cairo_rectangle_int_t *r = subRect();
- // current subwindow clip
- cairo_rectangle_int_t current_clip = (r ? *r : full);
- if (!crect_equal(&srect, &current_clip)) { // if new clip differs from current clip
- if (crect_equal(&srect, &full)) r = NULL;
- else {
- r = &srect;
- if (r->width == 0 || r->height == 0) {
- r = NULL;
- }
- }
- subRect(r);
- }
-}
-
-
-void Fl_Wayland_Window_Driver::subRect(cairo_rectangle_int_t *r) {
- if (subRect_) delete subRect_;
- cairo_rectangle_int_t *r2 = NULL;
- if (r) {
- r2 = new cairo_rectangle_int_t;
- *r2 = *r;
- }
- subRect_ = r2;
-}
-
-
-void Fl_Wayland_Window_Driver::reposition_menu_window(int x, int y) {
- if (y == pWindow->y()) return;
- // 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();
-}
-
-
-void Fl_Wayland_Window_Driver::menu_window_area(int &X, int &Y, int &W, int &H, int nscreen) {
- int HH;
- Fl_Window *parent = Fl_Window_Driver::menu_parent(&HH);
- if (parent) {
- if (pWindow->menu_window() && popup_window() && pWindow->h() > HH) {
- // tall menu: set top (Y) and bottom (Y+H) bounds relatively to reference window
- int ih = Fl_Window_Driver::menu_itemheight(pWindow);
- X = -50000;
- W = 1000000;
- H = HH - 2 * ih;
- Fl_Window *origin = Fl_Window_Driver::menu_leftorigin(pWindow);
- if (origin) { // has left parent
- int selected = fl_max(Fl_Window_Driver::menu_selected(origin), 0);
- Y = origin->y() + (selected + 0.5) * ih;
- } else if (!Fl_Window_Driver::menu_bartitle(pWindow)) { // tall menu button
- static int y_offset = 0;
- if (new_popup) {
- y_offset = pWindow->y()- ih;
- new_popup = false;
- }
- Y = 1.5 * ih + y_offset;
- } else { // has a menutitle
- Y = 1.5 * ih;
- }
- } else { // position the menu window by wayland constraints
- X = -50000;
- Y = -50000;
- W = 1000000;
- H = 1000000;
- }
- //printf("menu_window_area: %dx%d - %dx%d\n",X,Y,W,H);
- } else Fl_Window_Driver::menu_window_area(X, Y, W, H, nscreen);
-}
-
-
-int Fl_Wayland_Window_Driver::wld_scale() {
- Fl_X *flx = Fl_X::flx(pWindow);
- struct wld_window *xid = (flx ? (struct wld_window *)flx->xid : NULL);
- if (!xid || wl_list_empty(&xid->outputs)) {
- int scale = 1;
- Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver();
- Fl_Wayland_Screen_Driver::output *output;
- wl_list_for_each(output, &(scr_driver->outputs), link) {
- scale = fl_max(scale, output->wld_scale);
- }
- return scale;
- }
- struct surface_output *s_output;
- s_output = wl_container_of(xid->outputs.next, s_output, link);
- return s_output->output->wld_scale;
-}
-
-
-FL_EXPORT struct wl_surface *fl_wl_surface(struct wld_window *xid) {
- return xid->wl_surface;
-}
-
-
-cairo_t *fl_wl_gc() {
- return ((Fl_Cairo_Graphics_Driver*)fl_graphics_driver)->cr();
-}
-
-
-Fl_Window *fl_wl_find(struct wld_window *xid) {
- return Fl_Window_Driver::find((fl_uintptr_t)xid);
-}
-
-
-struct wld_window *fl_wl_xid(const Fl_Window *win) {
- return (struct wld_window *)Fl_Window_Driver::xid(win);
-}
-
-
-struct wl_compositor *fl_wl_compositor() {
- Fl_Wayland_Screen_Driver *screen_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver();
- return screen_driver->wl_compositor;
-}
-
-
-int fl_wl_buffer_scale(Fl_Window *window) {
- return Fl_Wayland_Window_Driver::driver(window)->wld_scale();
-}
-
-
-Fl_Wayland_Plugin *Fl_Wayland_Window_Driver::gl_plugin() {
- static Fl_Wayland_Plugin *plugin = NULL;
- if (!plugin) {
- Fl_Plugin_Manager pm("wayland.fltk.org");
- plugin = (Fl_Wayland_Plugin*)pm.plugin("gl.wayland.fltk.org");
- }
- return plugin;
-}
-
-
-void Fl_Wayland_Window_Driver::maximize() {
- struct wld_window *xid = (struct wld_window *)Fl_X::flx(pWindow)->xid;
- if (xid->kind == DECORATED) libdecor_frame_set_maximized(xid->frame);
- else Fl_Window_Driver::maximize();
-}
-
-
-void Fl_Wayland_Window_Driver::un_maximize() {
- struct wld_window *xid = (struct wld_window *)Fl_X::flx(pWindow)->xid;
- if (xid->kind == DECORATED) libdecor_frame_unset_maximized(xid->frame);
- else Fl_Window_Driver::un_maximize();
-}